Skip to content
Open
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 number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ class SimpleConformanceTest {
"math_ext.textproto",
"namespace.textproto",
"network_ext.textproto",
"optionals.textproto",
"parse.textproto",
"plumbing.textproto",
"proto2.textproto",
Expand Down Expand Up @@ -185,12 +186,7 @@ class SimpleConformanceTest {
"enums/strong_proto3/convert_int_too_big",
"enums/strong_proto3/convert_int_too_neg",
"enums/strong_proto3/convert_string",
"enums/strong_proto3/convert_string_bad",
// Optional list/map/message syntax and runtime support is not implemented yet.
"block_ext/basic/optional_list",
"block_ext/basic/optional_map",
"block_ext/basic/optional_map_chained",
"block_ext/basic/optional_message");
"enums/strong_proto3/convert_string_bad");

private static final Set<String> matchedSkips = new LinkedHashSet<>();
private static final AtomicInteger total = new AtomicInteger();
Expand Down Expand Up @@ -353,6 +349,9 @@ private static ParsedExpr parse(SimpleTest test) {
if (usesTestOnlyBlockMacros(test.getExpr())) {
parseOptions.add(macros(Macro.TestOnlyBlockMacros));
}
if (usesOptionals(test.getExpr())) {
parseOptions.add(optionals());
}

Env env = newEnv(parseOptions.toArray(new EnvOption[0]));
AstIssuesTuple astIss = env.parse(sourceText);
Expand Down Expand Up @@ -439,7 +438,7 @@ private static List<EnvOption> conformanceEnvOptions(SimpleTest test, EnvOption.
if (usesNetworkExtensions(test.getExpr())) {
envOptions.add(network());
}
if (test.getExpr().contains("optional.")) {
if (usesOptionals(test.getExpr())) {
envOptions.add(optionals());
}
envOptions.addAll(List.of(options));
Expand All @@ -462,6 +461,13 @@ private static boolean usesStringExtensions(String expression) {
|| expression.contains(".reverse(");
}

private static boolean usesOptionals(String expression) {
return expression.contains("optional.")
|| expression.contains(".?")
|| expression.contains("[?")
|| expression.contains("{?");
}

private static boolean usesNetworkExtensions(String expression) {
return expression.contains("ip(")
|| expression.contains("cidr(")
Expand Down
14 changes: 9 additions & 5 deletions core/src/main/congocc/cel/cel.ccc
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,16 @@ Unary :
Member :
Primary
(
<DOT> Field [<LPAREN> (<RPAREN> | ExprList <RPAREN>)]
| <LBRACKET> Expr <RBRACKET>
<DOT> [<QUESTIONMARK>] Field [<LPAREN> (<RPAREN> | ExprList <RPAREN>)]
| <LBRACKET> [<QUESTIONMARK>] Expr <RBRACKET>
| <LBRACE> [FieldInitializerList] [<COMMA>] <RBRACE>
)*!
;

Primary :
[<DOT>] <IDENTIFIER> [<LPAREN> (<RPAREN> | ExprList <RPAREN>)]
| <LPAREN> Expr <RPAREN>
| <LBRACKET> (<RBRACKET> | ExprList [<COMMA>] <RBRACKET>)
| <LBRACKET> (<RBRACKET> | ListInitializerList [<COMMA>] <RBRACKET>)
| <LBRACE> (<RBRACE> | MapInitializerList [<COMMA>] <RBRACE>)
| ConstantLiteral
;
Expand All @@ -68,8 +68,12 @@ ExprList :
Expr (<COMMA> Expr =>||)*!
;

ListInitializerList :
[<QUESTIONMARK>] Expr (<COMMA> [<QUESTIONMARK>] Expr =>||)*!
;

FieldInitializerList :
Field <COLON> Expr (<COMMA> Field <COLON> Expr =>||)*!
[<QUESTIONMARK>] Field <COLON> Expr (<COMMA> [<QUESTIONMARK>] Field <COLON> Expr =>||)*!
;

Field :
Expand All @@ -78,7 +82,7 @@ Field :
;

MapInitializerList :
Expr <COLON> Expr (<COMMA> Expr <COLON> Expr =>||)*!
[<QUESTIONMARK>] Expr <COLON> Expr (<COMMA> [<QUESTIONMARK>] Expr <COLON> Expr =>||)*!
;

ConstantLiteral :
Expand Down
49 changes: 46 additions & 3 deletions core/src/main/java/org/projectnessie/cel/checker/Checker.java
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,13 @@ void checkSelect(Expr.Builder e) {
resultType = fieldType.type;
}
break;
case kindAbstract:
if (isOptionalType(targetType)) {
resultType = Decls.newAbstractType("optional_type", Collections.singletonList(Decls.Dyn));
} else {
errors.typeDoesNotSupportFieldSelection(location(e), targetType);
}
break;
case kindTypeParam:
// Set the operand type to DYN to prevent assignment to a potentionally incorrect type
// at a later point in type-checking. The isAssignable call will update the type
Expand All @@ -309,6 +316,10 @@ void checkSelect(Expr.Builder e) {
setType(e, resultType);
}

private static boolean isOptionalType(Type type) {
return type.hasAbstractType() && "optional_type".equals(type.getAbstractType().getName());
}

private boolean isQualifiedLocalVariableSelection(Expr.Builder e) {
if (e.getExprKindCase() == Expr.ExprKindCase.IDENT_EXPR) {
return env.hasLocalIdent(e.getIdentExpr().getName());
Expand Down Expand Up @@ -469,10 +480,21 @@ OverloadResolution resolveOverload(
void checkCreateList(Expr.Builder e) {
CreateList.Builder create = e.getListExprBuilder();
Type elemType = null;
boolean[] optionalIndices = new boolean[create.getElementsCount()];
for (int index : create.getOptionalIndicesList()) {
optionalIndices[index] = true;
}
for (int i = 0; i < create.getElementsBuilderList().size(); i++) {
Expr.Builder el = create.getElementsBuilderList().get(i);
check(el);
elemType = joinTypes(location(el), elemType, getType(el));
Type type = getType(el);
if (optionalIndices[i]) {
Type unwrapped = optionalValueType(type);
if (unwrapped != null) {
type = unwrapped;
}
}
elemType = joinTypes(location(el), elemType, type);
}
if (elemType == null) {
// If the list is empty, assign free type var to elem type.
Expand Down Expand Up @@ -501,7 +523,14 @@ void checkCreateMap(Expr.Builder e) {

Expr.Builder val = ent.getValueBuilder();
check(val);
valueType = joinTypes(location(val), valueType, getType(val));
Type type = getType(val);
if (ent.getOptionalEntry()) {
Type unwrapped = optionalValueType(type);
if (unwrapped != null) {
type = unwrapped;
}
}
valueType = joinTypes(location(val), valueType, type);
}
if (keyType == null) {
// If the map is empty, assign free type variables to typeKey and value type.
Expand Down Expand Up @@ -553,12 +582,26 @@ void checkCreateMessage(Expr.Builder e) {
if (t != null) {
fieldType = t.type;
}
if (!isAssignable(fieldType, getType(value))) {
Type valueType = getType(value);
if (ent.getOptionalEntry()) {
Type unwrapped = optionalValueType(valueType);
if (unwrapped != null) {
valueType = unwrapped;
}
}
if (!isAssignable(fieldType, valueType)) {
errors.fieldTypeMismatch(locationByID(ent.getId()), field, fieldType, getType(value));
}
}
}

private static Type optionalValueType(Type type) {
if (!isOptionalType(type) || type.getAbstractType().getParameterTypesCount() == 0) {
return null;
}
return type.getAbstractType().getParameterTypes(0);
}

void checkComprehension(Expr.Builder e) {
Comprehension.Builder comp = e.getComprehensionExprBuilder();
check(comp.getIterRangeBuilder());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public enum Operator {
Modulo("_%_", 3, "%"),
Negate("-_", 2, "-"),
Index("_[_]", 1, null),
OptionalSelect("@optional_select"),
OptionalIndex("@optional_index"),
// Macros, must have a valid identifier.
Has("has"),
All("all"),
Expand Down
Loading
Loading