Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@
import dev.cel.expr.conformance.test.SimpleTest;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.testing.CelRuntimeFlavor;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand DownExpand Up@@ -143,7 +144,7 @@ public void flatten_negativeDepth_throws() {
CelEvaluationException e =
assertThrows(CelEvaluationException.class, () -> eval(cel, "[1,2,3,4].flatten(-1)"));

if (isParseOnly) {
if (runtimeFlavor.equals(CelRuntimeFlavor.PLANNER)) {
assertThat(e)
.hasMessageThat()
.contains("evaluation error at <input>:17: Function 'flatten' failed");
Expand Down
4 changes: 3 additions & 1 deletion runtime/src/main/java/dev/cel/runtime/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,7 @@ LITE_PROGRAM_IMPL_SOURCES = [
FUNCTION_BINDING_SOURCES = [
"CelFunctionBinding.java",
"FunctionBindingImpl.java",
"InternalCelFunctionBinding.java",
]

# keep sorted
Expand DownExpand Up@@ -740,6 +741,7 @@ java_library(
deps = [
":evaluation_exception",
":function_overload",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
Expand All@@ -754,6 +756,7 @@ cel_android_library(
deps = [
":evaluation_exception",
":function_overload_android",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
Expand DownExpand Up@@ -890,7 +893,6 @@ java_library(
"//common/types:type_providers",
"//common/values:cel_value_provider",
"//common/values:proto_message_value_provider",
"//runtime/standard:add",
"//runtime/standard:int",
"//runtime/standard:timestamp",
"@maven//:com_google_code_findbugs_annotations",
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,7 @@ static CelFunctionBinding from(
overloadId, ImmutableList.copyOf(argTypes), impl, /* isStrict= */ true);
}


/** See {@link #fromOverloads(String, Collection)}. */
static ImmutableSet<CelFunctionBinding> fromOverloads(
String functionName, CelFunctionBinding... overloadBindings) {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,7 +63,12 @@ public static CelLateFunctionBindings from(Collection<CelFunctionBinding> functi
}

private static CelResolvedOverload createResolvedOverload(CelFunctionBinding binding) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
return CelResolvedOverload.of(
functionName,
binding.getOverloadId(),
binding.getDefinition(),
binding.isStrict(),
Expand Down
26 changes: 19 additions & 7 deletions runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,6 +30,9 @@
@Internal
public abstract class CelResolvedOverload {

/** The base function name. */
public abstract String getFunctionName();

/** The overload id of the function. */
public abstract String getOverloadId();

Expand DownExpand Up@@ -61,40 +64,44 @@ public Object invoke(Object[] args) throws CelEvaluationException {
|| CelFunctionOverload.canHandle(args, getParameterTypes(), isStrict())) {
return getDefinition().apply(args);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg1, Object arg2) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg1, arg2, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg1, arg2);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Class<?>... parameterTypes) {
return of(overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
return of(functionName, overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Expand All@@ -104,7 +111,12 @@ public static CelResolvedOverload of(
? (OptimizedFunctionOverload) definition
: definition::apply;
return new AutoValue_CelResolvedOverload(
overloadId, ImmutableList.copyOf(parameterTypes), isStrict, definition, optimizedDef);
functionName,
overloadId,
ImmutableList.copyOf(parameterTypes),
isStrict,
definition,
optimizedDef);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -381,15 +381,25 @@ private static DefaultDispatcher newDispatcher(
DefaultDispatcher.Builder builder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding binding :
standardFunctions.newFunctionBindings(runtimeEquality, options)) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
binding.getDefinition());
}

for (CelFunctionBinding binding : customFunctionBindings) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -305,15 +305,25 @@ public CelRuntimeLegacyImpl build() {
DefaultDispatcher.Builder dispatcherBuilder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding standardFunctionBinding :
newStandardFunctionBindings(runtimeEquality)) {
String functionName = standardFunctionBinding.getOverloadId();
if (standardFunctionBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) standardFunctionBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
standardFunctionBinding.getOverloadId(),
standardFunctionBinding.getArgTypes(),
standardFunctionBinding.isStrict(),
standardFunctionBinding.getDefinition());
}

for (CelFunctionBinding customBinding : customFunctionBindings.values()) {
String functionName = customBinding.getOverloadId();
if (customBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) customBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
customBinding.getOverloadId(),
customBinding.getArgTypes(),
customBinding.isStrict(),
Expand Down
23 changes: 18 additions & 5 deletions runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,32 +134,41 @@ public static class Builder {
@AutoValue
@Immutable
abstract static class OverloadEntry {
abstract String functionName();

abstract ImmutableList<Class<?>> argTypes();

abstract boolean isStrict();

abstract CelFunctionOverload overload();

private static OverloadEntry of(
ImmutableList<Class<?>> argTypes, boolean isStrict, CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(argTypes, isStrict, overload);
String functionName,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(
functionName, argTypes, isStrict, overload);
}
}

private final Map<String, OverloadEntry> overloads;

@CanIgnoreReturnValue
public Builder addOverload(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
checkNotNull(functionName);
checkArgument(!functionName.isEmpty(), "Function name cannot be empty.");
checkNotNull(overloadId);
checkArgument(!overloadId.isEmpty(), "Overload ID cannot be empty.");
checkNotNull(argTypes);
checkNotNull(overload);

OverloadEntry newEntry = OverloadEntry.of(argTypes, isStrict, overload);
OverloadEntry newEntry = OverloadEntry.of(functionName, argTypes, isStrict, overload);

overloads.merge(
overloadId,
Expand DownExpand Up@@ -188,7 +197,7 @@ private OverloadEntry mergeDynamicDispatchesOrThrow(
boolean isStrict =
mergedOverload.getOverloadBindings().stream().allMatch(CelFunctionBinding::isStrict);

return OverloadEntry.of(incoming.argTypes(), isStrict, mergedOverload);
return OverloadEntry.of(overloadId, incoming.argTypes(), isStrict, mergedOverload);
}

throw new IllegalArgumentException("Duplicate overload ID binding: " + overloadId);
Expand All@@ -204,7 +213,11 @@ public DefaultDispatcher build() {
resolvedOverloads.put(
overloadId,
CelResolvedOverload.of(
overloadId, overloadImpl, overloadEntry.isStrict(), overloadEntry.argTypes()));
overloadEntry.functionName(),
overloadId,
overloadImpl,
overloadEntry.isStrict(),
overloadEntry.argTypes()));
}

return new DefaultDispatcher(resolvedOverloads.buildOrThrow());
Expand Down
35 changes: 31 additions & 4 deletions runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,9 @@
import dev.cel.common.exceptions.CelOverloadNotFoundException;

@Immutable
final class FunctionBindingImpl implements CelFunctionBinding {
final class FunctionBindingImpl implements InternalCelFunctionBinding {

private final String functionName;

private final String overloadId;

Expand All@@ -33,6 +35,11 @@ final class FunctionBindingImpl implements CelFunctionBinding {

private final boolean isStrict;

@Override
public String getFunctionName() {
return functionName;
}

@Override
public String getOverloadId() {
return overloadId;
Expand All@@ -54,20 +61,34 @@ public boolean isStrict() {
}

FunctionBindingImpl(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this.functionName = functionName;
this.overloadId = overloadId;
this.argTypes = argTypes;
this.definition = definition;
this.isStrict = isStrict;
}

FunctionBindingImpl(
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this(overloadId, overloadId, argTypes, definition, isStrict);
}

static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
String functionName, ImmutableSet<CelFunctionBinding> overloadBindings) {
ImmutableSet.Builder<CelFunctionBinding> builder = ImmutableSet.builder();
builder.addAll(overloadBindings);
for (CelFunctionBinding b : overloadBindings) {
builder.add(
new FunctionBindingImpl(
functionName, b.getOverloadId(), b.getArgTypes(), b.getDefinition(), b.isStrict()));
}

// If there is already a binding with the same name as the function, we treat it as a
// "Singleton" binding and do not create a dynamic dispatch wrapper for it.
Expand All@@ -80,11 +101,12 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
CelFunctionBinding singleBinding = Iterables.getOnlyElement(overloadBindings);
builder.add(
new FunctionBindingImpl(
functionName,
functionName,
singleBinding.getArgTypes(),
singleBinding.getDefinition(),
singleBinding.isStrict()));
} else {
} else if (overloadBindings.size() > 1) {
builder.add(new DynamicDispatchBinding(functionName, overloadBindings));
}
}
Expand All@@ -93,7 +115,7 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
}

@Immutable
static final class DynamicDispatchBinding implements CelFunctionBinding {
static final class DynamicDispatchBinding implements InternalCelFunctionBinding {

private final boolean isStrict;
private final DynamicDispatchOverload dynamicDispatchOverload;
Expand All@@ -103,6 +125,11 @@ public String getOverloadId() {
return dynamicDispatchOverload.functionName;
}

@Override
public String getFunctionName() {
return dynamicDispatchOverload.functionName;
}

@Override
public ImmutableList<Class<?>> getArgTypes() {
return ImmutableList.of();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
// Copyright 2026 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.runtime;

import com.google.errorprone.annotations.Immutable;
import dev.cel.common.annotations.Internal;

/**
* Internal interface to expose the function name associated with a binding.
*
* <p>CEL Library Internals. Do Not Use.
*/
@Internal
@Immutable
public interface InternalCelFunctionBinding extends CelFunctionBinding {
String getFunctionName();
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@
import dev.cel.expr.conformance.test.SimpleTest;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.testing.CelRuntimeFlavor;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand DownExpand Up@@ -143,7 +144,7 @@ public void flatten_negativeDepth_throws() {
CelEvaluationException e =
assertThrows(CelEvaluationException.class, () -> eval(cel, "[1,2,3,4].flatten(-1)"));

if (isParseOnly) {
if (runtimeFlavor.equals(CelRuntimeFlavor.PLANNER)) {
assertThat(e)
.hasMessageThat()
.contains("evaluation error at <input>:17: Function 'flatten' failed");
Expand Down
4 changes: 3 additions & 1 deletion runtime/src/main/java/dev/cel/runtime/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,7 @@ LITE_PROGRAM_IMPL_SOURCES = [
FUNCTION_BINDING_SOURCES = [
"CelFunctionBinding.java",
"FunctionBindingImpl.java",
"InternalCelFunctionBinding.java",
]

# keep sorted
Expand DownExpand Up@@ -740,6 +741,7 @@ java_library(
deps = [
":evaluation_exception",
":function_overload",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
Expand All@@ -754,6 +756,7 @@ cel_android_library(
deps = [
":evaluation_exception",
":function_overload_android",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
Expand DownExpand Up@@ -890,7 +893,6 @@ java_library(
"//common/types:type_providers",
"//common/values:cel_value_provider",
"//common/values:proto_message_value_provider",
"//runtime/standard:add",
"//runtime/standard:int",
"//runtime/standard:timestamp",
"@maven//:com_google_code_findbugs_annotations",
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,7 @@ static CelFunctionBinding from(
overloadId, ImmutableList.copyOf(argTypes), impl, /* isStrict= */ true);
}


/** See {@link #fromOverloads(String, Collection)}. */
static ImmutableSet<CelFunctionBinding> fromOverloads(
String functionName, CelFunctionBinding... overloadBindings) {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,7 +63,12 @@ public static CelLateFunctionBindings from(Collection<CelFunctionBinding> functi
}

private static CelResolvedOverload createResolvedOverload(CelFunctionBinding binding) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
return CelResolvedOverload.of(
functionName,
binding.getOverloadId(),
binding.getDefinition(),
binding.isStrict(),
Expand Down
26 changes: 19 additions & 7 deletions runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,6 +30,9 @@
@Internal
public abstract class CelResolvedOverload {

/** The base function name. */
public abstract String getFunctionName();

/** The overload id of the function. */
public abstract String getOverloadId();

Expand DownExpand Up@@ -61,40 +64,44 @@ public Object invoke(Object[] args) throws CelEvaluationException {
|| CelFunctionOverload.canHandle(args, getParameterTypes(), isStrict())) {
return getDefinition().apply(args);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg1, Object arg2) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg1, arg2, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg1, arg2);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Class<?>... parameterTypes) {
return of(overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
return of(functionName, overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Expand All@@ -104,7 +111,12 @@ public static CelResolvedOverload of(
? (OptimizedFunctionOverload) definition
: definition::apply;
return new AutoValue_CelResolvedOverload(
overloadId, ImmutableList.copyOf(parameterTypes), isStrict, definition, optimizedDef);
functionName,
overloadId,
ImmutableList.copyOf(parameterTypes),
isStrict,
definition,
optimizedDef);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -381,15 +381,25 @@ private static DefaultDispatcher newDispatcher(
DefaultDispatcher.Builder builder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding binding :
standardFunctions.newFunctionBindings(runtimeEquality, options)) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
binding.getDefinition());
}

for (CelFunctionBinding binding : customFunctionBindings) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -305,15 +305,25 @@ public CelRuntimeLegacyImpl build() {
DefaultDispatcher.Builder dispatcherBuilder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding standardFunctionBinding :
newStandardFunctionBindings(runtimeEquality)) {
String functionName = standardFunctionBinding.getOverloadId();
if (standardFunctionBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) standardFunctionBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
standardFunctionBinding.getOverloadId(),
standardFunctionBinding.getArgTypes(),
standardFunctionBinding.isStrict(),
standardFunctionBinding.getDefinition());
}

for (CelFunctionBinding customBinding : customFunctionBindings.values()) {
String functionName = customBinding.getOverloadId();
if (customBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) customBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
customBinding.getOverloadId(),
customBinding.getArgTypes(),
customBinding.isStrict(),
Expand Down
23 changes: 18 additions & 5 deletions runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,32 +134,41 @@ public static class Builder {
@AutoValue
@Immutable
abstract static class OverloadEntry {
abstract String functionName();

abstract ImmutableList<Class<?>> argTypes();

abstract boolean isStrict();

abstract CelFunctionOverload overload();

private static OverloadEntry of(
ImmutableList<Class<?>> argTypes, boolean isStrict, CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(argTypes, isStrict, overload);
String functionName,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(
functionName, argTypes, isStrict, overload);
}
}

private final Map<String, OverloadEntry> overloads;

@CanIgnoreReturnValue
public Builder addOverload(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
checkNotNull(functionName);
checkArgument(!functionName.isEmpty(), "Function name cannot be empty.");
checkNotNull(overloadId);
checkArgument(!overloadId.isEmpty(), "Overload ID cannot be empty.");
checkNotNull(argTypes);
checkNotNull(overload);

OverloadEntry newEntry = OverloadEntry.of(argTypes, isStrict, overload);
OverloadEntry newEntry = OverloadEntry.of(functionName, argTypes, isStrict, overload);

overloads.merge(
overloadId,
Expand DownExpand Up@@ -188,7 +197,7 @@ private OverloadEntry mergeDynamicDispatchesOrThrow(
boolean isStrict =
mergedOverload.getOverloadBindings().stream().allMatch(CelFunctionBinding::isStrict);

return OverloadEntry.of(incoming.argTypes(), isStrict, mergedOverload);
return OverloadEntry.of(overloadId, incoming.argTypes(), isStrict, mergedOverload);
}

throw new IllegalArgumentException("Duplicate overload ID binding: " + overloadId);
Expand All@@ -204,7 +213,11 @@ public DefaultDispatcher build() {
resolvedOverloads.put(
overloadId,
CelResolvedOverload.of(
overloadId, overloadImpl, overloadEntry.isStrict(), overloadEntry.argTypes()));
overloadEntry.functionName(),
overloadId,
overloadImpl,
overloadEntry.isStrict(),
overloadEntry.argTypes()));
}

return new DefaultDispatcher(resolvedOverloads.buildOrThrow());
Expand Down
35 changes: 31 additions & 4 deletions runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,9 @@
import dev.cel.common.exceptions.CelOverloadNotFoundException;

@Immutable
final class FunctionBindingImpl implements CelFunctionBinding {
final class FunctionBindingImpl implements InternalCelFunctionBinding {

private final String functionName;

private final String overloadId;

Expand All@@ -33,6 +35,11 @@ final class FunctionBindingImpl implements CelFunctionBinding {

private final boolean isStrict;

@Override
public String getFunctionName() {
return functionName;
}

@Override
public String getOverloadId() {
return overloadId;
Expand All@@ -54,20 +61,34 @@ public boolean isStrict() {
}

FunctionBindingImpl(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this.functionName = functionName;
this.overloadId = overloadId;
this.argTypes = argTypes;
this.definition = definition;
this.isStrict = isStrict;
}

FunctionBindingImpl(
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this(overloadId, overloadId, argTypes, definition, isStrict);
}

static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
String functionName, ImmutableSet<CelFunctionBinding> overloadBindings) {
ImmutableSet.Builder<CelFunctionBinding> builder = ImmutableSet.builder();
builder.addAll(overloadBindings);
for (CelFunctionBinding b : overloadBindings) {
builder.add(
new FunctionBindingImpl(
functionName, b.getOverloadId(), b.getArgTypes(), b.getDefinition(), b.isStrict()));
}

// If there is already a binding with the same name as the function, we treat it as a
// "Singleton" binding and do not create a dynamic dispatch wrapper for it.
Expand All@@ -80,11 +101,12 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
CelFunctionBinding singleBinding = Iterables.getOnlyElement(overloadBindings);
builder.add(
new FunctionBindingImpl(
functionName,
functionName,
singleBinding.getArgTypes(),
singleBinding.getDefinition(),
singleBinding.isStrict()));
} else {
} else if (overloadBindings.size() > 1) {
builder.add(new DynamicDispatchBinding(functionName, overloadBindings));
}
}
Expand All@@ -93,7 +115,7 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
}

@Immutable
static final class DynamicDispatchBinding implements CelFunctionBinding {
static final class DynamicDispatchBinding implements InternalCelFunctionBinding {

private final boolean isStrict;
private final DynamicDispatchOverload dynamicDispatchOverload;
Expand All@@ -103,6 +125,11 @@ public String getOverloadId() {
return dynamicDispatchOverload.functionName;
}

@Override
public String getFunctionName() {
return dynamicDispatchOverload.functionName;
}

@Override
public ImmutableList<Class<?>> getArgTypes() {
return ImmutableList.of();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
// Copyright 2026 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.runtime;

import com.google.errorprone.annotations.Immutable;
import dev.cel.common.annotations.Internal;

/**
* Internal interface to expose the function name associated with a binding.
*
* <p>CEL Library Internals. Do Not Use.
*/
@Internal
@Immutable
public interface InternalCelFunctionBinding extends CelFunctionBinding {
String getFunctionName();
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@
import dev.cel.expr.conformance.test.SimpleTest;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.testing.CelRuntimeFlavor;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand DownExpand Up@@ -143,7 +144,7 @@ public void flatten_negativeDepth_throws() {
CelEvaluationException e =
assertThrows(CelEvaluationException.class, () -> eval(cel, "[1,2,3,4].flatten(-1)"));

if (isParseOnly) {
if (runtimeFlavor.equals(CelRuntimeFlavor.PLANNER)) {
assertThat(e)
.hasMessageThat()
.contains("evaluation error at <input>:17: Function 'flatten' failed");
Expand Down
4 changes: 3 additions & 1 deletion runtime/src/main/java/dev/cel/runtime/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,7 @@ LITE_PROGRAM_IMPL_SOURCES = [
FUNCTION_BINDING_SOURCES = [
"CelFunctionBinding.java",
"FunctionBindingImpl.java",
"InternalCelFunctionBinding.java",
]

# keep sorted
Expand DownExpand Up@@ -740,6 +741,7 @@ java_library(
deps = [
":evaluation_exception",
":function_overload",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
Expand All@@ -754,6 +756,7 @@ cel_android_library(
deps = [
":evaluation_exception",
":function_overload_android",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
Expand DownExpand Up@@ -890,7 +893,6 @@ java_library(
"//common/types:type_providers",
"//common/values:cel_value_provider",
"//common/values:proto_message_value_provider",
"//runtime/standard:add",
"//runtime/standard:int",
"//runtime/standard:timestamp",
"@maven//:com_google_code_findbugs_annotations",
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,7 @@ static CelFunctionBinding from(
overloadId, ImmutableList.copyOf(argTypes), impl, /* isStrict= */ true);
}


/** See {@link #fromOverloads(String, Collection)}. */
static ImmutableSet<CelFunctionBinding> fromOverloads(
String functionName, CelFunctionBinding... overloadBindings) {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,7 +63,12 @@ public static CelLateFunctionBindings from(Collection<CelFunctionBinding> functi
}

private static CelResolvedOverload createResolvedOverload(CelFunctionBinding binding) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
return CelResolvedOverload.of(
functionName,
binding.getOverloadId(),
binding.getDefinition(),
binding.isStrict(),
Expand Down
26 changes: 19 additions & 7 deletions runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,6 +30,9 @@
@Internal
public abstract class CelResolvedOverload {

/** The base function name. */
public abstract String getFunctionName();

/** The overload id of the function. */
public abstract String getOverloadId();

Expand DownExpand Up@@ -61,40 +64,44 @@ public Object invoke(Object[] args) throws CelEvaluationException {
|| CelFunctionOverload.canHandle(args, getParameterTypes(), isStrict())) {
return getDefinition().apply(args);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg1, Object arg2) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg1, arg2, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg1, arg2);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Class<?>... parameterTypes) {
return of(overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
return of(functionName, overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Expand All@@ -104,7 +111,12 @@ public static CelResolvedOverload of(
? (OptimizedFunctionOverload) definition
: definition::apply;
return new AutoValue_CelResolvedOverload(
overloadId, ImmutableList.copyOf(parameterTypes), isStrict, definition, optimizedDef);
functionName,
overloadId,
ImmutableList.copyOf(parameterTypes),
isStrict,
definition,
optimizedDef);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -381,15 +381,25 @@ private static DefaultDispatcher newDispatcher(
DefaultDispatcher.Builder builder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding binding :
standardFunctions.newFunctionBindings(runtimeEquality, options)) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
binding.getDefinition());
}

for (CelFunctionBinding binding : customFunctionBindings) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -305,15 +305,25 @@ public CelRuntimeLegacyImpl build() {
DefaultDispatcher.Builder dispatcherBuilder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding standardFunctionBinding :
newStandardFunctionBindings(runtimeEquality)) {
String functionName = standardFunctionBinding.getOverloadId();
if (standardFunctionBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) standardFunctionBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
standardFunctionBinding.getOverloadId(),
standardFunctionBinding.getArgTypes(),
standardFunctionBinding.isStrict(),
standardFunctionBinding.getDefinition());
}

for (CelFunctionBinding customBinding : customFunctionBindings.values()) {
String functionName = customBinding.getOverloadId();
if (customBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) customBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
customBinding.getOverloadId(),
customBinding.getArgTypes(),
customBinding.isStrict(),
Expand Down
23 changes: 18 additions & 5 deletions runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,32 +134,41 @@ public static class Builder {
@AutoValue
@Immutable
abstract static class OverloadEntry {
abstract String functionName();

abstract ImmutableList<Class<?>> argTypes();

abstract boolean isStrict();

abstract CelFunctionOverload overload();

private static OverloadEntry of(
ImmutableList<Class<?>> argTypes, boolean isStrict, CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(argTypes, isStrict, overload);
String functionName,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(
functionName, argTypes, isStrict, overload);
}
}

private final Map<String, OverloadEntry> overloads;

@CanIgnoreReturnValue
public Builder addOverload(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
checkNotNull(functionName);
checkArgument(!functionName.isEmpty(), "Function name cannot be empty.");
checkNotNull(overloadId);
checkArgument(!overloadId.isEmpty(), "Overload ID cannot be empty.");
checkNotNull(argTypes);
checkNotNull(overload);

OverloadEntry newEntry = OverloadEntry.of(argTypes, isStrict, overload);
OverloadEntry newEntry = OverloadEntry.of(functionName, argTypes, isStrict, overload);

overloads.merge(
overloadId,
Expand DownExpand Up@@ -188,7 +197,7 @@ private OverloadEntry mergeDynamicDispatchesOrThrow(
boolean isStrict =
mergedOverload.getOverloadBindings().stream().allMatch(CelFunctionBinding::isStrict);

return OverloadEntry.of(incoming.argTypes(), isStrict, mergedOverload);
return OverloadEntry.of(overloadId, incoming.argTypes(), isStrict, mergedOverload);
}

throw new IllegalArgumentException("Duplicate overload ID binding: " + overloadId);
Expand All@@ -204,7 +213,11 @@ public DefaultDispatcher build() {
resolvedOverloads.put(
overloadId,
CelResolvedOverload.of(
overloadId, overloadImpl, overloadEntry.isStrict(), overloadEntry.argTypes()));
overloadEntry.functionName(),
overloadId,
overloadImpl,
overloadEntry.isStrict(),
overloadEntry.argTypes()));
}

return new DefaultDispatcher(resolvedOverloads.buildOrThrow());
Expand Down
35 changes: 31 additions & 4 deletions runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,9 @@
import dev.cel.common.exceptions.CelOverloadNotFoundException;

@Immutable
final class FunctionBindingImpl implements CelFunctionBinding {
final class FunctionBindingImpl implements InternalCelFunctionBinding {

private final String functionName;

private final String overloadId;

Expand All@@ -33,6 +35,11 @@ final class FunctionBindingImpl implements CelFunctionBinding {

private final boolean isStrict;

@Override
public String getFunctionName() {
return functionName;
}

@Override
public String getOverloadId() {
return overloadId;
Expand All@@ -54,20 +61,34 @@ public boolean isStrict() {
}

FunctionBindingImpl(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this.functionName = functionName;
this.overloadId = overloadId;
this.argTypes = argTypes;
this.definition = definition;
this.isStrict = isStrict;
}

FunctionBindingImpl(
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this(overloadId, overloadId, argTypes, definition, isStrict);
}

static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
String functionName, ImmutableSet<CelFunctionBinding> overloadBindings) {
ImmutableSet.Builder<CelFunctionBinding> builder = ImmutableSet.builder();
builder.addAll(overloadBindings);
for (CelFunctionBinding b : overloadBindings) {
builder.add(
new FunctionBindingImpl(
functionName, b.getOverloadId(), b.getArgTypes(), b.getDefinition(), b.isStrict()));
}

// If there is already a binding with the same name as the function, we treat it as a
// "Singleton" binding and do not create a dynamic dispatch wrapper for it.
Expand All@@ -80,11 +101,12 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
CelFunctionBinding singleBinding = Iterables.getOnlyElement(overloadBindings);
builder.add(
new FunctionBindingImpl(
functionName,
functionName,
singleBinding.getArgTypes(),
singleBinding.getDefinition(),
singleBinding.isStrict()));
} else {
} else if (overloadBindings.size() > 1) {
builder.add(new DynamicDispatchBinding(functionName, overloadBindings));
}
}
Expand All@@ -93,7 +115,7 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
}

@Immutable
static final class DynamicDispatchBinding implements CelFunctionBinding {
static final class DynamicDispatchBinding implements InternalCelFunctionBinding {

private final boolean isStrict;
private final DynamicDispatchOverload dynamicDispatchOverload;
Expand All@@ -103,6 +125,11 @@ public String getOverloadId() {
return dynamicDispatchOverload.functionName;
}

@Override
public String getFunctionName() {
return dynamicDispatchOverload.functionName;
}

@Override
public ImmutableList<Class<?>> getArgTypes() {
return ImmutableList.of();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
// Copyright 2026 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.runtime;

import com.google.errorprone.annotations.Immutable;
import dev.cel.common.annotations.Internal;

/**
* Internal interface to expose the function name associated with a binding.
*
* <p>CEL Library Internals. Do Not Use.
*/
@Internal
@Immutable
public interface InternalCelFunctionBinding extends CelFunctionBinding {
String getFunctionName();
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@
import dev.cel.expr.conformance.test.SimpleTest;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.testing.CelRuntimeFlavor;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand DownExpand Up@@ -143,7 +144,7 @@ public void flatten_negativeDepth_throws() {
CelEvaluationException e =
assertThrows(CelEvaluationException.class, () -> eval(cel, "[1,2,3,4].flatten(-1)"));

if (isParseOnly) {
if (runtimeFlavor.equals(CelRuntimeFlavor.PLANNER)) {
assertThat(e)
.hasMessageThat()
.contains("evaluation error at <input>:17: Function 'flatten' failed");
Expand Down
4 changes: 3 additions & 1 deletion runtime/src/main/java/dev/cel/runtime/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,7 @@ LITE_PROGRAM_IMPL_SOURCES = [
FUNCTION_BINDING_SOURCES = [
"CelFunctionBinding.java",
"FunctionBindingImpl.java",
"InternalCelFunctionBinding.java",
]

# keep sorted
Expand DownExpand Up@@ -740,6 +741,7 @@ java_library(
deps = [
":evaluation_exception",
":function_overload",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
Expand All@@ -754,6 +756,7 @@ cel_android_library(
deps = [
":evaluation_exception",
":function_overload_android",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
Expand DownExpand Up@@ -890,7 +893,6 @@ java_library(
"//common/types:type_providers",
"//common/values:cel_value_provider",
"//common/values:proto_message_value_provider",
"//runtime/standard:add",
"//runtime/standard:int",
"//runtime/standard:timestamp",
"@maven//:com_google_code_findbugs_annotations",
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,7 @@ static CelFunctionBinding from(
overloadId, ImmutableList.copyOf(argTypes), impl, /* isStrict= */ true);
}


/** See {@link #fromOverloads(String, Collection)}. */
static ImmutableSet<CelFunctionBinding> fromOverloads(
String functionName, CelFunctionBinding... overloadBindings) {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,7 +63,12 @@ public static CelLateFunctionBindings from(Collection<CelFunctionBinding> functi
}

private static CelResolvedOverload createResolvedOverload(CelFunctionBinding binding) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
return CelResolvedOverload.of(
functionName,
binding.getOverloadId(),
binding.getDefinition(),
binding.isStrict(),
Expand Down
26 changes: 19 additions & 7 deletions runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,6 +30,9 @@
@Internal
public abstract class CelResolvedOverload {

/** The base function name. */
public abstract String getFunctionName();

/** The overload id of the function. */
public abstract String getOverloadId();

Expand DownExpand Up@@ -61,40 +64,44 @@ public Object invoke(Object[] args) throws CelEvaluationException {
|| CelFunctionOverload.canHandle(args, getParameterTypes(), isStrict())) {
return getDefinition().apply(args);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg1, Object arg2) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg1, arg2, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg1, arg2);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Class<?>... parameterTypes) {
return of(overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
return of(functionName, overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Expand All@@ -104,7 +111,12 @@ public static CelResolvedOverload of(
? (OptimizedFunctionOverload) definition
: definition::apply;
return new AutoValue_CelResolvedOverload(
overloadId, ImmutableList.copyOf(parameterTypes), isStrict, definition, optimizedDef);
functionName,
overloadId,
ImmutableList.copyOf(parameterTypes),
isStrict,
definition,
optimizedDef);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -381,15 +381,25 @@ private static DefaultDispatcher newDispatcher(
DefaultDispatcher.Builder builder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding binding :
standardFunctions.newFunctionBindings(runtimeEquality, options)) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
binding.getDefinition());
}

for (CelFunctionBinding binding : customFunctionBindings) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -305,15 +305,25 @@ public CelRuntimeLegacyImpl build() {
DefaultDispatcher.Builder dispatcherBuilder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding standardFunctionBinding :
newStandardFunctionBindings(runtimeEquality)) {
String functionName = standardFunctionBinding.getOverloadId();
if (standardFunctionBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) standardFunctionBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
standardFunctionBinding.getOverloadId(),
standardFunctionBinding.getArgTypes(),
standardFunctionBinding.isStrict(),
standardFunctionBinding.getDefinition());
}

for (CelFunctionBinding customBinding : customFunctionBindings.values()) {
String functionName = customBinding.getOverloadId();
if (customBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) customBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
customBinding.getOverloadId(),
customBinding.getArgTypes(),
customBinding.isStrict(),
Expand Down
23 changes: 18 additions & 5 deletions runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,32 +134,41 @@ public static class Builder {
@AutoValue
@Immutable
abstract static class OverloadEntry {
abstract String functionName();

abstract ImmutableList<Class<?>> argTypes();

abstract boolean isStrict();

abstract CelFunctionOverload overload();

private static OverloadEntry of(
ImmutableList<Class<?>> argTypes, boolean isStrict, CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(argTypes, isStrict, overload);
String functionName,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(
functionName, argTypes, isStrict, overload);
}
}

private final Map<String, OverloadEntry> overloads;

@CanIgnoreReturnValue
public Builder addOverload(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
checkNotNull(functionName);
checkArgument(!functionName.isEmpty(), "Function name cannot be empty.");
checkNotNull(overloadId);
checkArgument(!overloadId.isEmpty(), "Overload ID cannot be empty.");
checkNotNull(argTypes);
checkNotNull(overload);

OverloadEntry newEntry = OverloadEntry.of(argTypes, isStrict, overload);
OverloadEntry newEntry = OverloadEntry.of(functionName, argTypes, isStrict, overload);

overloads.merge(
overloadId,
Expand DownExpand Up@@ -188,7 +197,7 @@ private OverloadEntry mergeDynamicDispatchesOrThrow(
boolean isStrict =
mergedOverload.getOverloadBindings().stream().allMatch(CelFunctionBinding::isStrict);

return OverloadEntry.of(incoming.argTypes(), isStrict, mergedOverload);
return OverloadEntry.of(overloadId, incoming.argTypes(), isStrict, mergedOverload);
}

throw new IllegalArgumentException("Duplicate overload ID binding: " + overloadId);
Expand All@@ -204,7 +213,11 @@ public DefaultDispatcher build() {
resolvedOverloads.put(
overloadId,
CelResolvedOverload.of(
overloadId, overloadImpl, overloadEntry.isStrict(), overloadEntry.argTypes()));
overloadEntry.functionName(),
overloadId,
overloadImpl,
overloadEntry.isStrict(),
overloadEntry.argTypes()));
}

return new DefaultDispatcher(resolvedOverloads.buildOrThrow());
Expand Down
35 changes: 31 additions & 4 deletions runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,9 @@
import dev.cel.common.exceptions.CelOverloadNotFoundException;

@Immutable
final class FunctionBindingImpl implements CelFunctionBinding {
final class FunctionBindingImpl implements InternalCelFunctionBinding {

private final String functionName;

private final String overloadId;

Expand All@@ -33,6 +35,11 @@ final class FunctionBindingImpl implements CelFunctionBinding {

private final boolean isStrict;

@Override
public String getFunctionName() {
return functionName;
}

@Override
public String getOverloadId() {
return overloadId;
Expand All@@ -54,20 +61,34 @@ public boolean isStrict() {
}

FunctionBindingImpl(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this.functionName = functionName;
this.overloadId = overloadId;
this.argTypes = argTypes;
this.definition = definition;
this.isStrict = isStrict;
}

FunctionBindingImpl(
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this(overloadId, overloadId, argTypes, definition, isStrict);
}

static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
String functionName, ImmutableSet<CelFunctionBinding> overloadBindings) {
ImmutableSet.Builder<CelFunctionBinding> builder = ImmutableSet.builder();
builder.addAll(overloadBindings);
for (CelFunctionBinding b : overloadBindings) {
builder.add(
new FunctionBindingImpl(
functionName, b.getOverloadId(), b.getArgTypes(), b.getDefinition(), b.isStrict()));
}

// If there is already a binding with the same name as the function, we treat it as a
// "Singleton" binding and do not create a dynamic dispatch wrapper for it.
Expand All@@ -80,11 +101,12 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
CelFunctionBinding singleBinding = Iterables.getOnlyElement(overloadBindings);
builder.add(
new FunctionBindingImpl(
functionName,
functionName,
singleBinding.getArgTypes(),
singleBinding.getDefinition(),
singleBinding.isStrict()));
} else {
} else if (overloadBindings.size() > 1) {
builder.add(new DynamicDispatchBinding(functionName, overloadBindings));
}
}
Expand All@@ -93,7 +115,7 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
}

@Immutable
static final class DynamicDispatchBinding implements CelFunctionBinding {
static final class DynamicDispatchBinding implements InternalCelFunctionBinding {

private final boolean isStrict;
private final DynamicDispatchOverload dynamicDispatchOverload;
Expand All@@ -103,6 +125,11 @@ public String getOverloadId() {
return dynamicDispatchOverload.functionName;
}

@Override
public String getFunctionName() {
return dynamicDispatchOverload.functionName;
}

@Override
public ImmutableList<Class<?>> getArgTypes() {
return ImmutableList.of();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
// Copyright 2026 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.runtime;

import com.google.errorprone.annotations.Immutable;
import dev.cel.common.annotations.Internal;

/**
* Internal interface to expose the function name associated with a binding.
*
* <p>CEL Library Internals. Do Not Use.
*/
@Internal
@Immutable
public interface InternalCelFunctionBinding extends CelFunctionBinding {
String getFunctionName();
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@
import dev.cel.expr.conformance.test.SimpleTest;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.testing.CelRuntimeFlavor;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand DownExpand Up@@ -143,7 +144,7 @@ public void flatten_negativeDepth_throws() {
CelEvaluationException e =
assertThrows(CelEvaluationException.class, () -> eval(cel, "[1,2,3,4].flatten(-1)"));

if (isParseOnly) {
if (runtimeFlavor.equals(CelRuntimeFlavor.PLANNER)) {
assertThat(e)
.hasMessageThat()
.contains("evaluation error at <input>:17: Function 'flatten' failed");
Expand Down
4 changes: 3 additions & 1 deletion runtime/src/main/java/dev/cel/runtime/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,7 @@ LITE_PROGRAM_IMPL_SOURCES = [
FUNCTION_BINDING_SOURCES = [
"CelFunctionBinding.java",
"FunctionBindingImpl.java",
"InternalCelFunctionBinding.java",
]

# keep sorted
Expand DownExpand Up@@ -740,6 +741,7 @@ java_library(
deps = [
":evaluation_exception",
":function_overload",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
Expand All@@ -754,6 +756,7 @@ cel_android_library(
deps = [
":evaluation_exception",
":function_overload_android",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
Expand DownExpand Up@@ -890,7 +893,6 @@ java_library(
"//common/types:type_providers",
"//common/values:cel_value_provider",
"//common/values:proto_message_value_provider",
"//runtime/standard:add",
"//runtime/standard:int",
"//runtime/standard:timestamp",
"@maven//:com_google_code_findbugs_annotations",
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,7 @@ static CelFunctionBinding from(
overloadId, ImmutableList.copyOf(argTypes), impl, /* isStrict= */ true);
}


/** See {@link #fromOverloads(String, Collection)}. */
static ImmutableSet<CelFunctionBinding> fromOverloads(
String functionName, CelFunctionBinding... overloadBindings) {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,7 +63,12 @@ public static CelLateFunctionBindings from(Collection<CelFunctionBinding> functi
}

private static CelResolvedOverload createResolvedOverload(CelFunctionBinding binding) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
return CelResolvedOverload.of(
functionName,
binding.getOverloadId(),
binding.getDefinition(),
binding.isStrict(),
Expand Down
26 changes: 19 additions & 7 deletions runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,6 +30,9 @@
@Internal
public abstract class CelResolvedOverload {

/** The base function name. */
public abstract String getFunctionName();

/** The overload id of the function. */
public abstract String getOverloadId();

Expand DownExpand Up@@ -61,40 +64,44 @@ public Object invoke(Object[] args) throws CelEvaluationException {
|| CelFunctionOverload.canHandle(args, getParameterTypes(), isStrict())) {
return getDefinition().apply(args);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg1, Object arg2) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg1, arg2, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg1, arg2);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Class<?>... parameterTypes) {
return of(overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
return of(functionName, overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Expand All@@ -104,7 +111,12 @@ public static CelResolvedOverload of(
? (OptimizedFunctionOverload) definition
: definition::apply;
return new AutoValue_CelResolvedOverload(
overloadId, ImmutableList.copyOf(parameterTypes), isStrict, definition, optimizedDef);
functionName,
overloadId,
ImmutableList.copyOf(parameterTypes),
isStrict,
definition,
optimizedDef);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -381,15 +381,25 @@ private static DefaultDispatcher newDispatcher(
DefaultDispatcher.Builder builder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding binding :
standardFunctions.newFunctionBindings(runtimeEquality, options)) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
binding.getDefinition());
}

for (CelFunctionBinding binding : customFunctionBindings) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -305,15 +305,25 @@ public CelRuntimeLegacyImpl build() {
DefaultDispatcher.Builder dispatcherBuilder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding standardFunctionBinding :
newStandardFunctionBindings(runtimeEquality)) {
String functionName = standardFunctionBinding.getOverloadId();
if (standardFunctionBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) standardFunctionBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
standardFunctionBinding.getOverloadId(),
standardFunctionBinding.getArgTypes(),
standardFunctionBinding.isStrict(),
standardFunctionBinding.getDefinition());
}

for (CelFunctionBinding customBinding : customFunctionBindings.values()) {
String functionName = customBinding.getOverloadId();
if (customBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) customBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
customBinding.getOverloadId(),
customBinding.getArgTypes(),
customBinding.isStrict(),
Expand Down
23 changes: 18 additions & 5 deletions runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,32 +134,41 @@ public static class Builder {
@AutoValue
@Immutable
abstract static class OverloadEntry {
abstract String functionName();

abstract ImmutableList<Class<?>> argTypes();

abstract boolean isStrict();

abstract CelFunctionOverload overload();

private static OverloadEntry of(
ImmutableList<Class<?>> argTypes, boolean isStrict, CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(argTypes, isStrict, overload);
String functionName,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(
functionName, argTypes, isStrict, overload);
}
}

private final Map<String, OverloadEntry> overloads;

@CanIgnoreReturnValue
public Builder addOverload(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
checkNotNull(functionName);
checkArgument(!functionName.isEmpty(), "Function name cannot be empty.");
checkNotNull(overloadId);
checkArgument(!overloadId.isEmpty(), "Overload ID cannot be empty.");
checkNotNull(argTypes);
checkNotNull(overload);

OverloadEntry newEntry = OverloadEntry.of(argTypes, isStrict, overload);
OverloadEntry newEntry = OverloadEntry.of(functionName, argTypes, isStrict, overload);

overloads.merge(
overloadId,
Expand DownExpand Up@@ -188,7 +197,7 @@ private OverloadEntry mergeDynamicDispatchesOrThrow(
boolean isStrict =
mergedOverload.getOverloadBindings().stream().allMatch(CelFunctionBinding::isStrict);

return OverloadEntry.of(incoming.argTypes(), isStrict, mergedOverload);
return OverloadEntry.of(overloadId, incoming.argTypes(), isStrict, mergedOverload);
}

throw new IllegalArgumentException("Duplicate overload ID binding: " + overloadId);
Expand All@@ -204,7 +213,11 @@ public DefaultDispatcher build() {
resolvedOverloads.put(
overloadId,
CelResolvedOverload.of(
overloadId, overloadImpl, overloadEntry.isStrict(), overloadEntry.argTypes()));
overloadEntry.functionName(),
overloadId,
overloadImpl,
overloadEntry.isStrict(),
overloadEntry.argTypes()));
}

return new DefaultDispatcher(resolvedOverloads.buildOrThrow());
Expand Down
35 changes: 31 additions & 4 deletions runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,9 @@
import dev.cel.common.exceptions.CelOverloadNotFoundException;

@Immutable
final class FunctionBindingImpl implements CelFunctionBinding {
final class FunctionBindingImpl implements InternalCelFunctionBinding {

private final String functionName;

private final String overloadId;

Expand All@@ -33,6 +35,11 @@ final class FunctionBindingImpl implements CelFunctionBinding {

private final boolean isStrict;

@Override
public String getFunctionName() {
return functionName;
}

@Override
public String getOverloadId() {
return overloadId;
Expand All@@ -54,20 +61,34 @@ public boolean isStrict() {
}

FunctionBindingImpl(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this.functionName = functionName;
this.overloadId = overloadId;
this.argTypes = argTypes;
this.definition = definition;
this.isStrict = isStrict;
}

FunctionBindingImpl(
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this(overloadId, overloadId, argTypes, definition, isStrict);
}

static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
String functionName, ImmutableSet<CelFunctionBinding> overloadBindings) {
ImmutableSet.Builder<CelFunctionBinding> builder = ImmutableSet.builder();
builder.addAll(overloadBindings);
for (CelFunctionBinding b : overloadBindings) {
builder.add(
new FunctionBindingImpl(
functionName, b.getOverloadId(), b.getArgTypes(), b.getDefinition(), b.isStrict()));
}

// If there is already a binding with the same name as the function, we treat it as a
// "Singleton" binding and do not create a dynamic dispatch wrapper for it.
Expand All@@ -80,11 +101,12 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
CelFunctionBinding singleBinding = Iterables.getOnlyElement(overloadBindings);
builder.add(
new FunctionBindingImpl(
functionName,
functionName,
singleBinding.getArgTypes(),
singleBinding.getDefinition(),
singleBinding.isStrict()));
} else {
} else if (overloadBindings.size() > 1) {
builder.add(new DynamicDispatchBinding(functionName, overloadBindings));
}
}
Expand All@@ -93,7 +115,7 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
}

@Immutable
static final class DynamicDispatchBinding implements CelFunctionBinding {
static final class DynamicDispatchBinding implements InternalCelFunctionBinding {

private final boolean isStrict;
private final DynamicDispatchOverload dynamicDispatchOverload;
Expand All@@ -103,6 +125,11 @@ public String getOverloadId() {
return dynamicDispatchOverload.functionName;
}

@Override
public String getFunctionName() {
return dynamicDispatchOverload.functionName;
}

@Override
public ImmutableList<Class<?>> getArgTypes() {
return ImmutableList.of();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
// Copyright 2026 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.runtime;

import com.google.errorprone.annotations.Immutable;
import dev.cel.common.annotations.Internal;

/**
* Internal interface to expose the function name associated with a binding.
*
* <p>CEL Library Internals. Do Not Use.
*/
@Internal
@Immutable
public interface InternalCelFunctionBinding extends CelFunctionBinding {
String getFunctionName();
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@
import dev.cel.expr.conformance.test.SimpleTest;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.testing.CelRuntimeFlavor;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand DownExpand Up@@ -143,7 +144,7 @@ public void flatten_negativeDepth_throws() {
CelEvaluationException e =
assertThrows(CelEvaluationException.class, () -> eval(cel, "[1,2,3,4].flatten(-1)"));

if (isParseOnly) {
if (runtimeFlavor.equals(CelRuntimeFlavor.PLANNER)) {
assertThat(e)
.hasMessageThat()
.contains("evaluation error at <input>:17: Function 'flatten' failed");
Expand Down
4 changes: 3 additions & 1 deletion runtime/src/main/java/dev/cel/runtime/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,7 @@ LITE_PROGRAM_IMPL_SOURCES = [
FUNCTION_BINDING_SOURCES = [
"CelFunctionBinding.java",
"FunctionBindingImpl.java",
"InternalCelFunctionBinding.java",
]

# keep sorted
Expand DownExpand Up@@ -740,6 +741,7 @@ java_library(
deps = [
":evaluation_exception",
":function_overload",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
Expand All@@ -754,6 +756,7 @@ cel_android_library(
deps = [
":evaluation_exception",
":function_overload_android",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
Expand DownExpand Up@@ -890,7 +893,6 @@ java_library(
"//common/types:type_providers",
"//common/values:cel_value_provider",
"//common/values:proto_message_value_provider",
"//runtime/standard:add",
"//runtime/standard:int",
"//runtime/standard:timestamp",
"@maven//:com_google_code_findbugs_annotations",
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,7 @@ static CelFunctionBinding from(
overloadId, ImmutableList.copyOf(argTypes), impl, /* isStrict= */ true);
}


/** See {@link #fromOverloads(String, Collection)}. */
static ImmutableSet<CelFunctionBinding> fromOverloads(
String functionName, CelFunctionBinding... overloadBindings) {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,7 +63,12 @@ public static CelLateFunctionBindings from(Collection<CelFunctionBinding> functi
}

private static CelResolvedOverload createResolvedOverload(CelFunctionBinding binding) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
return CelResolvedOverload.of(
functionName,
binding.getOverloadId(),
binding.getDefinition(),
binding.isStrict(),
Expand Down
26 changes: 19 additions & 7 deletions runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,6 +30,9 @@
@Internal
public abstract class CelResolvedOverload {

/** The base function name. */
public abstract String getFunctionName();

/** The overload id of the function. */
public abstract String getOverloadId();

Expand DownExpand Up@@ -61,40 +64,44 @@ public Object invoke(Object[] args) throws CelEvaluationException {
|| CelFunctionOverload.canHandle(args, getParameterTypes(), isStrict())) {
return getDefinition().apply(args);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg1, Object arg2) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg1, arg2, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg1, arg2);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Class<?>... parameterTypes) {
return of(overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
return of(functionName, overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Expand All@@ -104,7 +111,12 @@ public static CelResolvedOverload of(
? (OptimizedFunctionOverload) definition
: definition::apply;
return new AutoValue_CelResolvedOverload(
overloadId, ImmutableList.copyOf(parameterTypes), isStrict, definition, optimizedDef);
functionName,
overloadId,
ImmutableList.copyOf(parameterTypes),
isStrict,
definition,
optimizedDef);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -381,15 +381,25 @@ private static DefaultDispatcher newDispatcher(
DefaultDispatcher.Builder builder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding binding :
standardFunctions.newFunctionBindings(runtimeEquality, options)) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
binding.getDefinition());
}

for (CelFunctionBinding binding : customFunctionBindings) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -305,15 +305,25 @@ public CelRuntimeLegacyImpl build() {
DefaultDispatcher.Builder dispatcherBuilder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding standardFunctionBinding :
newStandardFunctionBindings(runtimeEquality)) {
String functionName = standardFunctionBinding.getOverloadId();
if (standardFunctionBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) standardFunctionBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
standardFunctionBinding.getOverloadId(),
standardFunctionBinding.getArgTypes(),
standardFunctionBinding.isStrict(),
standardFunctionBinding.getDefinition());
}

for (CelFunctionBinding customBinding : customFunctionBindings.values()) {
String functionName = customBinding.getOverloadId();
if (customBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) customBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
customBinding.getOverloadId(),
customBinding.getArgTypes(),
customBinding.isStrict(),
Expand Down
23 changes: 18 additions & 5 deletions runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,32 +134,41 @@ public static class Builder {
@AutoValue
@Immutable
abstract static class OverloadEntry {
abstract String functionName();

abstract ImmutableList<Class<?>> argTypes();

abstract boolean isStrict();

abstract CelFunctionOverload overload();

private static OverloadEntry of(
ImmutableList<Class<?>> argTypes, boolean isStrict, CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(argTypes, isStrict, overload);
String functionName,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(
functionName, argTypes, isStrict, overload);
}
}

private final Map<String, OverloadEntry> overloads;

@CanIgnoreReturnValue
public Builder addOverload(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
checkNotNull(functionName);
checkArgument(!functionName.isEmpty(), "Function name cannot be empty.");
checkNotNull(overloadId);
checkArgument(!overloadId.isEmpty(), "Overload ID cannot be empty.");
checkNotNull(argTypes);
checkNotNull(overload);

OverloadEntry newEntry = OverloadEntry.of(argTypes, isStrict, overload);
OverloadEntry newEntry = OverloadEntry.of(functionName, argTypes, isStrict, overload);

overloads.merge(
overloadId,
Expand DownExpand Up@@ -188,7 +197,7 @@ private OverloadEntry mergeDynamicDispatchesOrThrow(
boolean isStrict =
mergedOverload.getOverloadBindings().stream().allMatch(CelFunctionBinding::isStrict);

return OverloadEntry.of(incoming.argTypes(), isStrict, mergedOverload);
return OverloadEntry.of(overloadId, incoming.argTypes(), isStrict, mergedOverload);
}

throw new IllegalArgumentException("Duplicate overload ID binding: " + overloadId);
Expand All@@ -204,7 +213,11 @@ public DefaultDispatcher build() {
resolvedOverloads.put(
overloadId,
CelResolvedOverload.of(
overloadId, overloadImpl, overloadEntry.isStrict(), overloadEntry.argTypes()));
overloadEntry.functionName(),
overloadId,
overloadImpl,
overloadEntry.isStrict(),
overloadEntry.argTypes()));
}

return new DefaultDispatcher(resolvedOverloads.buildOrThrow());
Expand Down
35 changes: 31 additions & 4 deletions runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,9 @@
import dev.cel.common.exceptions.CelOverloadNotFoundException;

@Immutable
final class FunctionBindingImpl implements CelFunctionBinding {
final class FunctionBindingImpl implements InternalCelFunctionBinding {

private final String functionName;

private final String overloadId;

Expand All@@ -33,6 +35,11 @@ final class FunctionBindingImpl implements CelFunctionBinding {

private final boolean isStrict;

@Override
public String getFunctionName() {
return functionName;
}

@Override
public String getOverloadId() {
return overloadId;
Expand All@@ -54,20 +61,34 @@ public boolean isStrict() {
}

FunctionBindingImpl(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this.functionName = functionName;
this.overloadId = overloadId;
this.argTypes = argTypes;
this.definition = definition;
this.isStrict = isStrict;
}

FunctionBindingImpl(
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this(overloadId, overloadId, argTypes, definition, isStrict);
}

static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
String functionName, ImmutableSet<CelFunctionBinding> overloadBindings) {
ImmutableSet.Builder<CelFunctionBinding> builder = ImmutableSet.builder();
builder.addAll(overloadBindings);
for (CelFunctionBinding b : overloadBindings) {
builder.add(
new FunctionBindingImpl(
functionName, b.getOverloadId(), b.getArgTypes(), b.getDefinition(), b.isStrict()));
}

// If there is already a binding with the same name as the function, we treat it as a
// "Singleton" binding and do not create a dynamic dispatch wrapper for it.
Expand All@@ -80,11 +101,12 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
CelFunctionBinding singleBinding = Iterables.getOnlyElement(overloadBindings);
builder.add(
new FunctionBindingImpl(
functionName,
functionName,
singleBinding.getArgTypes(),
singleBinding.getDefinition(),
singleBinding.isStrict()));
} else {
} else if (overloadBindings.size() > 1) {
builder.add(new DynamicDispatchBinding(functionName, overloadBindings));
}
}
Expand All@@ -93,7 +115,7 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
}

@Immutable
static final class DynamicDispatchBinding implements CelFunctionBinding {
static final class DynamicDispatchBinding implements InternalCelFunctionBinding {

private final boolean isStrict;
private final DynamicDispatchOverload dynamicDispatchOverload;
Expand All@@ -103,6 +125,11 @@ public String getOverloadId() {
return dynamicDispatchOverload.functionName;
}

@Override
public String getFunctionName() {
return dynamicDispatchOverload.functionName;
}

@Override
public ImmutableList<Class<?>> getArgTypes() {
return ImmutableList.of();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
// Copyright 2026 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.runtime;

import com.google.errorprone.annotations.Immutable;
import dev.cel.common.annotations.Internal;

/**
* Internal interface to expose the function name associated with a binding.
*
* <p>CEL Library Internals. Do Not Use.
*/
@Internal
@Immutable
public interface InternalCelFunctionBinding extends CelFunctionBinding {
String getFunctionName();
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@
import dev.cel.expr.conformance.test.SimpleTest;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.testing.CelRuntimeFlavor;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand DownExpand Up@@ -143,7 +144,7 @@ public void flatten_negativeDepth_throws() {
CelEvaluationException e =
assertThrows(CelEvaluationException.class, () -> eval(cel, "[1,2,3,4].flatten(-1)"));

if (isParseOnly) {
if (runtimeFlavor.equals(CelRuntimeFlavor.PLANNER)) {
assertThat(e)
.hasMessageThat()
.contains("evaluation error at <input>:17: Function 'flatten' failed");
Expand Down
4 changes: 3 additions & 1 deletion runtime/src/main/java/dev/cel/runtime/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,7 @@ LITE_PROGRAM_IMPL_SOURCES = [
FUNCTION_BINDING_SOURCES = [
"CelFunctionBinding.java",
"FunctionBindingImpl.java",
"InternalCelFunctionBinding.java",
]

# keep sorted
Expand DownExpand Up@@ -740,6 +741,7 @@ java_library(
deps = [
":evaluation_exception",
":function_overload",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
Expand All@@ -754,6 +756,7 @@ cel_android_library(
deps = [
":evaluation_exception",
":function_overload_android",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
Expand DownExpand Up@@ -890,7 +893,6 @@ java_library(
"//common/types:type_providers",
"//common/values:cel_value_provider",
"//common/values:proto_message_value_provider",
"//runtime/standard:add",
"//runtime/standard:int",
"//runtime/standard:timestamp",
"@maven//:com_google_code_findbugs_annotations",
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,7 @@ static CelFunctionBinding from(
overloadId, ImmutableList.copyOf(argTypes), impl, /* isStrict= */ true);
}


/** See {@link #fromOverloads(String, Collection)}. */
static ImmutableSet<CelFunctionBinding> fromOverloads(
String functionName, CelFunctionBinding... overloadBindings) {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,7 +63,12 @@ public static CelLateFunctionBindings from(Collection<CelFunctionBinding> functi
}

private static CelResolvedOverload createResolvedOverload(CelFunctionBinding binding) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
return CelResolvedOverload.of(
functionName,
binding.getOverloadId(),
binding.getDefinition(),
binding.isStrict(),
Expand Down
26 changes: 19 additions & 7 deletions runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,6 +30,9 @@
@Internal
public abstract class CelResolvedOverload {

/** The base function name. */
public abstract String getFunctionName();

/** The overload id of the function. */
public abstract String getOverloadId();

Expand DownExpand Up@@ -61,40 +64,44 @@ public Object invoke(Object[] args) throws CelEvaluationException {
|| CelFunctionOverload.canHandle(args, getParameterTypes(), isStrict())) {
return getDefinition().apply(args);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg1, Object arg2) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg1, arg2, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg1, arg2);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Class<?>... parameterTypes) {
return of(overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
return of(functionName, overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Expand All@@ -104,7 +111,12 @@ public static CelResolvedOverload of(
? (OptimizedFunctionOverload) definition
: definition::apply;
return new AutoValue_CelResolvedOverload(
overloadId, ImmutableList.copyOf(parameterTypes), isStrict, definition, optimizedDef);
functionName,
overloadId,
ImmutableList.copyOf(parameterTypes),
isStrict,
definition,
optimizedDef);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -381,15 +381,25 @@ private static DefaultDispatcher newDispatcher(
DefaultDispatcher.Builder builder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding binding :
standardFunctions.newFunctionBindings(runtimeEquality, options)) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
binding.getDefinition());
}

for (CelFunctionBinding binding : customFunctionBindings) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -305,15 +305,25 @@ public CelRuntimeLegacyImpl build() {
DefaultDispatcher.Builder dispatcherBuilder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding standardFunctionBinding :
newStandardFunctionBindings(runtimeEquality)) {
String functionName = standardFunctionBinding.getOverloadId();
if (standardFunctionBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) standardFunctionBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
standardFunctionBinding.getOverloadId(),
standardFunctionBinding.getArgTypes(),
standardFunctionBinding.isStrict(),
standardFunctionBinding.getDefinition());
}

for (CelFunctionBinding customBinding : customFunctionBindings.values()) {
String functionName = customBinding.getOverloadId();
if (customBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) customBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
customBinding.getOverloadId(),
customBinding.getArgTypes(),
customBinding.isStrict(),
Expand Down
23 changes: 18 additions & 5 deletions runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,32 +134,41 @@ public static class Builder {
@AutoValue
@Immutable
abstract static class OverloadEntry {
abstract String functionName();

abstract ImmutableList<Class<?>> argTypes();

abstract boolean isStrict();

abstract CelFunctionOverload overload();

private static OverloadEntry of(
ImmutableList<Class<?>> argTypes, boolean isStrict, CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(argTypes, isStrict, overload);
String functionName,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(
functionName, argTypes, isStrict, overload);
}
}

private final Map<String, OverloadEntry> overloads;

@CanIgnoreReturnValue
public Builder addOverload(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
checkNotNull(functionName);
checkArgument(!functionName.isEmpty(), "Function name cannot be empty.");
checkNotNull(overloadId);
checkArgument(!overloadId.isEmpty(), "Overload ID cannot be empty.");
checkNotNull(argTypes);
checkNotNull(overload);

OverloadEntry newEntry = OverloadEntry.of(argTypes, isStrict, overload);
OverloadEntry newEntry = OverloadEntry.of(functionName, argTypes, isStrict, overload);

overloads.merge(
overloadId,
Expand DownExpand Up@@ -188,7 +197,7 @@ private OverloadEntry mergeDynamicDispatchesOrThrow(
boolean isStrict =
mergedOverload.getOverloadBindings().stream().allMatch(CelFunctionBinding::isStrict);

return OverloadEntry.of(incoming.argTypes(), isStrict, mergedOverload);
return OverloadEntry.of(overloadId, incoming.argTypes(), isStrict, mergedOverload);
}

throw new IllegalArgumentException("Duplicate overload ID binding: " + overloadId);
Expand All@@ -204,7 +213,11 @@ public DefaultDispatcher build() {
resolvedOverloads.put(
overloadId,
CelResolvedOverload.of(
overloadId, overloadImpl, overloadEntry.isStrict(), overloadEntry.argTypes()));
overloadEntry.functionName(),
overloadId,
overloadImpl,
overloadEntry.isStrict(),
overloadEntry.argTypes()));
}

return new DefaultDispatcher(resolvedOverloads.buildOrThrow());
Expand Down
35 changes: 31 additions & 4 deletions runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,9 @@
import dev.cel.common.exceptions.CelOverloadNotFoundException;

@Immutable
final class FunctionBindingImpl implements CelFunctionBinding {
final class FunctionBindingImpl implements InternalCelFunctionBinding {

private final String functionName;

private final String overloadId;

Expand All@@ -33,6 +35,11 @@ final class FunctionBindingImpl implements CelFunctionBinding {

private final boolean isStrict;

@Override
public String getFunctionName() {
return functionName;
}

@Override
public String getOverloadId() {
return overloadId;
Expand All@@ -54,20 +61,34 @@ public boolean isStrict() {
}

FunctionBindingImpl(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this.functionName = functionName;
this.overloadId = overloadId;
this.argTypes = argTypes;
this.definition = definition;
this.isStrict = isStrict;
}

FunctionBindingImpl(
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this(overloadId, overloadId, argTypes, definition, isStrict);
}

static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
String functionName, ImmutableSet<CelFunctionBinding> overloadBindings) {
ImmutableSet.Builder<CelFunctionBinding> builder = ImmutableSet.builder();
builder.addAll(overloadBindings);
for (CelFunctionBinding b : overloadBindings) {
builder.add(
new FunctionBindingImpl(
functionName, b.getOverloadId(), b.getArgTypes(), b.getDefinition(), b.isStrict()));
}

// If there is already a binding with the same name as the function, we treat it as a
// "Singleton" binding and do not create a dynamic dispatch wrapper for it.
Expand All@@ -80,11 +101,12 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
CelFunctionBinding singleBinding = Iterables.getOnlyElement(overloadBindings);
builder.add(
new FunctionBindingImpl(
functionName,
functionName,
singleBinding.getArgTypes(),
singleBinding.getDefinition(),
singleBinding.isStrict()));
} else {
} else if (overloadBindings.size() > 1) {
builder.add(new DynamicDispatchBinding(functionName, overloadBindings));
}
}
Expand All@@ -93,7 +115,7 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
}

@Immutable
static final class DynamicDispatchBinding implements CelFunctionBinding {
static final class DynamicDispatchBinding implements InternalCelFunctionBinding {

private final boolean isStrict;
private final DynamicDispatchOverload dynamicDispatchOverload;
Expand All@@ -103,6 +125,11 @@ public String getOverloadId() {
return dynamicDispatchOverload.functionName;
}

@Override
public String getFunctionName() {
return dynamicDispatchOverload.functionName;
}

@Override
public ImmutableList<Class<?>> getArgTypes() {
return ImmutableList.of();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
// Copyright 2026 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.runtime;

import com.google.errorprone.annotations.Immutable;
import dev.cel.common.annotations.Internal;

/**
* Internal interface to expose the function name associated with a binding.
*
* <p>CEL Library Internals. Do Not Use.
*/
@Internal
@Immutable
public interface InternalCelFunctionBinding extends CelFunctionBinding {
String getFunctionName();
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,6 +29,7 @@
import dev.cel.expr.conformance.test.SimpleTest;
import dev.cel.parser.CelStandardMacro;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.testing.CelRuntimeFlavor;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand DownExpand Up@@ -143,7 +144,7 @@ public void flatten_negativeDepth_throws() {
CelEvaluationException e =
assertThrows(CelEvaluationException.class, () -> eval(cel, "[1,2,3,4].flatten(-1)"));

if (isParseOnly) {
if (runtimeFlavor.equals(CelRuntimeFlavor.PLANNER)) {
assertThat(e)
.hasMessageThat()
.contains("evaluation error at <input>:17: Function 'flatten' failed");
Expand Down
4 changes: 3 additions & 1 deletion runtime/src/main/java/dev/cel/runtime/BUILD.bazel
Original file line numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,7 @@ LITE_PROGRAM_IMPL_SOURCES = [
FUNCTION_BINDING_SOURCES = [
"CelFunctionBinding.java",
"FunctionBindingImpl.java",
"InternalCelFunctionBinding.java",
]

# keep sorted
Expand DownExpand Up@@ -740,6 +741,7 @@ java_library(
deps = [
":evaluation_exception",
":function_overload",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
Expand All@@ -754,6 +756,7 @@ cel_android_library(
deps = [
":evaluation_exception",
":function_overload_android",
"//common/annotations",
"//common/exceptions:overload_not_found",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
Expand DownExpand Up@@ -890,7 +893,6 @@ java_library(
"//common/types:type_providers",
"//common/values:cel_value_provider",
"//common/values:proto_message_value_provider",
"//runtime/standard:add",
"//runtime/standard:int",
"//runtime/standard:timestamp",
"@maven//:com_google_code_findbugs_annotations",
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,6 +100,7 @@ static CelFunctionBinding from(
overloadId, ImmutableList.copyOf(argTypes), impl, /* isStrict= */ true);
}


/** See {@link #fromOverloads(String, Collection)}. */
static ImmutableSet<CelFunctionBinding> fromOverloads(
String functionName, CelFunctionBinding... overloadBindings) {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,7 +63,12 @@ public static CelLateFunctionBindings from(Collection<CelFunctionBinding> functi
}

private static CelResolvedOverload createResolvedOverload(CelFunctionBinding binding) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
return CelResolvedOverload.of(
functionName,
binding.getOverloadId(),
binding.getDefinition(),
binding.isStrict(),
Expand Down
26 changes: 19 additions & 7 deletions runtime/src/main/java/dev/cel/runtime/CelResolvedOverload.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,6 +30,9 @@
@Internal
public abstract class CelResolvedOverload {

/** The base function name. */
public abstract String getFunctionName();

/** The overload id of the function. */
public abstract String getOverloadId();

Expand DownExpand Up@@ -61,40 +64,44 @@ public Object invoke(Object[] args) throws CelEvaluationException {
|| CelFunctionOverload.canHandle(args, getParameterTypes(), isStrict())) {
return getDefinition().apply(args);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

public Object invoke(Object arg1, Object arg2) throws CelEvaluationException {
if (isDynamicDispatch()
|| CelFunctionOverload.canHandle(arg1, arg2, getParameterTypes(), isStrict())) {
return getOptimizedDefinition().apply(arg1, arg2);
}
throw new CelOverloadNotFoundException(getOverloadId());
throw new CelOverloadNotFoundException(getFunctionName(), ImmutableList.of(getOverloadId()));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Class<?>... parameterTypes) {
return of(overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
return of(functionName, overloadId, definition, isStrict, ImmutableList.copyOf(parameterTypes));
}

/**
* Creates a new resolved overload from the given overload id, parameter types, and definition.
* Creates a new resolved overload from the given function name, overload id, parameter types, and
* definition.
*/
public static CelResolvedOverload of(
String functionName,
String overloadId,
CelFunctionOverload definition,
boolean isStrict,
Expand All@@ -104,7 +111,12 @@ public static CelResolvedOverload of(
? (OptimizedFunctionOverload) definition
: definition::apply;
return new AutoValue_CelResolvedOverload(
overloadId, ImmutableList.copyOf(parameterTypes), isStrict, definition, optimizedDef);
functionName,
overloadId,
ImmutableList.copyOf(parameterTypes),
isStrict,
definition,
optimizedDef);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -381,15 +381,25 @@ private static DefaultDispatcher newDispatcher(
DefaultDispatcher.Builder builder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding binding :
standardFunctions.newFunctionBindings(runtimeEquality, options)) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
binding.getDefinition());
}

for (CelFunctionBinding binding : customFunctionBindings) {
String functionName = binding.getOverloadId();
if (binding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) binding).getFunctionName();
}
builder.addOverload(
functionName,
binding.getOverloadId(),
binding.getArgTypes(),
binding.isStrict(),
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/CelRuntimeLegacyImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -305,15 +305,25 @@ public CelRuntimeLegacyImpl build() {
DefaultDispatcher.Builder dispatcherBuilder = DefaultDispatcher.newBuilder();
for (CelFunctionBinding standardFunctionBinding :
newStandardFunctionBindings(runtimeEquality)) {
String functionName = standardFunctionBinding.getOverloadId();
if (standardFunctionBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) standardFunctionBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
standardFunctionBinding.getOverloadId(),
standardFunctionBinding.getArgTypes(),
standardFunctionBinding.isStrict(),
standardFunctionBinding.getDefinition());
}

for (CelFunctionBinding customBinding : customFunctionBindings.values()) {
String functionName = customBinding.getOverloadId();
if (customBinding instanceof InternalCelFunctionBinding) {
functionName = ((InternalCelFunctionBinding) customBinding).getFunctionName();
}
dispatcherBuilder.addOverload(
functionName,
customBinding.getOverloadId(),
customBinding.getArgTypes(),
customBinding.isStrict(),
Expand Down
23 changes: 18 additions & 5 deletions runtime/src/main/java/dev/cel/runtime/DefaultDispatcher.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -134,32 +134,41 @@ public static class Builder {
@AutoValue
@Immutable
abstract static class OverloadEntry {
abstract String functionName();

abstract ImmutableList<Class<?>> argTypes();

abstract boolean isStrict();

abstract CelFunctionOverload overload();

private static OverloadEntry of(
ImmutableList<Class<?>> argTypes, boolean isStrict, CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(argTypes, isStrict, overload);
String functionName,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
return new AutoValue_DefaultDispatcher_Builder_OverloadEntry(
functionName, argTypes, isStrict, overload);
}
}

private final Map<String, OverloadEntry> overloads;

@CanIgnoreReturnValue
public Builder addOverload(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
boolean isStrict,
CelFunctionOverload overload) {
checkNotNull(functionName);
checkArgument(!functionName.isEmpty(), "Function name cannot be empty.");
checkNotNull(overloadId);
checkArgument(!overloadId.isEmpty(), "Overload ID cannot be empty.");
checkNotNull(argTypes);
checkNotNull(overload);

OverloadEntry newEntry = OverloadEntry.of(argTypes, isStrict, overload);
OverloadEntry newEntry = OverloadEntry.of(functionName, argTypes, isStrict, overload);

overloads.merge(
overloadId,
Expand DownExpand Up@@ -188,7 +197,7 @@ private OverloadEntry mergeDynamicDispatchesOrThrow(
boolean isStrict =
mergedOverload.getOverloadBindings().stream().allMatch(CelFunctionBinding::isStrict);

return OverloadEntry.of(incoming.argTypes(), isStrict, mergedOverload);
return OverloadEntry.of(overloadId, incoming.argTypes(), isStrict, mergedOverload);
}

throw new IllegalArgumentException("Duplicate overload ID binding: " + overloadId);
Expand All@@ -204,7 +213,11 @@ public DefaultDispatcher build() {
resolvedOverloads.put(
overloadId,
CelResolvedOverload.of(
overloadId, overloadImpl, overloadEntry.isStrict(), overloadEntry.argTypes()));
overloadEntry.functionName(),
overloadId,
overloadImpl,
overloadEntry.isStrict(),
overloadEntry.argTypes()));
}

return new DefaultDispatcher(resolvedOverloads.buildOrThrow());
Expand Down
35 changes: 31 additions & 4 deletions runtime/src/main/java/dev/cel/runtime/FunctionBindingImpl.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,9 @@
import dev.cel.common.exceptions.CelOverloadNotFoundException;

@Immutable
final class FunctionBindingImpl implements CelFunctionBinding {
final class FunctionBindingImpl implements InternalCelFunctionBinding {

private final String functionName;

private final String overloadId;

Expand All@@ -33,6 +35,11 @@ final class FunctionBindingImpl implements CelFunctionBinding {

private final boolean isStrict;

@Override
public String getFunctionName() {
return functionName;
}

@Override
public String getOverloadId() {
return overloadId;
Expand All@@ -54,20 +61,34 @@ public boolean isStrict() {
}

FunctionBindingImpl(
String functionName,
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this.functionName = functionName;
this.overloadId = overloadId;
this.argTypes = argTypes;
this.definition = definition;
this.isStrict = isStrict;
}

FunctionBindingImpl(
String overloadId,
ImmutableList<Class<?>> argTypes,
CelFunctionOverload definition,
boolean isStrict) {
this(overloadId, overloadId, argTypes, definition, isStrict);
}

static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
String functionName, ImmutableSet<CelFunctionBinding> overloadBindings) {
ImmutableSet.Builder<CelFunctionBinding> builder = ImmutableSet.builder();
builder.addAll(overloadBindings);
for (CelFunctionBinding b : overloadBindings) {
builder.add(
new FunctionBindingImpl(
functionName, b.getOverloadId(), b.getArgTypes(), b.getDefinition(), b.isStrict()));
}

// If there is already a binding with the same name as the function, we treat it as a
// "Singleton" binding and do not create a dynamic dispatch wrapper for it.
Expand All@@ -80,11 +101,12 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
CelFunctionBinding singleBinding = Iterables.getOnlyElement(overloadBindings);
builder.add(
new FunctionBindingImpl(
functionName,
functionName,
singleBinding.getArgTypes(),
singleBinding.getDefinition(),
singleBinding.isStrict()));
} else {
} else if (overloadBindings.size() > 1) {
builder.add(new DynamicDispatchBinding(functionName, overloadBindings));
}
}
Expand All@@ -93,7 +115,7 @@ static ImmutableSet<CelFunctionBinding> groupOverloadsToFunction(
}

@Immutable
static final class DynamicDispatchBinding implements CelFunctionBinding {
static final class DynamicDispatchBinding implements InternalCelFunctionBinding {

private final boolean isStrict;
private final DynamicDispatchOverload dynamicDispatchOverload;
Expand All@@ -103,6 +125,11 @@ public String getOverloadId() {
return dynamicDispatchOverload.functionName;
}

@Override
public String getFunctionName() {
return dynamicDispatchOverload.functionName;
}

@Override
public ImmutableList<Class<?>> getArgTypes() {
return ImmutableList.of();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
// Copyright 2026 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.runtime;

import com.google.errorprone.annotations.Immutable;
import dev.cel.common.annotations.Internal;

/**
* Internal interface to expose the function name associated with a binding.
*
* <p>CEL Library Internals. Do Not Use.
*/
@Internal
@Immutable
public interface InternalCelFunctionBinding extends CelFunctionBinding {
String getFunctionName();
}
Loading
Loading