| // 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 stdlib contains all of the standard library function declarations and definitions for CEL. | |
| package stdlib | |
| import ( | |
| "fmt" | |
| "math" | |
| "strconv" | |
| "strings" | |
| "time" | |
| "cel.dev/cel-go/common" | |
| "cel.dev/cel-go/common/decls" | |
| "cel.dev/cel-go/common/functions" | |
| "cel.dev/cel-go/common/operators" | |
| "cel.dev/cel-go/common/overloads" | |
| "cel.dev/cel-go/common/types" | |
| "cel.dev/cel-go/common/types/ref" | |
| "cel.dev/cel-go/common/types/traits" | |
| ) | |
| var ( | |
| stdFunctions []*decls.FunctionDecl | |
| stdTypes []*decls.VariableDecl | |
| utcTZ = types.String("UTC") | |
| ) | |
| func init() { | |
| paramA := types.NewTypeParamType("A") | |
| paramB := types.NewTypeParamType("B") | |
| listOfA := types.NewListType(paramA) | |
| mapOfAB := types.NewMapType(paramA, paramB) | |
| stdTypes = []*decls.VariableDecl{ | |
| decls.TypeVariable(types.BoolType), | |
| decls.TypeVariable(types.BytesType), | |
| decls.TypeVariable(types.DoubleType), | |
| decls.TypeVariable(types.DurationType), | |
| decls.TypeVariable(types.IntType), | |
| decls.TypeVariable(listOfA), | |
| decls.TypeVariable(mapOfAB), | |
| decls.TypeVariable(types.NullType), | |
| decls.TypeVariable(types.StringType), | |
| decls.TypeVariable(types.TimestampType), | |
| decls.TypeVariable(types.TypeType), | |
| decls.TypeVariable(types.UintType), | |
| } | |
| stdFunctions = []*decls.FunctionDecl{ | |
| // Logical operators. Special-cased within the interpreter. | |
| // Note, the singleton binding prevents extensions from overriding the operator behavior. | |
| function(operators.Conditional, | |
| decls.FunctionDocs( | |
| `The ternary operator tests a boolean predicate and returns the left-hand side `+ | |
| `(truthy) expression if true, or the right-hand side (falsy) expression if false`), | |
| decls.Overload(overloads.Conditional, argTypes(types.BoolType, paramA, paramA), paramA, | |
| decls.OverloadIsNonStrict(), | |
| decls.OverloadExamples( | |
| `'hello'.contains('lo') ? 'hi' : 'bye' // 'hi'`, | |
| `32 % 3 == 0 ? 'divisible' : 'not divisible' // 'not divisible'`)), | |
| decls.SingletonFunctionBinding(noFunctionOverrides)), | |
| function(operators.LogicalAnd, | |
| decls.FunctionDocs( | |
| `logically AND two boolean values. Errors and unknown values`, | |
| `are valid inputs and will not halt evaluation.`), | |
| decls.Overload(overloads.LogicalAnd, argTypes(types.BoolType, types.BoolType), types.BoolType, | |
| decls.OverloadIsNonStrict(), | |
| decls.OverloadExamples( | |
| `true && true // true`, | |
| `true && false // false`, | |
| `error && true // error`, | |
| `error && false // false`)), | |
| decls.SingletonBinaryBinding(noBinaryOverrides)), | |
| function(operators.LogicalOr, | |
| decls.FunctionDocs( | |
| `logically OR two boolean values. Errors and unknown values`, | |
| `are valid inputs and will not halt evaluation.`), | |
| decls.Overload(overloads.LogicalOr, argTypes(types.BoolType, types.BoolType), types.BoolType, | |
| decls.OverloadIsNonStrict(), | |
| decls.OverloadExamples( | |
| `true || false // true`, | |
| `false || false // false`, | |
| `error || true // true`, | |
| `error || error // true`)), | |
| decls.SingletonBinaryBinding(noBinaryOverrides)), | |
| function(operators.LogicalNot, | |
| decls.FunctionDocs(`logically negate a boolean value.`), | |
| decls.Overload(overloads.LogicalNot, argTypes(types.BoolType), types.BoolType, | |
| decls.OverloadExamples( | |
| `!true // false`, | |
| `!false // true`, | |
| `!error // error`)), | |
| decls.SingletonUnaryBinding(func(val ref.Val) ref.Val { | |
| b, ok := val.(types.Bool) | |
| if !ok { | |
| return types.MaybeNoSuchOverloadErr(val) | |
| } | |
| return b.Negate() | |
| })), | |
| // Comprehension short-circuiting related function | |
| function(operators.NotStrictlyFalse, | |
| decls.Overload(overloads.NotStrictlyFalse, argTypes(types.BoolType), types.BoolType, | |
| decls.OverloadIsNonStrict(), | |
| decls.UnaryBinding(notStrictlyFalse))), | |
| // Deprecated: __not_strictly_false__ | |
| function(operators.OldNotStrictlyFalse, | |
| decls.DisableDeclaration(true), // safe deprecation | |
| decls.Overload(operators.OldNotStrictlyFalse, argTypes(types.BoolType), types.BoolType, | |
| decls.OverloadIsNonStrict(), | |
| decls.UnaryBinding(notStrictlyFalse))), | |
| // Equality / inequality. Special-cased in the interpreter | |
| function(operators.Equals, | |
| decls.FunctionDocs(`compare two values of the same type for equality`), | |
| decls.Overload(overloads.Equals, argTypes(paramA, paramA), types.BoolType, | |
| decls.OverloadExamples( | |
| `1 == 1 // true`, | |
| `'hello' == 'world' // false`, | |
| `bytes('hello') == b'hello' // true`, | |
| `duration('1h') == duration('60m') // true`, | |
| `dyn(3.0) == 3 // true`)), | |
| decls.SingletonBinaryBinding(noBinaryOverrides)), | |
| function(operators.NotEquals, | |
| decls.FunctionDocs(`compare two values of the same type for inequality`), | |
| decls.Overload(overloads.NotEquals, argTypes(paramA, paramA), types.BoolType, | |
| decls.OverloadExamples( | |
| `1 != 2 // true`, | |
| `"a" != "a" // false`, | |
| `3.0 != 3.1 // true`)), | |
| decls.SingletonBinaryBinding(noBinaryOverrides)), | |
| // Mathematical operators | |
| function(operators.Add, | |
| decls.FunctionDocs( | |
| `adds two numeric values or concatenates two strings, bytes,`, | |
| `or lists.`), | |
| decls.Overload(overloads.AddBytes, | |
| argTypes(types.BytesType, types.BytesType), types.BytesType, | |
| decls.OverloadExamples(`b'hi' + bytes('ya') // b'hiya'`)), | |
| decls.Overload(overloads.AddDouble, | |
| argTypes(types.DoubleType, types.DoubleType), types.DoubleType, | |
| decls.OverloadExamples(`3.14 + 1.59 // 4.73`)), | |
| decls.Overload(overloads.AddDurationDuration, | |
| argTypes(types.DurationType, types.DurationType), types.DurationType, | |
| decls.OverloadExamples(`duration('1m') + duration('1s') // duration('1m1s')`)), | |
| decls.Overload(overloads.AddDurationTimestamp, | |
| argTypes(types.DurationType, types.TimestampType), types.TimestampType, | |
| decls.OverloadExamples(`duration('24h') + timestamp('2023-01-01T00:00:00Z') // timestamp('2023-01-02T00:00:00Z')`)), | |
| decls.Overload(overloads.AddTimestampDuration, | |
| argTypes(types.TimestampType, types.DurationType), types.TimestampType, | |
| decls.OverloadExamples(`timestamp('2023-01-01T00:00:00Z') + duration('24h1m2s') // timestamp('2023-01-02T00:01:02Z')`)), | |
| decls.Overload(overloads.AddInt64, | |
| argTypes(types.IntType, types.IntType), types.IntType, | |
| decls.OverloadExamples(`1 + 2 // 3`)), | |
| decls.Overload(overloads.AddList, | |
| argTypes(listOfA, listOfA), listOfA, | |
| decls.OverloadExamples(`[1] + [2, 3] // [1, 2, 3]`)), | |
| decls.Overload(overloads.AddString, | |
| argTypes(types.StringType, types.StringType), types.StringType, | |
| decls.OverloadExamples(`"Hello, " + "world!" // "Hello, world!"`)), | |
| decls.Overload(overloads.AddUint64, | |
| argTypes(types.UintType, types.UintType), types.UintType, | |
| decls.OverloadExamples(`22u + 33u // 55u`)), | |
| decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val { | |
| return lhs.(traits.Adder).Add(rhs) | |
| }, traits.AdderType)), | |
| function(operators.Divide, | |
| decls.FunctionDocs(`divide two numbers`), | |
| decls.Overload(overloads.DivideDouble, | |
| argTypes(types.DoubleType, types.DoubleType), types.DoubleType, | |
| decls.OverloadExamples(`7.0 / 2.0 // 3.5`)), | |
| decls.Overload(overloads.DivideInt64, | |
| argTypes(types.IntType, types.IntType), types.IntType, | |
| decls.OverloadExamples(`10 / 2 // 5`)), | |
| decls.Overload(overloads.DivideUint64, | |
| argTypes(types.UintType, types.UintType), types.UintType, | |
| decls.OverloadExamples(`42u / 2u // 21u`)), | |
| decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val { | |
| return lhs.(traits.Divider).Divide(rhs) | |
| }, traits.DividerType)), | |
| function(operators.Modulo, | |
| decls.FunctionDocs(`compute the modulus of one integer into another`), | |
| decls.Overload(overloads.ModuloInt64, | |
| argTypes(types.IntType, types.IntType), types.IntType, | |
| decls.OverloadExamples(`3 % 2 // 1`)), | |
| decls.Overload(overloads.ModuloUint64, | |
| argTypes(types.UintType, types.UintType), types.UintType, | |
| decls.OverloadExamples(`6u % 3u // 0u`)), | |
| decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val { | |
| return lhs.(traits.Modder).Modulo(rhs) | |
| }, traits.ModderType)), | |
| function(operators.Multiply, | |
| decls.FunctionDocs(`multiply two numbers`), | |
| decls.Overload(overloads.MultiplyDouble, | |
| argTypes(types.DoubleType, types.DoubleType), types.DoubleType, | |
| decls.OverloadExamples(`3.5 * 40.0 // 140.0`)), | |
| decls.Overload(overloads.MultiplyInt64, | |
| argTypes(types.IntType, types.IntType), types.IntType, | |
| decls.OverloadExamples(`-2 * 6 // -12`)), | |
| decls.Overload(overloads.MultiplyUint64, | |
| argTypes(types.UintType, types.UintType), types.UintType, | |
| decls.OverloadExamples(`13u * 3u // 39u`)), | |
| decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val { | |
| return lhs.(traits.Multiplier).Multiply(rhs) | |
| }, traits.MultiplierType)), | |
| function(operators.Negate, | |
| decls.FunctionDocs(`negate a numeric value`), | |
| decls.Overload(overloads.NegateDouble, argTypes(types.DoubleType), types.DoubleType, | |
| decls.OverloadExamples(`-(3.14) // -3.14`)), | |
| decls.Overload(overloads.NegateInt64, argTypes(types.IntType), types.IntType, | |
| decls.OverloadExamples(`-(5) // -5`)), | |
| decls.SingletonUnaryBinding(func(val ref.Val) ref.Val { | |
| if types.IsBool(val) { | |
| return types.MaybeNoSuchOverloadErr(val) | |
| } | |
| return val.(traits.Negater).Negate() | |
| }, traits.NegatorType)), | |
| function(operators.Subtract, | |
| decls.FunctionDocs(`subtract two numbers, or two time-related values`), | |
| decls.Overload(overloads.SubtractDouble, | |
| argTypes(types.DoubleType, types.DoubleType), types.DoubleType, | |
| decls.OverloadExamples(`10.5 - 2.0 // 8.5`)), | |
| decls.Overload(overloads.SubtractDurationDuration, | |
| argTypes(types.DurationType, types.DurationType), types.DurationType, | |
| decls.OverloadExamples(`duration('1m') - duration('1s') // duration('59s')`)), | |
| decls.Overload(overloads.SubtractInt64, | |
| argTypes(types.IntType, types.IntType), types.IntType, | |
| decls.OverloadExamples(`5 - 3 // 2`)), | |
| decls.Overload(overloads.SubtractTimestampDuration, | |
| argTypes(types.TimestampType, types.DurationType), types.TimestampType, | |
| decls.OverloadExamples(common.MultilineDescription( | |
| `timestamp('2023-01-10T12:00:00Z')`, | |
| ` - duration('12h') // timestamp('2023-01-10T00:00:00Z')`))), | |
| decls.Overload(overloads.SubtractTimestampTimestamp, | |
| argTypes(types.TimestampType, types.TimestampType), types.DurationType, | |
| decls.OverloadExamples(common.MultilineDescription( | |
| `timestamp('2023-01-10T12:00:00Z')`, | |
| ` - timestamp('2023-01-10T00:00:00Z') // duration('12h')`))), | |
| decls.Overload(overloads.SubtractUint64, | |
| argTypes(types.UintType, types.UintType), types.UintType, | |
| decls.OverloadExamples(common.MultilineDescription( | |
| `// the subtraction result must be positive, otherwise an overflow`, | |
| `// error is generated.`, | |
| `42u - 3u // 39u`))), | |
| decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val { | |
| return lhs.(traits.Subtractor).Subtract(rhs) | |
| }, traits.SubtractorType)), | |
| // Relations operators | |
| function(operators.Less, | |
| decls.FunctionDocs( | |
| `compare two values and return true if the first value is`, | |
| `less than the second`), | |
| decls.Overload(overloads.LessBool, | |
| argTypes(types.BoolType, types.BoolType), types.BoolType, | |
| decls.OverloadExamples(`false < true // true`)), | |
| decls.Overload(overloads.LessInt64, | |
| argTypes(types.IntType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`-2 < 3 // true`, `1 < 0 // false`)), | |
| decls.Overload(overloads.LessInt64Double, | |
| argTypes(types.IntType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`1 < 1.1 // true`)), | |
| decls.Overload(overloads.LessInt64Uint64, | |
| argTypes(types.IntType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`1 < 2u // true`)), | |
| decls.Overload(overloads.LessUint64, | |
| argTypes(types.UintType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`1u < 2u // true`)), | |
| decls.Overload(overloads.LessUint64Double, | |
| argTypes(types.UintType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`1u < 0.9 // false`)), | |
| decls.Overload(overloads.LessUint64Int64, | |
| argTypes(types.UintType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`1u < 23 // true`, `1u < -1 // false`)), | |
| decls.Overload(overloads.LessDouble, | |
| argTypes(types.DoubleType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`2.0 < 2.4 // true`)), | |
| decls.Overload(overloads.LessDoubleInt64, | |
| argTypes(types.DoubleType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`2.1 < 3 // true`)), | |
| decls.Overload(overloads.LessDoubleUint64, | |
| argTypes(types.DoubleType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`2.3 < 2u // false`, `-1.0 < 1u // true`)), | |
| decls.Overload(overloads.LessString, | |
| argTypes(types.StringType, types.StringType), types.BoolType, | |
| decls.OverloadExamples(`'a' < 'b' // true`, `'cat' < 'cab' // false`)), | |
| decls.Overload(overloads.LessBytes, | |
| argTypes(types.BytesType, types.BytesType), types.BoolType, | |
| decls.OverloadExamples(`b'hello' < b'world' // true`)), | |
| decls.Overload(overloads.LessTimestamp, | |
| argTypes(types.TimestampType, types.TimestampType), types.BoolType, | |
| decls.OverloadExamples(`timestamp('2001-01-01T02:03:04Z') < timestamp('2002-02-02T02:03:04Z') // true`)), | |
| decls.Overload(overloads.LessDuration, | |
| argTypes(types.DurationType, types.DurationType), types.BoolType, | |
| decls.OverloadExamples(`duration('1ms') < duration('1s') // true`)), | |
| decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val { | |
| if isNaN(lhs) || isNaN(rhs) { | |
| return types.False | |
| } | |
| cmp := lhs.(traits.Comparer).Compare(rhs) | |
| if cmp == types.IntNegOne { | |
| return types.True | |
| } | |
| if cmp == types.IntOne || cmp == types.IntZero { | |
| return types.False | |
| } | |
| return cmp | |
| }, traits.ComparerType)), | |
| function(operators.LessEquals, | |
| decls.FunctionDocs( | |
| `compare two values and return true if the first value is`, | |
| `less than or equal to the second`), | |
| decls.Overload(overloads.LessEqualsBool, | |
| argTypes(types.BoolType, types.BoolType), types.BoolType, | |
| decls.OverloadExamples(`false <= true // true`)), | |
| decls.Overload(overloads.LessEqualsInt64, | |
| argTypes(types.IntType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`-2 <= 3 // true`)), | |
| decls.Overload(overloads.LessEqualsInt64Double, | |
| argTypes(types.IntType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`1 <= 1.1 // true`)), | |
| decls.Overload(overloads.LessEqualsInt64Uint64, | |
| argTypes(types.IntType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`1 <= 2u // true`, `-1 <= 0u // true`)), | |
| decls.Overload(overloads.LessEqualsUint64, | |
| argTypes(types.UintType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`1u <= 2u // true`)), | |
| decls.Overload(overloads.LessEqualsUint64Double, | |
| argTypes(types.UintType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`1u <= 1.0 // true`, `1u <= 1.1 // true`)), | |
| decls.Overload(overloads.LessEqualsUint64Int64, | |
| argTypes(types.UintType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`1u <= 23 // true`)), | |
| decls.Overload(overloads.LessEqualsDouble, | |
| argTypes(types.DoubleType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`2.0 <= 2.4 // true`)), | |
| decls.Overload(overloads.LessEqualsDoubleInt64, | |
| argTypes(types.DoubleType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`2.1 <= 3 // true`)), | |
| decls.Overload(overloads.LessEqualsDoubleUint64, | |
| argTypes(types.DoubleType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`2.0 <= 2u // true`, `-1.0 <= 1u // true`)), | |
| decls.Overload(overloads.LessEqualsString, | |
| argTypes(types.StringType, types.StringType), types.BoolType, | |
| decls.OverloadExamples(`'a' <= 'b' // true`, `'a' <= 'a' // true`, `'cat' <= 'cab' // false`)), | |
| decls.Overload(overloads.LessEqualsBytes, | |
| argTypes(types.BytesType, types.BytesType), types.BoolType, | |
| decls.OverloadExamples(`b'hello' <= b'world' // true`)), | |
| decls.Overload(overloads.LessEqualsTimestamp, | |
| argTypes(types.TimestampType, types.TimestampType), types.BoolType, | |
| decls.OverloadExamples(`timestamp('2001-01-01T02:03:04Z') <= timestamp('2002-02-02T02:03:04Z') // true`)), | |
| decls.Overload(overloads.LessEqualsDuration, | |
| argTypes(types.DurationType, types.DurationType), types.BoolType, | |
| decls.OverloadExamples(`duration('1ms') <= duration('1s') // true`)), | |
| decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val { | |
| if isNaN(lhs) || isNaN(rhs) { | |
| return types.False | |
| } | |
| cmp := lhs.(traits.Comparer).Compare(rhs) | |
| if cmp == types.IntNegOne || cmp == types.IntZero { | |
| return types.True | |
| } | |
| if cmp == types.IntOne { | |
| return types.False | |
| } | |
| return cmp | |
| }, traits.ComparerType)), | |
| function(operators.Greater, | |
| decls.FunctionDocs( | |
| `compare two values and return true if the first value is`, | |
| `greater than the second`), | |
| decls.Overload(overloads.GreaterBool, | |
| argTypes(types.BoolType, types.BoolType), types.BoolType, | |
| decls.OverloadExamples(`true > false // true`)), | |
| decls.Overload(overloads.GreaterInt64, | |
| argTypes(types.IntType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`3 > -2 // true`)), | |
| decls.Overload(overloads.GreaterInt64Double, | |
| argTypes(types.IntType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`2 > 1.1 // true`)), | |
| decls.Overload(overloads.GreaterInt64Uint64, | |
| argTypes(types.IntType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`3 > 2u // true`)), | |
| decls.Overload(overloads.GreaterUint64, | |
| argTypes(types.UintType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`2u > 1u // true`)), | |
| decls.Overload(overloads.GreaterUint64Double, | |
| argTypes(types.UintType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`2u > 1.9 // true`)), | |
| decls.Overload(overloads.GreaterUint64Int64, | |
| argTypes(types.UintType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`23u > 1 // true`, `0u > -1 // true`)), | |
| decls.Overload(overloads.GreaterDouble, | |
| argTypes(types.DoubleType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`2.4 > 2.0 // true`)), | |
| decls.Overload(overloads.GreaterDoubleInt64, | |
| argTypes(types.DoubleType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`3.1 > 3 // true`, `3.0 > 3 // false`)), | |
| decls.Overload(overloads.GreaterDoubleUint64, | |
| argTypes(types.DoubleType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`2.3 > 2u // true`)), | |
| decls.Overload(overloads.GreaterString, | |
| argTypes(types.StringType, types.StringType), types.BoolType, | |
| decls.OverloadExamples(`'b' > 'a' // true`)), | |
| decls.Overload(overloads.GreaterBytes, | |
| argTypes(types.BytesType, types.BytesType), types.BoolType, | |
| decls.OverloadExamples(`b'world' > b'hello' // true`)), | |
| decls.Overload(overloads.GreaterTimestamp, | |
| argTypes(types.TimestampType, types.TimestampType), types.BoolType, | |
| decls.OverloadExamples(`timestamp('2002-02-02T02:03:04Z') > timestamp('2001-01-01T02:03:04Z') // true`)), | |
| decls.Overload(overloads.GreaterDuration, | |
| argTypes(types.DurationType, types.DurationType), types.BoolType, | |
| decls.OverloadExamples(`duration('1ms') > duration('1us') // true`)), | |
| decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val { | |
| if isNaN(lhs) || isNaN(rhs) { | |
| return types.False | |
| } | |
| cmp := lhs.(traits.Comparer).Compare(rhs) | |
| if cmp == types.IntOne { | |
| return types.True | |
| } | |
| if cmp == types.IntNegOne || cmp == types.IntZero { | |
| return types.False | |
| } | |
| return cmp | |
| }, traits.ComparerType)), | |
| function(operators.GreaterEquals, | |
| decls.FunctionDocs( | |
| `compare two values and return true if the first value is`, | |
| `greater than or equal to the second`), | |
| decls.Overload(overloads.GreaterEqualsBool, | |
| argTypes(types.BoolType, types.BoolType), types.BoolType, | |
| decls.OverloadExamples(`true >= false // true`)), | |
| decls.Overload(overloads.GreaterEqualsInt64, | |
| argTypes(types.IntType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`3 >= -2 // true`)), | |
| decls.Overload(overloads.GreaterEqualsInt64Double, | |
| argTypes(types.IntType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`2 >= 1.1 // true`, `1 >= 1.0 // true`)), | |
| decls.Overload(overloads.GreaterEqualsInt64Uint64, | |
| argTypes(types.IntType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`3 >= 2u // true`)), | |
| decls.Overload(overloads.GreaterEqualsUint64, | |
| argTypes(types.UintType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`2u >= 1u // true`)), | |
| decls.Overload(overloads.GreaterEqualsUint64Double, | |
| argTypes(types.UintType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`2u >= 1.9 // true`)), | |
| decls.Overload(overloads.GreaterEqualsUint64Int64, | |
| argTypes(types.UintType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`23u >= 1 // true`, `1u >= 1 // true`)), | |
| decls.Overload(overloads.GreaterEqualsDouble, | |
| argTypes(types.DoubleType, types.DoubleType), types.BoolType, | |
| decls.OverloadExamples(`2.4 >= 2.0 // true`)), | |
| decls.Overload(overloads.GreaterEqualsDoubleInt64, | |
| argTypes(types.DoubleType, types.IntType), types.BoolType, | |
| decls.OverloadExamples(`3.1 >= 3 // true`)), | |
| decls.Overload(overloads.GreaterEqualsDoubleUint64, | |
| argTypes(types.DoubleType, types.UintType), types.BoolType, | |
| decls.OverloadExamples(`2.3 >= 2u // true`)), | |
| decls.Overload(overloads.GreaterEqualsString, | |
| argTypes(types.StringType, types.StringType), types.BoolType, | |
| decls.OverloadExamples(`'b' >= 'a' // true`)), | |
| decls.Overload(overloads.GreaterEqualsBytes, | |
| argTypes(types.BytesType, types.BytesType), types.BoolType, | |
| decls.OverloadExamples(`b'world' >= b'hello' // true`)), | |
| decls.Overload(overloads.GreaterEqualsTimestamp, | |
| argTypes(types.TimestampType, types.TimestampType), types.BoolType, | |
| decls.OverloadExamples(`timestamp('2001-01-01T02:03:04Z') >= timestamp('2001-01-01T02:03:04Z') // true`)), | |
| decls.Overload(overloads.GreaterEqualsDuration, | |
| argTypes(types.DurationType, types.DurationType), types.BoolType, | |
| decls.OverloadExamples(`duration('60s') >= duration('1m') // true`)), | |
| decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val { | |
| if isNaN(lhs) || isNaN(rhs) { | |
| return types.False | |
| } | |
| cmp := lhs.(traits.Comparer).Compare(rhs) | |
| if cmp == types.IntOne || cmp == types.IntZero { | |
| return types.True | |
| } | |
| if cmp == types.IntNegOne { | |
| return types.False | |
| } | |
| return cmp | |
| }, traits.ComparerType)), | |
| // Indexing | |
| function(operators.Index, | |
| decls.FunctionDocs(`select a value from a list by index, or value from a map by key`), | |
| decls.Overload(overloads.IndexList, argTypes(listOfA, types.IntType), paramA, | |
| decls.OverloadExamples(`[1, 2, 3][1] // 2`)), | |
| decls.Overload(overloads.IndexMap, argTypes(mapOfAB, paramA), paramB, | |
| decls.OverloadExamples( | |
| `{'key': 'value'}['key'] // 'value'`, | |
| `{'key': 'value'}['missing'] // error`)), | |
| decls.SingletonBinaryBinding(func(lhs, rhs ref.Val) ref.Val { | |
| return lhs.(traits.Indexer).Get(rhs) | |
| }, traits.IndexerType)), | |
| // Collections operators | |
| function(operators.In, | |
| decls.FunctionDocs(`test whether a value exists in a list, or a key exists in a map`), | |
| decls.Overload(overloads.InList, argTypes(paramA, listOfA), types.BoolType, | |
| decls.OverloadExamples( | |
| `2 in [1, 2, 3] // true`, | |
| `"a" in ["b", "c"] // false`)), | |
| decls.Overload(overloads.InMap, argTypes(paramA, mapOfAB), types.BoolType, | |
| decls.OverloadExamples( | |
| `'key1' in {'key1': 'value1', 'key2': 'value2'} // true`, | |
| `3 in {1: "one", 2: "two"} // false`)), | |
| decls.SingletonBinaryBinding(inAggregate)), | |
| function(operators.OldIn, | |
| decls.DisableDeclaration(true), // safe deprecation | |
| decls.Overload(overloads.InList, argTypes(paramA, listOfA), types.BoolType), | |
| decls.Overload(overloads.InMap, argTypes(paramA, mapOfAB), types.BoolType), | |
| decls.SingletonBinaryBinding(inAggregate)), | |
| function(overloads.DeprecatedIn, | |
| decls.DisableDeclaration(true), // safe deprecation | |
| decls.Overload(overloads.InList, argTypes(paramA, listOfA), types.BoolType), | |
| decls.Overload(overloads.InMap, argTypes(paramA, mapOfAB), types.BoolType), | |
| decls.SingletonBinaryBinding(inAggregate)), | |
| function(overloads.Size, | |
| decls.FunctionDocs( | |
| `compute the size of a list or map, the number of characters in a string,`, | |
| `or the number of bytes in a sequence`), | |
| decls.Overload(overloads.SizeBytes, argTypes(types.BytesType), types.IntType, | |
| decls.OverloadExamples(`size(b'123') // 3`)), | |
| decls.MemberOverload(overloads.SizeBytesInst, argTypes(types.BytesType), types.IntType, | |
| decls.OverloadExamples(`b'123'.size() // 3`)), | |
| decls.Overload(overloads.SizeList, argTypes(listOfA), types.IntType, | |
| decls.OverloadExamples(`size([1, 2, 3]) // 3`)), | |
| decls.MemberOverload(overloads.SizeListInst, argTypes(listOfA), types.IntType, | |
| decls.OverloadExamples(`[1, 2, 3].size() // 3`)), | |
| decls.Overload(overloads.SizeMap, argTypes(mapOfAB), types.IntType, | |
| decls.OverloadExamples(`size({'a': 1, 'b': 2}) // 2`)), | |
| decls.MemberOverload(overloads.SizeMapInst, argTypes(mapOfAB), types.IntType, | |
| decls.OverloadExamples(`{'a': 1, 'b': 2}.size() // 2`)), | |
| decls.Overload(overloads.SizeString, argTypes(types.StringType), types.IntType, | |
| decls.OverloadExamples(`size('hello') // 5`)), | |
| decls.MemberOverload(overloads.SizeStringInst, argTypes(types.StringType), types.IntType, | |
| decls.OverloadExamples(`'hello'.size() // 5`)), | |
| decls.SingletonUnaryBinding(func(val ref.Val) ref.Val { | |
| return val.(traits.Sizer).Size() | |
| }, traits.SizerType)), | |
| // Type conversions | |
| function(overloads.TypeConvertType, | |
| decls.FunctionDocs(`convert a value to its type identifier`), | |
| decls.Overload(overloads.TypeConvertType, argTypes(paramA), types.NewTypeTypeWithParam(paramA), | |
| decls.OverloadExamples( | |
| `type(1) // int`, | |
| `type('hello') // string`, | |
| `type(int) // type`, | |
| `type(type) // type`)), | |
| decls.SingletonUnaryBinding(convertToType(types.TypeType))), | |
| // Bool conversions | |
| function(overloads.TypeConvertBool, | |
| decls.FunctionDocs(`convert a value to a boolean`), | |
| decls.Overload(overloads.BoolToBool, argTypes(types.BoolType), types.BoolType, | |
| decls.OverloadExamples(`bool(true) // true`), | |
| decls.UnaryBinding(identity)), | |
| decls.Overload(overloads.StringToBool, argTypes(types.StringType), types.BoolType, | |
| decls.OverloadExamples(`bool('true') // true`, `bool('false') // false`), | |
| decls.UnaryBinding(convertToType(types.BoolType)))), | |
| // Bytes conversions | |
| function(overloads.TypeConvertBytes, | |
| decls.FunctionDocs(`convert a value to bytes`), | |
| decls.Overload(overloads.BytesToBytes, argTypes(types.BytesType), types.BytesType, | |
| decls.OverloadExamples(`bytes(b'abc') // b'abc'`), | |
| decls.UnaryBinding(identity)), | |
| decls.Overload(overloads.StringToBytes, argTypes(types.StringType), types.BytesType, | |
| decls.OverloadExamples(`bytes('hello') // b'hello'`), | |
| decls.UnaryBinding(convertToType(types.BytesType)))), | |
| // Double conversions | |
| function(overloads.TypeConvertDouble, | |
| decls.FunctionDocs(`convert a value to a double`), | |
| decls.Overload(overloads.DoubleToDouble, argTypes(types.DoubleType), types.DoubleType, | |
| decls.OverloadExamples(`double(1.23) // 1.23`), | |
| decls.UnaryBinding(identity)), | |
| decls.Overload(overloads.IntToDouble, argTypes(types.IntType), types.DoubleType, | |
| decls.OverloadExamples(`double(123) // 123.0`), | |
| decls.UnaryBinding(convertToType(types.DoubleType))), | |
| decls.Overload(overloads.StringToDouble, argTypes(types.StringType), types.DoubleType, | |
| decls.OverloadExamples(`double('1.23') // 1.23`), | |
| decls.UnaryBinding(convertToType(types.DoubleType))), | |
| decls.Overload(overloads.UintToDouble, argTypes(types.UintType), types.DoubleType, | |
| decls.OverloadExamples(`double(123u) // 123.0`), | |
| decls.UnaryBinding(convertToType(types.DoubleType)))), | |
| // Duration conversions | |
| function(overloads.TypeConvertDuration, | |
| decls.FunctionDocs(`convert a value to a google.protobuf.Duration`), | |
| decls.Overload(overloads.DurationToDuration, argTypes(types.DurationType), types.DurationType, | |
| decls.OverloadExamples(`duration(duration('1s')) // duration('1s')`), | |
| decls.UnaryBinding(identity)), | |
| decls.Overload(overloads.StringToDuration, argTypes(types.StringType), types.DurationType, | |
| decls.OverloadExamples(`duration('1h2m3s') // duration('3723s')`), | |
| decls.UnaryBinding(convertToType(types.DurationType)))), | |
| // Dyn conversions | |
| function(overloads.TypeConvertDyn, | |
| decls.FunctionDocs(`indicate that the type is dynamic for type-checking purposes`), | |
| decls.Overload(overloads.ToDyn, argTypes(paramA), types.DynType, | |
| decls.OverloadExamples(`dyn(1) // 1`)), | |
| decls.SingletonUnaryBinding(identity)), | |
| // Int conversions | |
| function(overloads.TypeConvertInt, | |
| decls.FunctionDocs(`convert a value to an int`), | |
| decls.Overload(overloads.IntToInt, argTypes(types.IntType), types.IntType, | |
| decls.OverloadExamples(`int(123) // 123`), | |
| decls.UnaryBinding(identity)), | |
| decls.Overload(overloads.DoubleToInt, argTypes(types.DoubleType), types.IntType, | |
| decls.OverloadExamples(`int(123.45) // 123`), | |
| decls.UnaryBinding(convertToType(types.IntType))), | |
| decls.Overload(overloads.DurationToInt, argTypes(types.DurationType), types.IntType, | |
| decls.OverloadExamples(`int(duration('1s')) // 1000000000`), | |
| decls.UnaryBinding(convertToType(types.IntType))), // Duration to nanoseconds | |
| decls.Overload(overloads.StringToInt, argTypes(types.StringType), types.IntType, | |
| decls.OverloadExamples(`int('123') // 123`, `int('-456') // -456`), | |
| decls.UnaryBinding(convertToType(types.IntType))), | |
| decls.Overload(overloads.TimestampToInt, argTypes(types.TimestampType), types.IntType, | |
| decls.OverloadExamples(`int(timestamp('1970-01-01T00:00:01Z')) // 1`), | |
| decls.UnaryBinding(convertToType(types.IntType))), // Timestamp to epoch seconds | |
| decls.Overload(overloads.UintToInt, argTypes(types.UintType), types.IntType, | |
| decls.OverloadExamples(`int(123u) // 123`), | |
| decls.UnaryBinding(convertToType(types.IntType)))), | |
| // String conversions | |
| function(overloads.TypeConvertString, | |
| decls.FunctionDocs(`convert a value to a string`), | |
| decls.Overload(overloads.StringToString, argTypes(types.StringType), types.StringType, | |
| decls.OverloadExamples(`string('hello') // 'hello'`), | |
| decls.UnaryBinding(identity)), | |
| decls.Overload(overloads.BoolToString, argTypes(types.BoolType), types.StringType, | |
| decls.OverloadExamples(`string(true) // 'true'`), | |
| decls.UnaryBinding(convertToType(types.StringType))), | |
| decls.Overload(overloads.BytesToString, argTypes(types.BytesType), types.StringType, | |
| decls.OverloadExamples(`string(b'hello') // 'hello'`), | |
| decls.UnaryBinding(convertToType(types.StringType))), | |
| decls.Overload(overloads.DoubleToString, argTypes(types.DoubleType), types.StringType, | |
| decls.UnaryBinding(convertToType(types.StringType)), | |
| decls.OverloadExamples(`string(-1.23e4) // '-12300'`)), | |
| decls.Overload(overloads.DurationToString, argTypes(types.DurationType), types.StringType, | |
| decls.OverloadExamples(`string(duration('1h30m')) // '5400s'`), | |
| decls.UnaryBinding(convertToType(types.StringType))), | |
| decls.Overload(overloads.IntToString, argTypes(types.IntType), types.StringType, | |
| decls.OverloadExamples(`string(-123) // '-123'`), | |
| decls.UnaryBinding(convertToType(types.StringType))), | |
| decls.Overload(overloads.TimestampToString, argTypes(types.TimestampType), types.StringType, | |
| decls.OverloadExamples(`string(timestamp('1970-01-01T00:00:00Z')) // '1970-01-01T00:00:00Z'`), | |
| decls.UnaryBinding(convertToType(types.StringType))), | |
| decls.Overload(overloads.UintToString, argTypes(types.UintType), types.StringType, | |
| decls.OverloadExamples(`string(123u) // '123'`), | |
| decls.UnaryBinding(convertToType(types.StringType)))), | |
| // Timestamp conversions | |
| function(overloads.TypeConvertTimestamp, | |
| decls.FunctionDocs(`convert a value to a google.protobuf.Timestamp`), | |
| decls.Overload(overloads.TimestampToTimestamp, argTypes(types.TimestampType), types.TimestampType, | |
| decls.OverloadExamples(`timestamp(timestamp('2023-01-01T00:00:00Z')) // timestamp('2023-01-01T00:00:00Z')`), | |
| decls.UnaryBinding(identity)), | |
| decls.Overload(overloads.IntToTimestamp, argTypes(types.IntType), types.TimestampType, | |
| decls.OverloadExamples(`timestamp(1) // timestamp('1970-01-01T00:00:01Z')`), // Epoch seconds to Timestamp | |
| decls.UnaryBinding(convertToType(types.TimestampType))), | |
| decls.Overload(overloads.StringToTimestamp, argTypes(types.StringType), types.TimestampType, | |
| decls.OverloadExamples(`timestamp('2025-01-01T12:34:56Z') // timestamp('2025-01-01T12:34:56Z')`), | |
| decls.UnaryBinding(convertToType(types.TimestampType)))), | |
| // Uint conversions | |
| function(overloads.TypeConvertUint, | |
| decls.FunctionDocs(`convert a value to a uint`), | |
| decls.Overload(overloads.UintToUint, argTypes(types.UintType), types.UintType, | |
| decls.OverloadExamples(`uint(123u) // 123u`), | |
| decls.UnaryBinding(identity)), | |
| decls.Overload(overloads.DoubleToUint, argTypes(types.DoubleType), types.UintType, | |
| decls.OverloadExamples(`uint(123.45) // 123u`), | |
| decls.UnaryBinding(convertToType(types.UintType))), | |
| decls.Overload(overloads.IntToUint, argTypes(types.IntType), types.UintType, | |
| decls.OverloadExamples(`uint(123) // 123u`), | |
| decls.UnaryBinding(convertToType(types.UintType))), | |
| decls.Overload(overloads.StringToUint, argTypes(types.StringType), types.UintType, | |
| decls.OverloadExamples(`uint('123') // 123u`), | |
| decls.UnaryBinding(convertToType(types.UintType)))), | |
| // String functions | |
| function(overloads.Contains, | |
| decls.FunctionDocs(`test whether a string contains a substring`), | |
| decls.MemberOverload(overloads.ContainsString, | |
| argTypes(types.StringType, types.StringType), types.BoolType, | |
| decls.OverloadExamples( | |
| `'hello world'.contains('o w') // true`, | |
| `'hello world'.contains('goodbye') // false`), | |
| decls.BinaryBinding(types.StringContains)), | |
| decls.DisableTypeGuards(true)), | |
| function(overloads.EndsWith, | |
| decls.FunctionDocs(`test whether a string ends with a substring suffix`), | |
| decls.MemberOverload(overloads.EndsWithString, | |
| argTypes(types.StringType, types.StringType), types.BoolType, | |
| decls.OverloadExamples( | |
| `'hello world'.endsWith('world') // true`, | |
| `'hello world'.endsWith('hello') // false`), | |
| decls.BinaryBinding(types.StringEndsWith)), | |
| decls.DisableTypeGuards(true)), | |
| function(overloads.StartsWith, | |
| decls.FunctionDocs(`test whether a string starts with a substring prefix`), | |
| decls.MemberOverload(overloads.StartsWithString, | |
| argTypes(types.StringType, types.StringType), types.BoolType, | |
| decls.OverloadExamples( | |
| `'hello world'.startsWith('hello') // true`, | |
| `'hello world'.startsWith('world') // false`), | |
| decls.BinaryBinding(types.StringStartsWith)), | |
| decls.DisableTypeGuards(true)), | |
| function(overloads.Matches, | |
| decls.FunctionDocs(`test whether a string matches an RE2 regular expression`), | |
| decls.Overload(overloads.Matches, argTypes(types.StringType, types.StringType), types.BoolType, | |
| decls.OverloadExamples( | |
| `matches('123-456', '^[0-9]+(-[0-9]+)?$') // true`, | |
| `matches('hello', '^h.*o$') // true`)), | |
| decls.MemberOverload(overloads.MatchesString, | |
| argTypes(types.StringType, types.StringType), types.BoolType, | |
| decls.OverloadExamples( | |
| `'123-456'.matches('^[0-9]+(-[0-9]+)?$') // true`, | |
| `'hello'.matches('^h.*o$') // true`)), | |
| decls.SingletonBinaryBinding(func(str, pat ref.Val) ref.Val { | |
| return str.(traits.Matcher).Match(pat) | |
| }, traits.MatcherType)), | |
| // Timestamp / duration functions | |
| function(overloads.TimeGetFullYear, | |
| decls.FunctionDocs(`get the 0-based full year from a timestamp, UTC unless an IANA timezone is specified.`), | |
| decls.MemberOverload(overloads.TimestampToYear, | |
| argTypes(types.TimestampType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getFullYear() // 2023`), | |
| decls.UnaryBinding(func(ts ref.Val) ref.Val { | |
| return timestampGetFullYear(ts, utcTZ) | |
| })), | |
| decls.MemberOverload(overloads.TimestampToYearWithTz, | |
| argTypes(types.TimestampType, types.StringType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-01-01T05:30:00Z').getFullYear('-08:00') // 2022`), | |
| decls.BinaryBinding(timestampGetFullYear))), | |
| function(overloads.TimeGetMonth, | |
| decls.FunctionDocs(`get the 0-based month from a timestamp, UTC unless an IANA timezone is specified.`), | |
| decls.MemberOverload(overloads.TimestampToMonth, | |
| argTypes(types.TimestampType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getMonth() // 6`), // July is month 6 | |
| decls.UnaryBinding(func(ts ref.Val) ref.Val { | |
| return timestampGetMonth(ts, utcTZ) | |
| })), | |
| decls.MemberOverload(overloads.TimestampToMonthWithTz, | |
| argTypes(types.TimestampType, types.StringType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-01-01T05:30:00Z').getMonth('America/Los_Angeles') // 11`), // December is month 11 | |
| decls.BinaryBinding(timestampGetMonth))), | |
| function(overloads.TimeGetDayOfYear, | |
| decls.FunctionDocs(`get the 0-based day of the year from a timestamp, UTC unless an IANA timezone is specified.`), | |
| decls.MemberOverload(overloads.TimestampToDayOfYear, | |
| argTypes(types.TimestampType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-01-02T00:00:00Z').getDayOfYear() // 1`), | |
| decls.UnaryBinding(func(ts ref.Val) ref.Val { | |
| return timestampGetDayOfYear(ts, utcTZ) | |
| })), | |
| decls.MemberOverload(overloads.TimestampToDayOfYearWithTz, | |
| argTypes(types.TimestampType, types.StringType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-01-01T05:00:00Z').getDayOfYear('America/Los_Angeles') // 364`), | |
| decls.BinaryBinding(timestampGetDayOfYear))), | |
| function(overloads.TimeGetDayOfMonth, | |
| decls.FunctionDocs(`get the 0-based day of the month from a timestamp, UTC unless an IANA timezone is specified.`), | |
| decls.MemberOverload(overloads.TimestampToDayOfMonthZeroBased, | |
| argTypes(types.TimestampType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getDayOfMonth() // 13`), | |
| decls.UnaryBinding(func(ts ref.Val) ref.Val { | |
| return timestampGetDayOfMonthZeroBased(ts, utcTZ) | |
| })), | |
| decls.MemberOverload(overloads.TimestampToDayOfMonthZeroBasedWithTz, | |
| argTypes(types.TimestampType, types.StringType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-01T05:00:00Z').getDayOfMonth('America/Los_Angeles') // 29`), | |
| decls.BinaryBinding(timestampGetDayOfMonthZeroBased))), | |
| function(overloads.TimeGetDate, | |
| decls.FunctionDocs(`get the 1-based day of the month from a timestamp, UTC unless an IANA timezone is specified.`), | |
| decls.MemberOverload(overloads.TimestampToDayOfMonthOneBased, | |
| argTypes(types.TimestampType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getDate() // 14`), | |
| decls.UnaryBinding(func(ts ref.Val) ref.Val { | |
| return timestampGetDayOfMonthOneBased(ts, utcTZ) | |
| })), | |
| decls.MemberOverload(overloads.TimestampToDayOfMonthOneBasedWithTz, | |
| argTypes(types.TimestampType, types.StringType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-01T05:00:00Z').getDate('America/Los_Angeles') // 30`), | |
| decls.BinaryBinding(timestampGetDayOfMonthOneBased))), | |
| function(overloads.TimeGetDayOfWeek, | |
| decls.FunctionDocs(`get the 0-based day of the week from a timestamp, UTC unless an IANA timezone is specified.`), | |
| decls.MemberOverload(overloads.TimestampToDayOfWeek, | |
| argTypes(types.TimestampType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getDayOfWeek() // 5`), // Friday is day 5 | |
| decls.UnaryBinding(func(ts ref.Val) ref.Val { | |
| return timestampGetDayOfWeek(ts, utcTZ) | |
| })), | |
| decls.MemberOverload(overloads.TimestampToDayOfWeekWithTz, | |
| argTypes(types.TimestampType, types.StringType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-16T05:00:00Z').getDayOfWeek('America/Los_Angeles') // 6`), // Saturday is day 6 | |
| decls.BinaryBinding(timestampGetDayOfWeek))), | |
| function(overloads.TimeGetHours, | |
| decls.FunctionDocs(`get the hours portion from a timestamp, or convert a duration to hours`), | |
| decls.MemberOverload(overloads.TimestampToHours, | |
| argTypes(types.TimestampType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getHours() // 10`), | |
| decls.UnaryBinding(func(ts ref.Val) ref.Val { | |
| return timestampGetHours(ts, utcTZ) | |
| })), | |
| decls.MemberOverload(overloads.TimestampToHoursWithTz, | |
| argTypes(types.TimestampType, types.StringType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getHours('America/Los_Angeles') // 2`), | |
| decls.BinaryBinding(timestampGetHours)), | |
| decls.MemberOverload(overloads.DurationToHours, | |
| argTypes(types.DurationType), types.IntType, | |
| decls.OverloadExamples(`duration('3723s').getHours() // 1`), | |
| decls.UnaryBinding(types.DurationGetHours))), | |
| function(overloads.TimeGetMinutes, | |
| decls.FunctionDocs(`get the minutes portion from a timestamp, or convert a duration to minutes`), | |
| decls.MemberOverload(overloads.TimestampToMinutes, | |
| argTypes(types.TimestampType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getMinutes() // 30`), | |
| decls.UnaryBinding(func(ts ref.Val) ref.Val { | |
| return timestampGetMinutes(ts, utcTZ) | |
| })), | |
| decls.MemberOverload(overloads.TimestampToMinutesWithTz, | |
| argTypes(types.TimestampType, types.StringType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getMinutes('America/Los_Angeles') // 30`), | |
| decls.BinaryBinding(timestampGetMinutes)), | |
| decls.MemberOverload(overloads.DurationToMinutes, | |
| argTypes(types.DurationType), types.IntType, | |
| decls.OverloadExamples(`duration('3723s').getMinutes() // 62`), | |
| decls.UnaryBinding(types.DurationGetMinutes))), | |
| function(overloads.TimeGetSeconds, | |
| decls.FunctionDocs(`get the seconds portion from a timestamp, or convert a duration to seconds`), | |
| decls.MemberOverload(overloads.TimestampToSeconds, | |
| argTypes(types.TimestampType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getSeconds() // 45`), | |
| decls.UnaryBinding(func(ts ref.Val) ref.Val { | |
| return timestampGetSeconds(ts, utcTZ) | |
| })), | |
| decls.MemberOverload(overloads.TimestampToSecondsWithTz, | |
| argTypes(types.TimestampType, types.StringType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getSeconds('America/Los_Angeles') // 45`), | |
| decls.BinaryBinding(timestampGetSeconds)), | |
| decls.MemberOverload(overloads.DurationToSeconds, | |
| argTypes(types.DurationType), types.IntType, | |
| decls.OverloadExamples(`duration('3723.456s').getSeconds() // 3723`), | |
| decls.UnaryBinding(types.DurationGetSeconds))), | |
| function(overloads.TimeGetMilliseconds, | |
| decls.FunctionDocs(`get the milliseconds portion from a timestamp`), | |
| decls.MemberOverload(overloads.TimestampToMilliseconds, | |
| argTypes(types.TimestampType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getMilliseconds() // 123`), | |
| decls.UnaryBinding(func(ts ref.Val) ref.Val { | |
| return timestampGetMilliseconds(ts, utcTZ) | |
| })), | |
| decls.MemberOverload(overloads.TimestampToMillisecondsWithTz, | |
| argTypes(types.TimestampType, types.StringType), types.IntType, | |
| decls.OverloadExamples(`timestamp('2023-07-14T10:30:45.123Z').getMilliseconds('America/Los_Angeles') // 123`), | |
| decls.BinaryBinding(timestampGetMilliseconds)), | |
| decls.MemberOverload(overloads.DurationToMilliseconds, | |
| argTypes(types.DurationType), types.IntType, | |
| decls.UnaryBinding(types.DurationGetMilliseconds))), | |
| } | |
| } | |
| // Functions returns the set of standard library function declarations and definitions for CEL. | |
| func Functions() []*decls.FunctionDecl { | |
| return stdFunctions | |
| } | |
| // Types returns the set of standard library types for CEL. | |
| func Types() []*decls.VariableDecl { | |
| return stdTypes | |
| } | |
| func notStrictlyFalse(value ref.Val) ref.Val { | |
| if types.IsBool(value) { | |
| return value | |
| } | |
| return types.True | |
| } | |
| func inAggregate(lhs ref.Val, rhs ref.Val) ref.Val { | |
| if rhs.Type().HasTrait(traits.ContainerType) { | |
| return rhs.(traits.Container).Contains(lhs) | |
| } | |
| return types.ValOrErr(rhs, "no such overload") | |
| } | |
| func function(name string, opts ...decls.FunctionOpt) *decls.FunctionDecl { | |
| fn, err := decls.NewFunction(name, opts...) | |
| if err != nil { | |
| panic(err) | |
| } | |
| return fn | |
| } | |
| func argTypes(args ...*types.Type) []*types.Type { | |
| return args | |
| } | |
| func noBinaryOverrides(rhs, lhs ref.Val) ref.Val { | |
| return types.NoSuchOverloadErr() | |
| } | |
| func isNaN(val ref.Val) bool { | |
| d, ok := val.(types.Double) | |
| return ok && math.IsNaN(float64(d)) | |
| } | |
| func noFunctionOverrides(args ...ref.Val) ref.Val { | |
| return types.NoSuchOverloadErr() | |
| } | |
| func identity(val ref.Val) ref.Val { | |
| return val | |
| } | |
| func convertToType(t ref.Type) functions.UnaryOp { | |
| return func(val ref.Val) ref.Val { | |
| return val.ConvertToType(t) | |
| } | |
| } | |
| func timestampGetFullYear(ts, tz ref.Val) ref.Val { | |
| t, err := inTimeZone(ts, tz) | |
| if err != nil { | |
| return types.NewErrFromString(err.Error()) | |
| } | |
| return types.Int(t.Year()) | |
| } | |
| func timestampGetMonth(ts, tz ref.Val) ref.Val { | |
| t, err := inTimeZone(ts, tz) | |
| if err != nil { | |
| return types.NewErrFromString(err.Error()) | |
| } | |
| // CEL spec indicates that the month should be 0-based, but the Time value | |
| // for Month() is 1-based. | |
| return types.Int(t.Month() - 1) | |
| } | |
| func timestampGetDayOfYear(ts, tz ref.Val) ref.Val { | |
| t, err := inTimeZone(ts, tz) | |
| if err != nil { | |
| return types.NewErrFromString(err.Error()) | |
| } | |
| return types.Int(t.YearDay() - 1) | |
| } | |
| func timestampGetDayOfMonthZeroBased(ts, tz ref.Val) ref.Val { | |
| t, err := inTimeZone(ts, tz) | |
| if err != nil { | |
| return types.NewErrFromString(err.Error()) | |
| } | |
| return types.Int(t.Day() - 1) | |
| } | |
| func timestampGetDayOfMonthOneBased(ts, tz ref.Val) ref.Val { | |
| t, err := inTimeZone(ts, tz) | |
| if err != nil { | |
| return types.NewErrFromString(err.Error()) | |
| } | |
| return types.Int(t.Day()) | |
| } | |
| func timestampGetDayOfWeek(ts, tz ref.Val) ref.Val { | |
| t, err := inTimeZone(ts, tz) | |
| if err != nil { | |
| return types.NewErrFromString(err.Error()) | |
| } | |
| return types.Int(t.Weekday()) | |
| } | |
| func timestampGetHours(ts, tz ref.Val) ref.Val { | |
| t, err := inTimeZone(ts, tz) | |
| if err != nil { | |
| return types.NewErrFromString(err.Error()) | |
| } | |
| return types.Int(t.Hour()) | |
| } | |
| func timestampGetMinutes(ts, tz ref.Val) ref.Val { | |
| t, err := inTimeZone(ts, tz) | |
| if err != nil { | |
| return types.NewErrFromString(err.Error()) | |
| } | |
| return types.Int(t.Minute()) | |
| } | |
| func timestampGetSeconds(ts, tz ref.Val) ref.Val { | |
| t, err := inTimeZone(ts, tz) | |
| if err != nil { | |
| return types.NewErrFromString(err.Error()) | |
| } | |
| return types.Int(t.Second()) | |
| } | |
| func timestampGetMilliseconds(ts, tz ref.Val) ref.Val { | |
| t, err := inTimeZone(ts, tz) | |
| if err != nil { | |
| return types.NewErrFromString(err.Error()) | |
| } | |
| return types.Int(t.Nanosecond() / 1000000) | |
| } | |
| func inTimeZone(ts, tz ref.Val) (time.Time, error) { | |
| t := ts.(types.Timestamp) | |
| val := string(tz.(types.String)) | |
| ind := strings.Index(val, ":") | |
| if ind == -1 { | |
| loc, err := time.LoadLocation(val) | |
| if err != nil { | |
| return time.Time{}, err | |
| } | |
| return t.In(loc), nil | |
| } | |
| // If the input is not the name of a timezone (for example, 'US/Central'), it should be a numerical offset from UTC | |
| // in the format ^(+|-)([01]\d|2[0-3]):[0-5][0-9]$. The numerical input is parsed in terms of hours and minutes. | |
| hr, err := strconv.Atoi(string(val[0:ind])) | |
| if err != nil { | |
| return time.Time{}, err | |
| } | |
| min, err := strconv.Atoi(string(val[ind+1:])) | |
| if err != nil { | |
| return time.Time{}, err | |
| } | |
| if hr < -23 || hr > 23 { | |
| return time.Time{}, fmt.Errorf("timezone offset hours out of range [-23, 23]: %s", val) | |
| } | |
| if min < 0 || min > 59 { | |
| return time.Time{}, fmt.Errorf("timezone offset minutes out of range [0, 59]: %s", val) | |
| } | |
| var offset int | |
| if string(val[0]) == "-" { | |
| offset = hr*60 - min | |
| } else { | |
| offset = hr*60 + min | |
| } | |
| secondsEastOfUTC := int((time.Duration(offset) * time.Minute).Seconds()) | |
| timezone := time.FixedZone("", secondsEastOfUTC) | |
| return t.In(timezone), nil | |
| } |