github.com/rajeev159/opa@v0.45.0/topdown/builtins/builtins.go (about) 1 // Copyright 2016 The OPA Authors. All rights reserved. 2 // Use of this source code is governed by an Apache2 3 // license that can be found in the LICENSE file. 4 5 // Package builtins contains utilities for implementing built-in functions. 6 package builtins 7 8 import ( 9 "fmt" 10 "math/big" 11 "strings" 12 13 "github.com/open-policy-agent/opa/ast" 14 ) 15 16 // Cache defines the built-in cache used by the top-down evaluation. The keys 17 // must be comparable and should not be of type string. 18 type Cache map[interface{}]interface{} 19 20 // Put updates the cache for the named built-in. 21 func (c Cache) Put(k, v interface{}) { 22 c[k] = v 23 } 24 25 // Get returns the cached value for k. 26 func (c Cache) Get(k interface{}) (interface{}, bool) { 27 v, ok := c[k] 28 return v, ok 29 } 30 31 // ErrOperand represents an invalid operand has been passed to a built-in 32 // function. Built-ins should return ErrOperand to indicate a type error has 33 // occurred. 34 type ErrOperand string 35 36 func (err ErrOperand) Error() string { 37 return string(err) 38 } 39 40 // NewOperandErr returns a generic operand error. 41 func NewOperandErr(pos int, f string, a ...interface{}) error { 42 f = fmt.Sprintf("operand %v ", pos) + f 43 return ErrOperand(fmt.Sprintf(f, a...)) 44 } 45 46 // NewOperandTypeErr returns an operand error indicating the operand's type was wrong. 47 func NewOperandTypeErr(pos int, got ast.Value, expected ...string) error { 48 49 if len(expected) == 1 { 50 return NewOperandErr(pos, "must be %v but got %v", expected[0], ast.TypeName(got)) 51 } 52 53 return NewOperandErr(pos, "must be one of {%v} but got %v", strings.Join(expected, ", "), ast.TypeName(got)) 54 } 55 56 // NewOperandElementErr returns an operand error indicating an element in the 57 // composite operand was wrong. 58 func NewOperandElementErr(pos int, composite ast.Value, got ast.Value, expected ...string) error { 59 60 tpe := ast.TypeName(composite) 61 62 if len(expected) == 1 { 63 return NewOperandErr(pos, "must be %v of %vs but got %v containing %v", tpe, expected[0], tpe, ast.TypeName(got)) 64 } 65 66 return NewOperandErr(pos, "must be %v of (any of) {%v} but got %v containing %v", tpe, strings.Join(expected, ", "), tpe, ast.TypeName(got)) 67 } 68 69 // NewOperandEnumErr returns an operand error indicating a value was wrong. 70 func NewOperandEnumErr(pos int, expected ...string) error { 71 72 if len(expected) == 1 { 73 return NewOperandErr(pos, "must be %v", expected[0]) 74 } 75 76 return NewOperandErr(pos, "must be one of {%v}", strings.Join(expected, ", ")) 77 } 78 79 // IntOperand converts x to an int. If the cast fails, a descriptive error is 80 // returned. 81 func IntOperand(x ast.Value, pos int) (int, error) { 82 n, ok := x.(ast.Number) 83 if !ok { 84 return 0, NewOperandTypeErr(pos, x, "number") 85 } 86 87 i, ok := n.Int() 88 if !ok { 89 return 0, NewOperandErr(pos, "must be integer number but got floating-point number") 90 } 91 92 return i, nil 93 } 94 95 // BigIntOperand converts x to a big int. If the cast fails, a descriptive error 96 // is returned. 97 func BigIntOperand(x ast.Value, pos int) (*big.Int, error) { 98 n, err := NumberOperand(x, 1) 99 if err != nil { 100 return nil, NewOperandTypeErr(pos, x, "integer") 101 } 102 bi, err := NumberToInt(n) 103 if err != nil { 104 return nil, NewOperandErr(pos, "must be integer number but got floating-point number") 105 } 106 107 return bi, nil 108 } 109 110 // NumberOperand converts x to a number. If the cast fails, a descriptive error is 111 // returned. 112 func NumberOperand(x ast.Value, pos int) (ast.Number, error) { 113 n, ok := x.(ast.Number) 114 if !ok { 115 return ast.Number(""), NewOperandTypeErr(pos, x, "number") 116 } 117 return n, nil 118 } 119 120 // SetOperand converts x to a set. If the cast fails, a descriptive error is 121 // returned. 122 func SetOperand(x ast.Value, pos int) (ast.Set, error) { 123 s, ok := x.(ast.Set) 124 if !ok { 125 return nil, NewOperandTypeErr(pos, x, "set") 126 } 127 return s, nil 128 } 129 130 // StringOperand converts x to a string. If the cast fails, a descriptive error is 131 // returned. 132 func StringOperand(x ast.Value, pos int) (ast.String, error) { 133 s, ok := x.(ast.String) 134 if !ok { 135 return ast.String(""), NewOperandTypeErr(pos, x, "string") 136 } 137 return s, nil 138 } 139 140 // ObjectOperand converts x to an object. If the cast fails, a descriptive 141 // error is returned. 142 func ObjectOperand(x ast.Value, pos int) (ast.Object, error) { 143 o, ok := x.(ast.Object) 144 if !ok { 145 return nil, NewOperandTypeErr(pos, x, "object") 146 } 147 return o, nil 148 } 149 150 // ArrayOperand converts x to an array. If the cast fails, a descriptive 151 // error is returned. 152 func ArrayOperand(x ast.Value, pos int) (*ast.Array, error) { 153 a, ok := x.(*ast.Array) 154 if !ok { 155 return ast.NewArray(), NewOperandTypeErr(pos, x, "array") 156 } 157 return a, nil 158 } 159 160 // NumberToFloat converts n to a big float. 161 func NumberToFloat(n ast.Number) *big.Float { 162 r, ok := new(big.Float).SetString(string(n)) 163 if !ok { 164 panic("illegal value") 165 } 166 return r 167 } 168 169 // FloatToNumber converts f to a number. 170 func FloatToNumber(f *big.Float) ast.Number { 171 return ast.Number(f.Text('g', -1)) 172 } 173 174 // NumberToInt converts n to a big int. 175 // If n cannot be converted to an big int, an error is returned. 176 func NumberToInt(n ast.Number) (*big.Int, error) { 177 f := NumberToFloat(n) 178 r, accuracy := f.Int(nil) 179 if accuracy != big.Exact { 180 return nil, fmt.Errorf("illegal value") 181 } 182 return r, nil 183 } 184 185 // IntToNumber converts i to a number. 186 func IntToNumber(i *big.Int) ast.Number { 187 return ast.Number(i.String()) 188 } 189 190 // StringSliceOperand converts x to a []string. If the cast fails, a descriptive error is 191 // returned. 192 func StringSliceOperand(x ast.Value, pos int) ([]string, error) { 193 a, err := ArrayOperand(x, pos) 194 if err != nil { 195 return nil, err 196 } 197 198 var f = make([]string, a.Len()) 199 for k := 0; k < a.Len(); k++ { 200 b := a.Elem(k) 201 c, ok := b.Value.(ast.String) 202 if !ok { 203 return nil, NewOperandElementErr(pos, x, b.Value, "[]string") 204 } 205 206 f[k] = string(c) 207 } 208 209 return f, nil 210 } 211 212 // RuneSliceOperand converts x to a []rune. If the cast fails, a descriptive error is 213 // returned. 214 func RuneSliceOperand(x ast.Value, pos int) ([]rune, error) { 215 a, err := ArrayOperand(x, pos) 216 if err != nil { 217 return nil, err 218 } 219 220 var f = make([]rune, a.Len()) 221 for k := 0; k < a.Len(); k++ { 222 b := a.Elem(k) 223 c, ok := b.Value.(ast.String) 224 if !ok { 225 return nil, NewOperandElementErr(pos, x, b.Value, "string") 226 } 227 228 d := []rune(string(c)) 229 if len(d) != 1 { 230 return nil, NewOperandElementErr(pos, x, b.Value, "rune") 231 } 232 233 f[k] = d[0] 234 } 235 236 return f, nil 237 }