diff --git a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java index 43e64bb8..2b836dcc 100644 --- a/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java +++ b/extensions/src/test/java/dev/cel/extensions/CelBindingsExtensionsTest.java @@ -26,7 +26,7 @@ import dev.cel.common.types.SimpleType; import dev.cel.compiler.CelCompiler; import dev.cel.compiler.CelCompilerFactory; -import dev.cel.parser.CelMacro; +import dev.cel.parser.CelStandardMacro; import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntime.CelFunctionBinding; import dev.cel.runtime.CelRuntimeFactory; @@ -39,7 +39,7 @@ public final class CelBindingsExtensionsTest { private static final CelCompiler COMPILER = CelCompilerFactory.standardCelCompilerBuilder() - .addMacros(CelMacro.STANDARD_MACROS) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .addLibraries(CelExtensions.bindings()) .build(); diff --git a/parser/src/main/java/dev/cel/parser/CelMacro.java b/parser/src/main/java/dev/cel/parser/CelMacro.java index 06e48d8b..cf75714a 100644 --- a/parser/src/main/java/dev/cel/parser/CelMacro.java +++ b/parser/src/main/java/dev/cel/parser/CelMacro.java @@ -19,70 +19,13 @@ import static com.google.common.base.Strings.isNullOrEmpty; import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.Immutable; -import dev.cel.common.CelIssue; -import dev.cel.common.ast.CelExpr; -import java.util.Optional; /** Describes a function signature to match and the {@link CelMacroExpander} to apply. */ @AutoValue @Immutable public abstract class CelMacro implements Comparable { - - private static final String ACCUMULATOR_VAR = "__result__"; - - /** Field presence test macro */ - public static final CelMacro HAS = - newGlobalMacro(Operator.HAS.getFunction(), 1, CelMacro::expandHasMacro); - - /** - * Boolean comprehension which asserts that a predicate holds true for all elements in the input - * range. - */ - public static final CelMacro ALL = - newReceiverMacro(Operator.ALL.getFunction(), 2, CelMacro::expandAllMacro); - - /** - * Boolean comprehension which asserts that a predicate holds true for at least one element in the - * input range. - */ - public static final CelMacro EXISTS = - newReceiverMacro(Operator.EXISTS.getFunction(), 2, CelMacro::expandExistsMacro); - - /** - * Boolean comprehension which asserts that a predicate holds true for exactly one element in the - * input range. - */ - public static final CelMacro EXISTS_ONE = - newReceiverMacro(Operator.EXISTS_ONE.getFunction(), 2, CelMacro::expandExistsOneMacro); - - /** - * Comprehension which applies a transform to each element in the input range and produces a list - * of equivalent size as output. - */ - public static final CelMacro MAP = - newReceiverMacro(Operator.MAP.getFunction(), 2, CelMacro::expandMapMacro); - - /** - * Comprehension which conditionally applies a transform to elements in the list which satisfy the - * filter predicate. - */ - public static final CelMacro MAP_FILTER = - newReceiverMacro(Operator.MAP.getFunction(), 3, CelMacro::expandMapMacro); - - /** - * Comprehension which produces a list containing elements in the input range which match the - * filter. - */ - public static final CelMacro FILTER = - newReceiverMacro(Operator.FILTER.getFunction(), 2, CelMacro::expandFilterMacro); - - /** Set of all standard macros supported by the CEL spec. */ - public static final ImmutableList STANDARD_MACROS = - ImmutableList.of(HAS, ALL, EXISTS, EXISTS_ONE, MAP, MAP_FILTER, FILTER); - // Package-private default constructor to prevent extensions outside of the codebase. CelMacro() {} @@ -241,186 +184,4 @@ abstract static class Builder { @CheckReturnValue abstract CelMacro build(); } - - // CelMacroExpander implementation for CEL's has() macro. - private static Optional expandHasMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 1); - CelExpr arg = checkNotNull(arguments.get(0)); - if (arg.exprKind().getKind() != CelExpr.ExprKind.Kind.SELECT) { - return Optional.of(exprFactory.reportError("invalid argument to has() macro")); - } - return Optional.of(exprFactory.newSelect(arg.select().operand(), arg.select().field(), true)); - } - - // CelMacroExpander implementation for CEL's all() macro. - private static Optional expandAllMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 2); - CelExpr arg0 = checkNotNull(arguments.get(0)); - if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { - return Optional.of(reportArgumentError(exprFactory, arg0)); - } - CelExpr arg1 = checkNotNull(arguments.get(1)); - CelExpr accuInit = exprFactory.newBoolLiteral(true); - CelExpr condition = - exprFactory.newGlobalCall( - Operator.NOT_STRICTLY_FALSE.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR)); - CelExpr step = - exprFactory.newGlobalCall( - Operator.LOGICAL_AND.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1); - CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR); - return Optional.of( - exprFactory.fold( - arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); - } - - // CelMacroExpander implementation for CEL's exists() macro. - private static Optional expandExistsMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 2); - CelExpr arg0 = checkNotNull(arguments.get(0)); - if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { - return Optional.of(reportArgumentError(exprFactory, arg0)); - } - CelExpr arg1 = checkNotNull(arguments.get(1)); - CelExpr accuInit = exprFactory.newBoolLiteral(false); - CelExpr condition = - exprFactory.newGlobalCall( - Operator.NOT_STRICTLY_FALSE.getFunction(), - exprFactory.newGlobalCall( - Operator.LOGICAL_NOT.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR))); - CelExpr step = - exprFactory.newGlobalCall( - Operator.LOGICAL_OR.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1); - CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR); - return Optional.of( - exprFactory.fold( - arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); - } - - // CelMacroExpander implementation for CEL's exists_one() macro. - private static Optional expandExistsOneMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 2); - CelExpr arg0 = checkNotNull(arguments.get(0)); - if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { - return Optional.of(reportArgumentError(exprFactory, arg0)); - } - CelExpr arg1 = checkNotNull(arguments.get(1)); - CelExpr zeroExpr = exprFactory.newIntLiteral(0); - CelExpr oneExpr = exprFactory.newIntLiteral(1); - CelExpr accuInit = zeroExpr; - CelExpr condition = exprFactory.newBoolLiteral(true); - CelExpr step = - exprFactory.newGlobalCall( - Operator.CONDITIONAL.getFunction(), - arg1, - exprFactory.newGlobalCall( - Operator.ADD.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), oneExpr), - exprFactory.newIdentifier(ACCUMULATOR_VAR)); - CelExpr result = - exprFactory.newGlobalCall( - Operator.EQUALS.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), oneExpr); - return Optional.of( - exprFactory.fold( - arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); - } - - // CelMacroExpander implementation for CEL's map() macro. - private static Optional expandMapMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 2 || arguments.size() == 3); - CelExpr arg0 = checkNotNull(arguments.get(0)); - if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { - return Optional.of( - exprFactory.reportError( - CelIssue.formatError( - exprFactory.getSourceLocation(arg0), "argument is not an identifier"))); - } - CelExpr arg1; - CelExpr arg2; - if (arguments.size() == 3) { - arg2 = checkNotNull(arguments.get(1)); - arg1 = checkNotNull(arguments.get(2)); - } else { - arg1 = checkNotNull(arguments.get(1)); - arg2 = null; - } - CelExpr accuInit = exprFactory.newList(); - CelExpr condition = exprFactory.newBoolLiteral(true); - CelExpr step = - exprFactory.newGlobalCall( - Operator.ADD.getFunction(), - exprFactory.newIdentifier(ACCUMULATOR_VAR), - exprFactory.newList(arg1)); - if (arg2 != null) { - step = - exprFactory.newGlobalCall( - Operator.CONDITIONAL.getFunction(), - arg2, - step, - exprFactory.newIdentifier(ACCUMULATOR_VAR)); - } - return Optional.of( - exprFactory.fold( - arg0.ident().name(), - target, - ACCUMULATOR_VAR, - accuInit, - condition, - step, - exprFactory.newIdentifier(ACCUMULATOR_VAR))); - } - - // CelMacroExpander implementation for CEL's filter() macro. - private static Optional expandFilterMacro( - CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { - checkNotNull(exprFactory); - checkNotNull(target); - checkArgument(arguments.size() == 2); - CelExpr arg0 = checkNotNull(arguments.get(0)); - if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { - return Optional.of(reportArgumentError(exprFactory, arg0)); - } - CelExpr arg1 = checkNotNull(arguments.get(1)); - CelExpr accuInit = exprFactory.newList(); - CelExpr condition = exprFactory.newBoolLiteral(true); - CelExpr step = - exprFactory.newGlobalCall( - Operator.ADD.getFunction(), - exprFactory.newIdentifier(ACCUMULATOR_VAR), - exprFactory.newList(arg0)); - step = - exprFactory.newGlobalCall( - Operator.CONDITIONAL.getFunction(), - arg1, - step, - exprFactory.newIdentifier(ACCUMULATOR_VAR)); - return Optional.of( - exprFactory.fold( - arg0.ident().name(), - target, - ACCUMULATOR_VAR, - accuInit, - condition, - step, - exprFactory.newIdentifier(ACCUMULATOR_VAR))); - } - - private static CelExpr reportArgumentError(CelMacroExprFactory exprFactory, CelExpr argument) { - return exprFactory.reportError( - CelIssue.formatError( - exprFactory.getSourceLocation(argument), "The argument must be a simple name")); - } } diff --git a/parser/src/main/java/dev/cel/parser/CelStandardMacro.java b/parser/src/main/java/dev/cel/parser/CelStandardMacro.java index a4aa50ff..3d93e853 100644 --- a/parser/src/main/java/dev/cel/parser/CelStandardMacro.java +++ b/parser/src/main/java/dev/cel/parser/CelStandardMacro.java @@ -14,55 +14,72 @@ package dev.cel.parser; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import dev.cel.common.CelIssue; +import dev.cel.common.ast.CelExpr; +import java.util.Optional; /** * CelStandardMacro enum represents all of the macros defined as part of the CEL standard library. */ public enum CelStandardMacro { + /** Field presence test macro */ - HAS(CelMacro.HAS), + HAS(CelMacro.newGlobalMacro(Operator.HAS.getFunction(), 1, CelStandardMacro::expandHasMacro)), /** * Boolean comprehension which asserts that a predicate holds true for all elements in the input * range. */ - ALL(CelMacro.ALL), + ALL(CelMacro.newReceiverMacro(Operator.ALL.getFunction(), 2, CelStandardMacro::expandAllMacro)), /** * Boolean comprehension which asserts that a predicate holds true for at least one element in the * input range. */ - EXISTS(CelMacro.EXISTS), + EXISTS( + CelMacro.newReceiverMacro( + Operator.EXISTS.getFunction(), 2, CelStandardMacro::expandExistsMacro)), /** * Boolean comprehension which asserts that a predicate holds true for exactly one element in the * input range. */ - EXISTS_ONE(CelMacro.EXISTS_ONE), + EXISTS_ONE( + CelMacro.newReceiverMacro( + Operator.EXISTS_ONE.getFunction(), 2, CelStandardMacro::expandExistsOneMacro)), /** * Comprehension which applies a transform to each element in the input range and produces a list * of equivalent size as output. */ - MAP(CelMacro.MAP), + MAP(CelMacro.newReceiverMacro(Operator.MAP.getFunction(), 2, CelStandardMacro::expandMapMacro)), /** * Comprehension which conditionally applies a transform to elements in the list which satisfy the * filter predicate. */ - MAP_FILTER(CelMacro.MAP_FILTER), + MAP_FILTER( + CelMacro.newReceiverMacro(Operator.MAP.getFunction(), 3, CelStandardMacro::expandMapMacro)), /** * Comprehension which produces a list containing elements in the input range which match the * filter. */ - FILTER(CelMacro.FILTER); + FILTER( + CelMacro.newReceiverMacro( + Operator.FILTER.getFunction(), 2, CelStandardMacro::expandFilterMacro)); /** Set of all standard macros supported by the CEL spec. */ public static final ImmutableSet STANDARD_MACROS = ImmutableSet.of(HAS, ALL, EXISTS, EXISTS_ONE, MAP, MAP_FILTER, FILTER); + private static final String ACCUMULATOR_VAR = "__result__"; + private final CelMacro macro; CelStandardMacro(CelMacro macro) { @@ -78,4 +95,186 @@ public String getFunction() { public CelMacro getDefinition() { return macro; } + + // CelMacroExpander implementation for CEL's has() macro. + private static Optional expandHasMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 1); + CelExpr arg = checkNotNull(arguments.get(0)); + if (arg.exprKind().getKind() != CelExpr.ExprKind.Kind.SELECT) { + return Optional.of(exprFactory.reportError("invalid argument to has() macro")); + } + return Optional.of(exprFactory.newSelect(arg.select().operand(), arg.select().field(), true)); + } + + // CelMacroExpander implementation for CEL's all() macro. + private static Optional expandAllMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 2); + CelExpr arg0 = checkNotNull(arguments.get(0)); + if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { + return Optional.of(reportArgumentError(exprFactory, arg0)); + } + CelExpr arg1 = checkNotNull(arguments.get(1)); + CelExpr accuInit = exprFactory.newBoolLiteral(true); + CelExpr condition = + exprFactory.newGlobalCall( + Operator.NOT_STRICTLY_FALSE.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR)); + CelExpr step = + exprFactory.newGlobalCall( + Operator.LOGICAL_AND.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1); + CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR); + return Optional.of( + exprFactory.fold( + arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); + } + + // CelMacroExpander implementation for CEL's exists() macro. + private static Optional expandExistsMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 2); + CelExpr arg0 = checkNotNull(arguments.get(0)); + if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { + return Optional.of(reportArgumentError(exprFactory, arg0)); + } + CelExpr arg1 = checkNotNull(arguments.get(1)); + CelExpr accuInit = exprFactory.newBoolLiteral(false); + CelExpr condition = + exprFactory.newGlobalCall( + Operator.NOT_STRICTLY_FALSE.getFunction(), + exprFactory.newGlobalCall( + Operator.LOGICAL_NOT.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR))); + CelExpr step = + exprFactory.newGlobalCall( + Operator.LOGICAL_OR.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), arg1); + CelExpr result = exprFactory.newIdentifier(ACCUMULATOR_VAR); + return Optional.of( + exprFactory.fold( + arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); + } + + // CelMacroExpander implementation for CEL's exists_one() macro. + private static Optional expandExistsOneMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 2); + CelExpr arg0 = checkNotNull(arguments.get(0)); + if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { + return Optional.of(reportArgumentError(exprFactory, arg0)); + } + CelExpr arg1 = checkNotNull(arguments.get(1)); + CelExpr zeroExpr = exprFactory.newIntLiteral(0); + CelExpr oneExpr = exprFactory.newIntLiteral(1); + CelExpr accuInit = zeroExpr; + CelExpr condition = exprFactory.newBoolLiteral(true); + CelExpr step = + exprFactory.newGlobalCall( + Operator.CONDITIONAL.getFunction(), + arg1, + exprFactory.newGlobalCall( + Operator.ADD.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), oneExpr), + exprFactory.newIdentifier(ACCUMULATOR_VAR)); + CelExpr result = + exprFactory.newGlobalCall( + Operator.EQUALS.getFunction(), exprFactory.newIdentifier(ACCUMULATOR_VAR), oneExpr); + return Optional.of( + exprFactory.fold( + arg0.ident().name(), target, ACCUMULATOR_VAR, accuInit, condition, step, result)); + } + + // CelMacroExpander implementation for CEL's map() macro. + private static Optional expandMapMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 2 || arguments.size() == 3); + CelExpr arg0 = checkNotNull(arguments.get(0)); + if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { + return Optional.of( + exprFactory.reportError( + CelIssue.formatError( + exprFactory.getSourceLocation(arg0), "argument is not an identifier"))); + } + CelExpr arg1; + CelExpr arg2; + if (arguments.size() == 3) { + arg2 = checkNotNull(arguments.get(1)); + arg1 = checkNotNull(arguments.get(2)); + } else { + arg1 = checkNotNull(arguments.get(1)); + arg2 = null; + } + CelExpr accuInit = exprFactory.newList(); + CelExpr condition = exprFactory.newBoolLiteral(true); + CelExpr step = + exprFactory.newGlobalCall( + Operator.ADD.getFunction(), + exprFactory.newIdentifier(ACCUMULATOR_VAR), + exprFactory.newList(arg1)); + if (arg2 != null) { + step = + exprFactory.newGlobalCall( + Operator.CONDITIONAL.getFunction(), + arg2, + step, + exprFactory.newIdentifier(ACCUMULATOR_VAR)); + } + return Optional.of( + exprFactory.fold( + arg0.ident().name(), + target, + ACCUMULATOR_VAR, + accuInit, + condition, + step, + exprFactory.newIdentifier(ACCUMULATOR_VAR))); + } + + // CelMacroExpander implementation for CEL's filter() macro. + private static Optional expandFilterMacro( + CelMacroExprFactory exprFactory, CelExpr target, ImmutableList arguments) { + checkNotNull(exprFactory); + checkNotNull(target); + checkArgument(arguments.size() == 2); + CelExpr arg0 = checkNotNull(arguments.get(0)); + if (arg0.exprKind().getKind() != CelExpr.ExprKind.Kind.IDENT) { + return Optional.of(reportArgumentError(exprFactory, arg0)); + } + CelExpr arg1 = checkNotNull(arguments.get(1)); + CelExpr accuInit = exprFactory.newList(); + CelExpr condition = exprFactory.newBoolLiteral(true); + CelExpr step = + exprFactory.newGlobalCall( + Operator.ADD.getFunction(), + exprFactory.newIdentifier(ACCUMULATOR_VAR), + exprFactory.newList(arg0)); + step = + exprFactory.newGlobalCall( + Operator.CONDITIONAL.getFunction(), + arg1, + step, + exprFactory.newIdentifier(ACCUMULATOR_VAR)); + return Optional.of( + exprFactory.fold( + arg0.ident().name(), + target, + ACCUMULATOR_VAR, + accuInit, + condition, + step, + exprFactory.newIdentifier(ACCUMULATOR_VAR))); + } + + private static CelExpr reportArgumentError(CelMacroExprFactory exprFactory, CelExpr argument) { + return exprFactory.reportError( + CelIssue.formatError( + exprFactory.getSourceLocation(argument), "The argument must be a simple name")); + } } diff --git a/parser/src/test/java/dev/cel/parser/CelMacroTest.java b/parser/src/test/java/dev/cel/parser/CelMacroTest.java index 301d2644..585b0157 100644 --- a/parser/src/test/java/dev/cel/parser/CelMacroTest.java +++ b/parser/src/test/java/dev/cel/parser/CelMacroTest.java @@ -16,7 +16,6 @@ import static com.google.common.truth.Truth.assertThat; -import com.google.common.testing.EqualsTester; import dev.cel.common.ast.CelExpr; import java.util.Optional; import org.junit.Test; @@ -26,103 +25,6 @@ @RunWith(JUnit4.class) public final class CelMacroTest { - @Test - public void testHas() { - assertThat(CelMacro.HAS.getFunction()).isEqualTo(Operator.HAS.getFunction()); - assertThat(CelMacro.HAS.getArgumentCount()).isEqualTo(1); - assertThat(CelMacro.HAS.isReceiverStyle()).isFalse(); - assertThat(CelMacro.HAS.getKey()).isEqualTo("has:1:false"); - assertThat(CelMacro.HAS.isVariadic()).isFalse(); - assertThat(CelMacro.HAS.toString()).isEqualTo(CelMacro.HAS.getKey()); - assertThat(CelMacro.HAS.hashCode()).isEqualTo(CelMacro.HAS.getKey().hashCode()); - assertThat(CelMacro.HAS).isEquivalentAccordingToCompareTo(CelMacro.HAS); - } - - @Test - public void testAll() { - assertThat(CelMacro.ALL.getFunction()).isEqualTo(Operator.ALL.getFunction()); - assertThat(CelMacro.ALL.getArgumentCount()).isEqualTo(2); - assertThat(CelMacro.ALL.isReceiverStyle()).isTrue(); - assertThat(CelMacro.ALL.getKey()).isEqualTo("all:2:true"); - assertThat(CelMacro.ALL.isVariadic()).isFalse(); - assertThat(CelMacro.ALL.toString()).isEqualTo(CelMacro.ALL.getKey()); - assertThat(CelMacro.ALL.hashCode()).isEqualTo(CelMacro.ALL.getKey().hashCode()); - assertThat(CelMacro.ALL).isEquivalentAccordingToCompareTo(CelMacro.ALL); - } - - @Test - public void testExists() { - assertThat(CelMacro.EXISTS.getFunction()).isEqualTo(Operator.EXISTS.getFunction()); - assertThat(CelMacro.EXISTS.getArgumentCount()).isEqualTo(2); - assertThat(CelMacro.EXISTS.isReceiverStyle()).isTrue(); - assertThat(CelMacro.EXISTS.getKey()).isEqualTo("exists:2:true"); - assertThat(CelMacro.EXISTS.isVariadic()).isFalse(); - assertThat(CelMacro.EXISTS.toString()).isEqualTo(CelMacro.EXISTS.getKey()); - assertThat(CelMacro.EXISTS.hashCode()).isEqualTo(CelMacro.EXISTS.getKey().hashCode()); - assertThat(CelMacro.EXISTS).isEquivalentAccordingToCompareTo(CelMacro.EXISTS); - } - - @Test - public void testExistsOne() { - assertThat(CelMacro.EXISTS_ONE.getFunction()).isEqualTo(Operator.EXISTS_ONE.getFunction()); - assertThat(CelMacro.EXISTS_ONE.getArgumentCount()).isEqualTo(2); - assertThat(CelMacro.EXISTS_ONE.isReceiverStyle()).isTrue(); - assertThat(CelMacro.EXISTS_ONE.getKey()).isEqualTo("exists_one:2:true"); - assertThat(CelMacro.EXISTS_ONE.isVariadic()).isFalse(); - assertThat(CelMacro.EXISTS_ONE.toString()).isEqualTo(CelMacro.EXISTS_ONE.getKey()); - assertThat(CelMacro.EXISTS_ONE.hashCode()).isEqualTo(CelMacro.EXISTS_ONE.getKey().hashCode()); - assertThat(CelMacro.EXISTS_ONE).isEquivalentAccordingToCompareTo(CelMacro.EXISTS_ONE); - } - - @Test - public void testMap2() { - assertThat(CelMacro.MAP.getFunction()).isEqualTo(Operator.MAP.getFunction()); - assertThat(CelMacro.MAP.getArgumentCount()).isEqualTo(2); - assertThat(CelMacro.MAP.isReceiverStyle()).isTrue(); - assertThat(CelMacro.MAP.getKey()).isEqualTo("map:2:true"); - assertThat(CelMacro.MAP.isVariadic()).isFalse(); - assertThat(CelMacro.MAP.toString()).isEqualTo(CelMacro.MAP.getKey()); - assertThat(CelMacro.MAP.hashCode()).isEqualTo(CelMacro.MAP.getKey().hashCode()); - assertThat(CelMacro.MAP).isEquivalentAccordingToCompareTo(CelMacro.MAP); - } - - @Test - public void testMap3() { - assertThat(CelMacro.MAP_FILTER.getFunction()).isEqualTo(Operator.MAP.getFunction()); - assertThat(CelMacro.MAP_FILTER.getArgumentCount()).isEqualTo(3); - assertThat(CelMacro.MAP_FILTER.isReceiverStyle()).isTrue(); - assertThat(CelMacro.MAP_FILTER.getKey()).isEqualTo("map:3:true"); - assertThat(CelMacro.MAP_FILTER.isVariadic()).isFalse(); - assertThat(CelMacro.MAP_FILTER.toString()).isEqualTo(CelMacro.MAP_FILTER.getKey()); - assertThat(CelMacro.MAP_FILTER.hashCode()).isEqualTo(CelMacro.MAP_FILTER.getKey().hashCode()); - assertThat(CelMacro.MAP_FILTER).isEquivalentAccordingToCompareTo(CelMacro.MAP_FILTER); - } - - @Test - public void testFilter() { - assertThat(CelMacro.FILTER.getFunction()).isEqualTo(Operator.FILTER.getFunction()); - assertThat(CelMacro.FILTER.getArgumentCount()).isEqualTo(2); - assertThat(CelMacro.FILTER.isReceiverStyle()).isTrue(); - assertThat(CelMacro.FILTER.getKey()).isEqualTo("filter:2:true"); - assertThat(CelMacro.FILTER.isVariadic()).isFalse(); - assertThat(CelMacro.FILTER.toString()).isEqualTo(CelMacro.FILTER.getKey()); - assertThat(CelMacro.FILTER.hashCode()).isEqualTo(CelMacro.FILTER.getKey().hashCode()); - assertThat(CelMacro.FILTER).isEquivalentAccordingToCompareTo(CelMacro.FILTER); - } - - @Test - public void testEquals() { - new EqualsTester() - .addEqualityGroup(CelMacro.HAS) - .addEqualityGroup(CelMacro.ALL) - .addEqualityGroup(CelMacro.EXISTS) - .addEqualityGroup(CelMacro.EXISTS_ONE) - .addEqualityGroup(CelMacro.MAP) - .addEqualityGroup(CelMacro.MAP_FILTER) - .addEqualityGroup(CelMacro.FILTER) - .testEquals(); - } - @Test public void testGlobalVarArgMacro() { CelMacro macro = diff --git a/parser/src/test/java/dev/cel/parser/CelParserImplTest.java b/parser/src/test/java/dev/cel/parser/CelParserImplTest.java index 8a9f1439..97bb8573 100644 --- a/parser/src/test/java/dev/cel/parser/CelParserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelParserImplTest.java @@ -40,14 +40,17 @@ public final class CelParserImplTest { @Test public void build_withMacros_containsAllMacros() { CelParserImpl parser = - (CelParserImpl) CelParserImpl.newBuilder().addMacros(CelMacro.STANDARD_MACROS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); - assertThat(parser.findMacro("all:2:true")).hasValue(CelMacro.ALL); - assertThat(parser.findMacro("exists:2:true")).hasValue(CelMacro.EXISTS); - assertThat(parser.findMacro("exists_one:2:true")).hasValue(CelMacro.EXISTS_ONE); - assertThat(parser.findMacro("map:2:true")).hasValue(CelMacro.MAP); - assertThat(parser.findMacro("map:3:true")).hasValue(CelMacro.MAP_FILTER); - assertThat(parser.findMacro("filter:2:true")).hasValue(CelMacro.FILTER); + (CelParserImpl) + CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.STANDARD_MACROS).build(); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); + assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); + assertThat(parser.findMacro("exists_one:2:true")) + .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); + assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); + assertThat(parser.findMacro("map:3:true")) + .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); + assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); } @Test @@ -55,13 +58,15 @@ public void build_withStandardMacros_containsAllMacros() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.STANDARD_MACROS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); - assertThat(parser.findMacro("all:2:true")).hasValue(CelMacro.ALL); - assertThat(parser.findMacro("exists:2:true")).hasValue(CelMacro.EXISTS); - assertThat(parser.findMacro("exists_one:2:true")).hasValue(CelMacro.EXISTS_ONE); - assertThat(parser.findMacro("map:2:true")).hasValue(CelMacro.MAP); - assertThat(parser.findMacro("map:3:true")).hasValue(CelMacro.MAP_FILTER); - assertThat(parser.findMacro("filter:2:true")).hasValue(CelMacro.FILTER); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); + assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); + assertThat(parser.findMacro("exists_one:2:true")) + .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); + assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); + assertThat(parser.findMacro("map:3:true")) + .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); + assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); } @Test @@ -76,28 +81,30 @@ public void build_withStandardMacrosAndCustomMacros_containsAllMacros() { .addMacros(customMacro) .build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); - assertThat(parser.findMacro("all:2:true")).hasValue(CelMacro.ALL); - assertThat(parser.findMacro("exists:2:true")).hasValue(CelMacro.EXISTS); - assertThat(parser.findMacro("exists_one:2:true")).hasValue(CelMacro.EXISTS_ONE); - assertThat(parser.findMacro("map:2:true")).hasValue(CelMacro.MAP); - assertThat(parser.findMacro("map:3:true")).hasValue(CelMacro.MAP_FILTER); - assertThat(parser.findMacro("filter:2:true")).hasValue(CelMacro.FILTER); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); + assertThat(parser.findMacro("all:2:true")).hasValue(CelStandardMacro.ALL.getDefinition()); + assertThat(parser.findMacro("exists:2:true")).hasValue(CelStandardMacro.EXISTS.getDefinition()); + assertThat(parser.findMacro("exists_one:2:true")) + .hasValue(CelStandardMacro.EXISTS_ONE.getDefinition()); + assertThat(parser.findMacro("map:2:true")).hasValue(CelStandardMacro.MAP.getDefinition()); + assertThat(parser.findMacro("map:3:true")) + .hasValue(CelStandardMacro.MAP_FILTER.getDefinition()); + assertThat(parser.findMacro("filter:2:true")).hasValue(CelStandardMacro.FILTER.getDefinition()); assertThat(parser.findMacro("customMacro:1:true")).hasValue(customMacro); } @Test public void build_withMacro_containsMacro() { CelParserImpl parser = - (CelParserImpl) CelParserImpl.newBuilder().addMacros(CelMacro.HAS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); + (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.HAS).build(); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); } @Test public void build_withStandardMacro_containsMacro() { CelParserImpl parser = (CelParserImpl) CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.HAS).build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); } @Test @@ -109,7 +116,7 @@ public void build_withStandardMacro_secondCallReplaces() { .setStandardMacros(CelStandardMacro.HAS) .build(); - assertThat(parser.findMacro("has:1:false")).hasValue(CelMacro.HAS); + assertThat(parser.findMacro("has:1:false")).hasValue(CelStandardMacro.HAS.getDefinition()); assertThat(parser.findMacro("all:2:true")).isEmpty(); } @@ -256,7 +263,8 @@ public void parse_exprUnderMaxRecursionLimit_doesNotThrow( @TestParameters("{expression: 'A.exists_one(a?b, c)'}") @TestParameters("{expression: 'A.filter(a?b, c)'}") public void parse_macroArgumentContainsSyntaxError_throws(String expression) { - CelParser parser = CelParserImpl.newBuilder().addMacros(CelMacro.STANDARD_MACROS).build(); + CelParser parser = + CelParserImpl.newBuilder().setStandardMacros(CelStandardMacro.STANDARD_MACROS).build(); CelValidationResult parseResult = parser.parse(expression); diff --git a/parser/src/test/java/dev/cel/parser/CelStandardMacroTest.java b/parser/src/test/java/dev/cel/parser/CelStandardMacroTest.java index 498c14f0..c06be268 100644 --- a/parser/src/test/java/dev/cel/parser/CelStandardMacroTest.java +++ b/parser/src/test/java/dev/cel/parser/CelStandardMacroTest.java @@ -16,6 +16,7 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.common.testing.EqualsTester; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -34,4 +35,109 @@ public void getFunction() { assertThat(CelStandardMacro.MAP.getFunction()).isEqualTo(Operator.MAP.getFunction()); assertThat(CelStandardMacro.MAP_FILTER.getFunction()).isEqualTo(Operator.MAP.getFunction()); } + + @Test + public void testHas() { + assertThat(CelStandardMacro.HAS.getFunction()).isEqualTo(Operator.HAS.getFunction()); + assertThat(CelStandardMacro.HAS.getDefinition().getArgumentCount()).isEqualTo(1); + assertThat(CelStandardMacro.HAS.getDefinition().isReceiverStyle()).isFalse(); + assertThat(CelStandardMacro.HAS.getDefinition().getKey()).isEqualTo("has:1:false"); + assertThat(CelStandardMacro.HAS.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.HAS.getDefinition().toString()) + .isEqualTo(CelStandardMacro.HAS.getDefinition().getKey()); + assertThat(CelStandardMacro.HAS.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.HAS.getDefinition().getKey().hashCode()); + } + + @Test + public void testAll() { + assertThat(CelStandardMacro.ALL.getFunction()).isEqualTo(Operator.ALL.getFunction()); + assertThat(CelStandardMacro.ALL.getDefinition().getArgumentCount()).isEqualTo(2); + assertThat(CelStandardMacro.ALL.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.ALL.getDefinition().getKey()).isEqualTo("all:2:true"); + assertThat(CelStandardMacro.ALL.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.ALL.getDefinition().toString()) + .isEqualTo(CelStandardMacro.ALL.getDefinition().getKey()); + assertThat(CelStandardMacro.ALL.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.ALL.getDefinition().getKey().hashCode()); + } + + @Test + public void testExists() { + assertThat(CelStandardMacro.EXISTS.getFunction()).isEqualTo(Operator.EXISTS.getFunction()); + assertThat(CelStandardMacro.EXISTS.getDefinition().getArgumentCount()).isEqualTo(2); + assertThat(CelStandardMacro.EXISTS.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.EXISTS.getDefinition().getKey()).isEqualTo("exists:2:true"); + assertThat(CelStandardMacro.EXISTS.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.EXISTS.getDefinition().toString()) + .isEqualTo(CelStandardMacro.EXISTS.getDefinition().getKey()); + assertThat(CelStandardMacro.EXISTS.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.EXISTS.getDefinition().getKey().hashCode()); + } + + @Test + public void testExistsOne() { + assertThat(CelStandardMacro.EXISTS_ONE.getFunction()) + .isEqualTo(Operator.EXISTS_ONE.getFunction()); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().getArgumentCount()).isEqualTo(2); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().getKey()).isEqualTo("exists_one:2:true"); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().toString()) + .isEqualTo(CelStandardMacro.EXISTS_ONE.getDefinition().getKey()); + assertThat(CelStandardMacro.EXISTS_ONE.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.EXISTS_ONE.getDefinition().getKey().hashCode()); + } + + @Test + public void testMap2() { + assertThat(CelStandardMacro.MAP.getFunction()).isEqualTo(Operator.MAP.getFunction()); + assertThat(CelStandardMacro.MAP.getDefinition().getArgumentCount()).isEqualTo(2); + assertThat(CelStandardMacro.MAP.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.MAP.getDefinition().getKey()).isEqualTo("map:2:true"); + assertThat(CelStandardMacro.MAP.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.MAP.getDefinition().toString()) + .isEqualTo(CelStandardMacro.MAP.getDefinition().getKey()); + assertThat(CelStandardMacro.MAP.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.MAP.getDefinition().getKey().hashCode()); + } + + @Test + public void testMap3() { + assertThat(CelStandardMacro.MAP_FILTER.getFunction()).isEqualTo(Operator.MAP.getFunction()); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().getArgumentCount()).isEqualTo(3); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().getKey()).isEqualTo("map:3:true"); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().toString()) + .isEqualTo(CelStandardMacro.MAP_FILTER.getDefinition().getKey()); + assertThat(CelStandardMacro.MAP_FILTER.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.MAP_FILTER.getDefinition().getKey().hashCode()); + } + + @Test + public void testFilter() { + assertThat(CelStandardMacro.FILTER.getFunction()).isEqualTo(Operator.FILTER.getFunction()); + assertThat(CelStandardMacro.FILTER.getDefinition().getArgumentCount()).isEqualTo(2); + assertThat(CelStandardMacro.FILTER.getDefinition().isReceiverStyle()).isTrue(); + assertThat(CelStandardMacro.FILTER.getDefinition().getKey()).isEqualTo("filter:2:true"); + assertThat(CelStandardMacro.FILTER.getDefinition().isVariadic()).isFalse(); + assertThat(CelStandardMacro.FILTER.getDefinition().toString()) + .isEqualTo(CelStandardMacro.FILTER.getDefinition().getKey()); + assertThat(CelStandardMacro.FILTER.getDefinition().hashCode()) + .isEqualTo(CelStandardMacro.FILTER.getDefinition().getKey().hashCode()); + } + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(CelStandardMacro.HAS) + .addEqualityGroup(CelStandardMacro.ALL) + .addEqualityGroup(CelStandardMacro.EXISTS) + .addEqualityGroup(CelStandardMacro.EXISTS_ONE) + .addEqualityGroup(CelStandardMacro.MAP) + .addEqualityGroup(CelStandardMacro.MAP_FILTER) + .addEqualityGroup(CelStandardMacro.FILTER) + .testEquals(); + } } diff --git a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java index d17cdf9a..8eb31256 100644 --- a/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java +++ b/parser/src/test/java/dev/cel/parser/CelUnparserImplTest.java @@ -41,7 +41,7 @@ public final class CelUnparserImplTest { CelParserImpl.newBuilder() .setOptions(CelOptions.newBuilder().populateMacroCalls(true).build()) .addLibraries(CelOptionalLibrary.INSTANCE) - .addMacros(CelMacro.STANDARD_MACROS) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .build(); private final CelUnparserImpl unparser = new CelUnparserImpl(); @@ -249,7 +249,7 @@ public void unparse_comprehensionWithoutMacroCallTracking_presenceTestSucceeds() CelParser parser = CelParserImpl.newBuilder() .setOptions(CelOptions.newBuilder().populateMacroCalls(false).build()) - .addMacros(CelMacro.STANDARD_MACROS) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .build(); CelAbstractSyntaxTree ast = parser.parse("has(hello.world)").getAst(); @@ -261,7 +261,7 @@ public void unparse_comprehensionWithoutMacroCallTracking_throwsException() thro CelParser parser = CelParserImpl.newBuilder() .setOptions(CelOptions.newBuilder().populateMacroCalls(false).build()) - .addMacros(CelMacro.STANDARD_MACROS) + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) .build(); CelAbstractSyntaxTree ast = parser.parse("[1, 2, 3].all(x, x > 0)").getAst();