| // Copyright 2018 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 | |
| // | |
| // http://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 operators defines the internal function names of operators. | |
| // | |
| // All operators in the expression language are modelled as function calls. | |
| package operators | |
| // String "names" for CEL operators. | |
| const ( | |
| // Symbolic operators. | |
| Conditional = "_?_:_" | |
| LogicalAnd = "_&&_" | |
| LogicalOr = "_||_" | |
| LogicalNot = "!_" | |
| Equals = "_==_" | |
| NotEquals = "_!=_" | |
| Less = "_<_" | |
| LessEquals = "_<=_" | |
| Greater = "_>_" | |
| GreaterEquals = "_>=_" | |
| Add = "_+_" | |
| Subtract = "_-_" | |
| Multiply = "_*_" | |
| Divide = "_/_" | |
| Modulo = "_%_" | |
| Negate = "-_" | |
| Index = "_[_]" | |
| OptIndex = "_[?_]" | |
| OptSelect = "_?._" | |
| // Macros, must have a valid identifier. | |
| Has = "has" | |
| All = "all" | |
| Exists = "exists" | |
| ExistsOne = "exists_one" | |
| Map = "map" | |
| Filter = "filter" | |
| // Named operators, must not have be valid identifiers. | |
| NotStrictlyFalse = "@not_strictly_false" | |
| In = "@in" | |
| // Deprecated: named operators with valid identifiers. | |
| OldNotStrictlyFalse = "__not_strictly_false__" | |
| OldIn = "_in_" | |
| ) | |
| var ( | |
| operators = map[string]string{ | |
| "+": Add, | |
| "/": Divide, | |
| "==": Equals, | |
| ">": Greater, | |
| ">=": GreaterEquals, | |
| "in": In, | |
| "<": Less, | |
| "<=": LessEquals, | |
| "%": Modulo, | |
| "*": Multiply, | |
| "!=": NotEquals, | |
| "-": Subtract, | |
| } | |
| // operatorMap of the operator symbol which refers to a struct containing the display name, | |
| // if applicable, the operator precedence, and the arity. | |
| // | |
| // If the symbol does not have a display name listed in the map, it is only because it requires | |
| // special casing to render properly as text. | |
| operatorMap = map[string]struct { | |
| displayName string | |
| precedence int | |
| arity int | |
| }{ | |
| Conditional: {displayName: "", precedence: 8, arity: 3}, | |
| LogicalOr: {displayName: "||", precedence: 7, arity: 2}, | |
| LogicalAnd: {displayName: "&&", precedence: 6, arity: 2}, | |
| Equals: {displayName: "==", precedence: 5, arity: 2}, | |
| Greater: {displayName: ">", precedence: 5, arity: 2}, | |
| GreaterEquals: {displayName: ">=", precedence: 5, arity: 2}, | |
| In: {displayName: "in", precedence: 5, arity: 2}, | |
| Less: {displayName: "<", precedence: 5, arity: 2}, | |
| LessEquals: {displayName: "<=", precedence: 5, arity: 2}, | |
| NotEquals: {displayName: "!=", precedence: 5, arity: 2}, | |
| OldIn: {displayName: "in", precedence: 5, arity: 2}, | |
| Add: {displayName: "+", precedence: 4, arity: 2}, | |
| Subtract: {displayName: "-", precedence: 4, arity: 2}, | |
| Divide: {displayName: "/", precedence: 3, arity: 2}, | |
| Modulo: {displayName: "%", precedence: 3, arity: 2}, | |
| Multiply: {displayName: "*", precedence: 3, arity: 2}, | |
| LogicalNot: {displayName: "!", precedence: 2, arity: 1}, | |
| Negate: {displayName: "-", precedence: 2, arity: 1}, | |
| Index: {displayName: "", precedence: 1, arity: 2}, | |
| OptIndex: {displayName: "", precedence: 1, arity: 2}, | |
| OptSelect: {displayName: "", precedence: 1, arity: 2}, | |
| } | |
| ) | |
| // Find the internal function name for an operator, if the input text is one. | |
| func Find(text string) (string, bool) { | |
| op, found := operators[text] | |
| return op, found | |
| } | |
| // FindReverse returns the unmangled, text representation of the operator. | |
| func FindReverse(symbol string) (string, bool) { | |
| op, found := operatorMap[symbol] | |
| if !found { | |
| return "", false | |
| } | |
| return op.displayName, true | |
| } | |
| // FindReverseBinaryOperator returns the unmangled, text representation of a binary operator. | |
| // | |
| // If the symbol does refer to an operator, but the operator does not have a display name the | |
| // result is false. | |
| func FindReverseBinaryOperator(symbol string) (string, bool) { | |
| op, found := operatorMap[symbol] | |
| if !found || op.arity != 2 { | |
| return "", false | |
| } | |
| if op.displayName == "" { | |
| return "", false | |
| } | |
| return op.displayName, true | |
| } | |
| // Precedence returns the operator precedence, where the higher the number indicates | |
| // higher precedence operations. | |
| func Precedence(symbol string) int { | |
| op, found := operatorMap[symbol] | |
| if !found { | |
| return 0 | |
| } | |
| return op.precedence | |
| } | |
| // Arity returns the number of argument the operator takes | |
| // -1 is returned if an undefined symbol is provided | |
| func Arity(symbol string) int { | |
| op, found := operatorMap[symbol] | |
| if !found { | |
| return -1 | |
| } | |
| return op.arity | |
| } |