diff --git a/profiler/profiler_test.go b/profiler/profiler_test.go index a02ad29d9d..953dc1a36b 100644 --- a/profiler/profiler_test.go +++ b/profiler/profiler_test.go @@ -106,10 +106,10 @@ func TestProfileCheckExprDuration(t *testing.T) { ), }) - topdown.RegisterFunctionalBuiltin1("test.sleep", func(a ast.Value) (ast.Value, error) { - d, _ := time.ParseDuration(string(a.(ast.String))) + topdown.RegisterBuiltinFunc("test.sleep", func(_ topdown.BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + d, _ := time.ParseDuration(string(operands[0].Value.(ast.String))) time.Sleep(d) - return ast.Null{}, nil + return iter(ast.NullTerm()) }) module := `package test @@ -152,7 +152,7 @@ func TestProfileCheckExprDuration(t *testing.T) { } if fr.Result[0].ExprTimeNs <= time.Duration(50*time.Millisecond).Nanoseconds() { - t.Fatalf("Expected eval time is atleast 100 msec but got %v", fr.Result[0].ExprTimeNs) + t.Fatalf("Expected eval time is at least 100 msec but got %v", fr.Result[0].ExprTimeNs) } } diff --git a/rego/rego_test.go b/rego/rego_test.go index 0c2ab3363f..3f408409b0 100644 --- a/rego/rego_test.go +++ b/rego/rego_test.go @@ -245,13 +245,13 @@ func TestRegoCancellation(t *testing.T) { ), }) - topdown.RegisterFunctionalBuiltin1("test.sleep", func(a ast.Value) (ast.Value, error) { - d, _ := time.ParseDuration(string(a.(ast.String))) + topdown.RegisterBuiltinFunc("test.sleep", func(_ topdown.BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + d, _ := time.ParseDuration(string(operands[0].Value.(ast.String))) time.Sleep(d) - return ast.Null{}, nil + return iter(ast.NullTerm()) }) - ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50) + ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*10) r := New(Query(`test.sleep("1s")`)) rs, err := r.Eval(ctx) cancel() diff --git a/tester/runner_test.go b/tester/runner_test.go index 876d2bf492..c3679c7cb2 100644 --- a/tester/runner_test.go +++ b/tester/runner_test.go @@ -487,10 +487,10 @@ func registerSleepBuiltin() { ), }) - topdown.RegisterFunctionalBuiltin1("test.sleep", func(a ast.Value) (ast.Value, error) { - d, _ := time.ParseDuration(string(a.(ast.String))) + topdown.RegisterBuiltinFunc("test.sleep", func(_ topdown.BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + d, _ := time.ParseDuration(string(operands[0].Value.(ast.String))) time.Sleep(d) - return ast.Null{}, nil + return iter(ast.NullTerm()) }) } diff --git a/topdown/aggregates.go b/topdown/aggregates.go index eba6db23dc..a0f67a7c95 100644 --- a/topdown/aggregates.go +++ b/topdown/aggregates.go @@ -11,22 +11,22 @@ import ( "github.com/open-policy-agent/opa/topdown/builtins" ) -func builtinCount(a ast.Value) (ast.Value, error) { - switch a := a.(type) { +func builtinCount(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch a := operands[0].Value.(type) { case *ast.Array: - return ast.IntNumberTerm(a.Len()).Value, nil + return iter(ast.IntNumberTerm(a.Len())) case ast.Object: - return ast.IntNumberTerm(a.Len()).Value, nil + return iter(ast.IntNumberTerm(a.Len())) case ast.Set: - return ast.IntNumberTerm(a.Len()).Value, nil + return iter(ast.IntNumberTerm(a.Len())) case ast.String: - return ast.IntNumberTerm(len([]rune(a))).Value, nil + return iter(ast.IntNumberTerm(len([]rune(a)))) } - return nil, builtins.NewOperandTypeErr(1, a, "array", "object", "set", "string") + return builtins.NewOperandTypeErr(1, operands[0].Value, "array", "object", "set", "string") } -func builtinSum(a ast.Value) (ast.Value, error) { - switch a := a.(type) { +func builtinSum(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch a := operands[0].Value.(type) { case *ast.Array: sum := big.NewFloat(0) err := a.Iter(func(x *ast.Term) error { @@ -37,7 +37,10 @@ func builtinSum(a ast.Value) (ast.Value, error) { sum = new(big.Float).Add(sum, builtins.NumberToFloat(n)) return nil }) - return builtins.FloatToNumber(sum), err + if err != nil { + return err + } + return iter(ast.NewTerm(builtins.FloatToNumber(sum))) case ast.Set: sum := big.NewFloat(0) err := a.Iter(func(x *ast.Term) error { @@ -48,13 +51,16 @@ func builtinSum(a ast.Value) (ast.Value, error) { sum = new(big.Float).Add(sum, builtins.NumberToFloat(n)) return nil }) - return builtins.FloatToNumber(sum), err + if err != nil { + return err + } + return iter(ast.NewTerm(builtins.FloatToNumber(sum))) } - return nil, builtins.NewOperandTypeErr(1, a, "set", "array") + return builtins.NewOperandTypeErr(1, operands[0].Value, "set", "array") } -func builtinProduct(a ast.Value) (ast.Value, error) { - switch a := a.(type) { +func builtinProduct(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch a := operands[0].Value.(type) { case *ast.Array: product := big.NewFloat(1) err := a.Iter(func(x *ast.Term) error { @@ -65,7 +71,10 @@ func builtinProduct(a ast.Value) (ast.Value, error) { product = new(big.Float).Mul(product, builtins.NumberToFloat(n)) return nil }) - return builtins.FloatToNumber(product), err + if err != nil { + return err + } + return iter(ast.NewTerm(builtins.FloatToNumber(product))) case ast.Set: product := big.NewFloat(1) err := a.Iter(func(x *ast.Term) error { @@ -76,16 +85,19 @@ func builtinProduct(a ast.Value) (ast.Value, error) { product = new(big.Float).Mul(product, builtins.NumberToFloat(n)) return nil }) - return builtins.FloatToNumber(product), err + if err != nil { + return err + } + return iter(ast.NewTerm(builtins.FloatToNumber(product))) } - return nil, builtins.NewOperandTypeErr(1, a, "set", "array") + return builtins.NewOperandTypeErr(1, operands[0].Value, "set", "array") } -func builtinMax(a ast.Value) (ast.Value, error) { - switch a := a.(type) { +func builtinMax(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch a := operands[0].Value.(type) { case *ast.Array: if a.Len() == 0 { - return nil, BuiltinEmpty{} + return nil } var max = ast.Value(ast.Null{}) a.Foreach(func(x *ast.Term) { @@ -93,10 +105,10 @@ func builtinMax(a ast.Value) (ast.Value, error) { max = x.Value } }) - return max, nil + return iter(ast.NewTerm(max)) case ast.Set: if a.Len() == 0 { - return nil, BuiltinEmpty{} + return nil } max, err := a.Reduce(ast.NullTerm(), func(max *ast.Term, elem *ast.Term) (*ast.Term, error) { if ast.Compare(max, elem) <= 0 { @@ -104,17 +116,20 @@ func builtinMax(a ast.Value) (ast.Value, error) { } return max, nil }) - return max.Value, err + if err != nil { + return err + } + return iter(max) } - return nil, builtins.NewOperandTypeErr(1, a, "set", "array") + return builtins.NewOperandTypeErr(1, operands[0].Value, "set", "array") } -func builtinMin(a ast.Value) (ast.Value, error) { - switch a := a.(type) { +func builtinMin(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch a := operands[0].Value.(type) { case *ast.Array: if a.Len() == 0 { - return nil, BuiltinEmpty{} + return nil } min := a.Elem(0).Value a.Foreach(func(x *ast.Term) { @@ -122,10 +137,10 @@ func builtinMin(a ast.Value) (ast.Value, error) { min = x.Value } }) - return min, nil + return iter(ast.NewTerm(min)) case ast.Set: if a.Len() == 0 { - return nil, BuiltinEmpty{} + return nil } min, err := a.Reduce(ast.NullTerm(), func(min *ast.Term, elem *ast.Term) (*ast.Term, error) { // The null term is considered to be less than any other term, @@ -140,24 +155,27 @@ func builtinMin(a ast.Value) (ast.Value, error) { } return min, nil }) - return min.Value, err + if err != nil { + return err + } + return iter(min) } - return nil, builtins.NewOperandTypeErr(1, a, "set", "array") + return builtins.NewOperandTypeErr(1, operands[0].Value, "set", "array") } -func builtinSort(a ast.Value) (ast.Value, error) { - switch a := a.(type) { +func builtinSort(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch a := operands[0].Value.(type) { case *ast.Array: - return a.Sorted(), nil + return iter(ast.NewTerm(a.Sorted())) case ast.Set: - return a.Sorted(), nil + return iter(ast.NewTerm(a.Sorted())) } - return nil, builtins.NewOperandTypeErr(1, a, "set", "array") + return builtins.NewOperandTypeErr(1, operands[0].Value, "set", "array") } -func builtinAll(a ast.Value) (ast.Value, error) { - switch val := a.(type) { +func builtinAll(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch val := operands[0].Value.(type) { case ast.Set: res := true match := ast.BooleanTerm(true) @@ -168,7 +186,7 @@ func builtinAll(a ast.Value) (ast.Value, error) { } return false }) - return ast.Boolean(res), nil + return iter(ast.BooleanTerm(res)) case *ast.Array: res := true match := ast.BooleanTerm(true) @@ -179,17 +197,17 @@ func builtinAll(a ast.Value) (ast.Value, error) { } return false }) - return ast.Boolean(res), nil + return iter(ast.BooleanTerm(res)) default: - return nil, builtins.NewOperandTypeErr(1, a, "array", "set") + return builtins.NewOperandTypeErr(1, operands[0].Value, "array", "set") } } -func builtinAny(a ast.Value) (ast.Value, error) { - switch val := a.(type) { +func builtinAny(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch val := operands[0].Value.(type) { case ast.Set: res := val.Len() > 0 && val.Contains(ast.BooleanTerm(true)) - return ast.Boolean(res), nil + return iter(ast.BooleanTerm(res)) case *ast.Array: res := false match := ast.BooleanTerm(true) @@ -200,15 +218,15 @@ func builtinAny(a ast.Value) (ast.Value, error) { } return false }) - return ast.Boolean(res), nil + return iter(ast.BooleanTerm(res)) default: - return nil, builtins.NewOperandTypeErr(1, a, "array", "set") + return builtins.NewOperandTypeErr(1, operands[0].Value, "array", "set") } } -func builtinMember(_ BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - containee := args[0] - switch c := args[1].Value.(type) { +func builtinMember(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + containee := operands[0] + switch c := operands[1].Value.(type) { case ast.Set: return iter(ast.BooleanTerm(c.Contains(containee))) case *ast.Array: @@ -233,9 +251,9 @@ func builtinMember(_ BuiltinContext, args []*ast.Term, iter func(*ast.Term) erro return iter(ast.BooleanTerm(false)) } -func builtinMemberWithKey(_ BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - key, val := args[0], args[1] - switch c := args[2].Value.(type) { +func builtinMemberWithKey(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + key, val := operands[0], operands[1] + switch c := operands[2].Value.(type) { case interface{ Get(*ast.Term) *ast.Term }: ret := false if act := c.Get(key); act != nil { @@ -247,14 +265,14 @@ func builtinMemberWithKey(_ BuiltinContext, args []*ast.Term, iter func(*ast.Ter } func init() { - RegisterFunctionalBuiltin1(ast.Count.Name, builtinCount) - RegisterFunctionalBuiltin1(ast.Sum.Name, builtinSum) - RegisterFunctionalBuiltin1(ast.Product.Name, builtinProduct) - RegisterFunctionalBuiltin1(ast.Max.Name, builtinMax) - RegisterFunctionalBuiltin1(ast.Min.Name, builtinMin) - RegisterFunctionalBuiltin1(ast.Sort.Name, builtinSort) - RegisterFunctionalBuiltin1(ast.Any.Name, builtinAny) - RegisterFunctionalBuiltin1(ast.All.Name, builtinAll) + RegisterBuiltinFunc(ast.Count.Name, builtinCount) + RegisterBuiltinFunc(ast.Sum.Name, builtinSum) + RegisterBuiltinFunc(ast.Product.Name, builtinProduct) + RegisterBuiltinFunc(ast.Max.Name, builtinMax) + RegisterBuiltinFunc(ast.Min.Name, builtinMin) + RegisterBuiltinFunc(ast.Sort.Name, builtinSort) + RegisterBuiltinFunc(ast.Any.Name, builtinAny) + RegisterBuiltinFunc(ast.All.Name, builtinAll) RegisterBuiltinFunc(ast.Member.Name, builtinMember) RegisterBuiltinFunc(ast.MemberWithKey.Name, builtinMemberWithKey) } diff --git a/topdown/arithmetic.go b/topdown/arithmetic.go index 7e9252ff6d..c75f816a4f 100644 --- a/topdown/arithmetic.go +++ b/topdown/arithmetic.go @@ -81,72 +81,72 @@ func arithRem(a, b *big.Int) (*big.Int, error) { return new(big.Int).Rem(a, b), nil } -func builtinArithArity1(fn arithArity1) FunctionalBuiltin1 { - return func(a ast.Value) (ast.Value, error) { - n, err := builtins.NumberOperand(a, 1) +func builtinArithArity1(fn arithArity1) BuiltinFunc { + return func(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + n, err := builtins.NumberOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } f, err := fn(builtins.NumberToFloat(n)) if err != nil { - return nil, err + return err } - return builtins.FloatToNumber(f), nil + return iter(ast.NewTerm(builtins.FloatToNumber(f))) } } -func builtinArithArity2(fn arithArity2) FunctionalBuiltin2 { - return func(a, b ast.Value) (ast.Value, error) { - n1, err := builtins.NumberOperand(a, 1) +func builtinArithArity2(fn arithArity2) BuiltinFunc { + return func(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + n1, err := builtins.NumberOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - n2, err := builtins.NumberOperand(b, 2) + n2, err := builtins.NumberOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } f, err := fn(builtins.NumberToFloat(n1), builtins.NumberToFloat(n2)) if err != nil { - return nil, err + return err } - return builtins.FloatToNumber(f), nil + return iter(ast.NewTerm(builtins.FloatToNumber(f))) } } -func builtinMinus(a, b ast.Value) (ast.Value, error) { +func builtinMinus(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - n1, ok1 := a.(ast.Number) - n2, ok2 := b.(ast.Number) + n1, ok1 := operands[0].Value.(ast.Number) + n2, ok2 := operands[1].Value.(ast.Number) if ok1 && ok2 { f, err := arithMinus(builtins.NumberToFloat(n1), builtins.NumberToFloat(n2)) if err != nil { - return nil, err + return err } - return builtins.FloatToNumber(f), nil + return iter(ast.NewTerm(builtins.FloatToNumber(f))) } - s1, ok3 := a.(ast.Set) - s2, ok4 := b.(ast.Set) + s1, ok3 := operands[0].Value.(ast.Set) + s2, ok4 := operands[1].Value.(ast.Set) if ok3 && ok4 { - return s1.Diff(s2), nil + return iter(ast.NewTerm(s1.Diff(s2))) } if !ok1 && !ok3 { - return nil, builtins.NewOperandTypeErr(1, a, "number", "set") + return builtins.NewOperandTypeErr(1, operands[0].Value, "number", "set") } if ok2 { - return nil, builtins.NewOperandTypeErr(2, b, "set") + return builtins.NewOperandTypeErr(2, operands[1].Value, "set") } - return nil, builtins.NewOperandTypeErr(2, b, "number") + return builtins.NewOperandTypeErr(2, operands[1].Value, "number") } -func builtinRem(a, b ast.Value) (ast.Value, error) { - n1, ok1 := a.(ast.Number) - n2, ok2 := b.(ast.Number) +func builtinRem(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + n1, ok1 := operands[0].Value.(ast.Number) + n2, ok2 := operands[1].Value.(ast.Number) if ok1 && ok2 { @@ -154,31 +154,31 @@ func builtinRem(a, b ast.Value) (ast.Value, error) { op2, err2 := builtins.NumberToInt(n2) if err1 != nil || err2 != nil { - return nil, fmt.Errorf("modulo on floating-point number") + return fmt.Errorf("modulo on floating-point number") } i, err := arithRem(op1, op2) if err != nil { - return nil, err + return err } - return builtins.IntToNumber(i), nil + return iter(ast.NewTerm(builtins.IntToNumber(i))) } if !ok1 { - return nil, builtins.NewOperandTypeErr(1, a, "number") + return builtins.NewOperandTypeErr(1, operands[0].Value, "number") } - return nil, builtins.NewOperandTypeErr(2, b, "number") + return builtins.NewOperandTypeErr(2, operands[1].Value, "number") } func init() { - RegisterFunctionalBuiltin1(ast.Abs.Name, builtinArithArity1(arithAbs)) - RegisterFunctionalBuiltin1(ast.Round.Name, builtinArithArity1(arithRound)) - RegisterFunctionalBuiltin1(ast.Ceil.Name, builtinArithArity1(arithCeil)) - RegisterFunctionalBuiltin1(ast.Floor.Name, builtinArithArity1(arithFloor)) - RegisterFunctionalBuiltin2(ast.Plus.Name, builtinArithArity2(arithPlus)) - RegisterFunctionalBuiltin2(ast.Minus.Name, builtinMinus) - RegisterFunctionalBuiltin2(ast.Multiply.Name, builtinArithArity2(arithMultiply)) - RegisterFunctionalBuiltin2(ast.Divide.Name, builtinArithArity2(arithDivide)) - RegisterFunctionalBuiltin2(ast.Rem.Name, builtinRem) + RegisterBuiltinFunc(ast.Abs.Name, builtinArithArity1(arithAbs)) + RegisterBuiltinFunc(ast.Round.Name, builtinArithArity1(arithRound)) + RegisterBuiltinFunc(ast.Ceil.Name, builtinArithArity1(arithCeil)) + RegisterBuiltinFunc(ast.Floor.Name, builtinArithArity1(arithFloor)) + RegisterBuiltinFunc(ast.Plus.Name, builtinArithArity2(arithPlus)) + RegisterBuiltinFunc(ast.Minus.Name, builtinMinus) + RegisterBuiltinFunc(ast.Multiply.Name, builtinArithArity2(arithMultiply)) + RegisterBuiltinFunc(ast.Divide.Name, builtinArithArity2(arithDivide)) + RegisterBuiltinFunc(ast.Rem.Name, builtinRem) } diff --git a/topdown/array.go b/topdown/array.go index 939de49920..e7fe5be643 100644 --- a/topdown/array.go +++ b/topdown/array.go @@ -9,15 +9,15 @@ import ( "github.com/open-policy-agent/opa/topdown/builtins" ) -func builtinArrayConcat(a, b ast.Value) (ast.Value, error) { - arrA, err := builtins.ArrayOperand(a, 1) +func builtinArrayConcat(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + arrA, err := builtins.ArrayOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - arrB, err := builtins.ArrayOperand(b, 2) + arrB, err := builtins.ArrayOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } arrC := make([]*ast.Term, arrA.Len()+arrB.Len()) @@ -33,23 +33,23 @@ func builtinArrayConcat(a, b ast.Value) (ast.Value, error) { i++ }) - return ast.NewArray(arrC...), nil + return iter(ast.NewTerm(ast.NewArray(arrC...))) } -func builtinArraySlice(a, i, j ast.Value) (ast.Value, error) { - arr, err := builtins.ArrayOperand(a, 1) +func builtinArraySlice(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + arr, err := builtins.ArrayOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - startIndex, err := builtins.IntOperand(i, 2) + startIndex, err := builtins.IntOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - stopIndex, err := builtins.IntOperand(j, 3) + stopIndex, err := builtins.IntOperand(operands[2].Value, 3) if err != nil { - return nil, err + return err } // Clamp stopIndex to avoid out-of-range errors. If negative, clamp to zero. @@ -68,10 +68,10 @@ func builtinArraySlice(a, i, j ast.Value) (ast.Value, error) { startIndex = stopIndex } - return arr.Slice(startIndex, stopIndex), nil + return iter(ast.NewTerm(arr.Slice(startIndex, stopIndex))) } -func builtinArrayReverse(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { +func builtinArrayReverse(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { arr, err := builtins.ArrayOperand(operands[0].Value, 1) if err != nil { return err @@ -88,7 +88,7 @@ func builtinArrayReverse(bctx BuiltinContext, operands []*ast.Term, iter func(*a } func init() { - RegisterFunctionalBuiltin2(ast.ArrayConcat.Name, builtinArrayConcat) - RegisterFunctionalBuiltin3(ast.ArraySlice.Name, builtinArraySlice) + RegisterBuiltinFunc(ast.ArrayConcat.Name, builtinArrayConcat) + RegisterBuiltinFunc(ast.ArraySlice.Name, builtinArraySlice) RegisterBuiltinFunc(ast.ArrayReverse.Name, builtinArrayReverse) } diff --git a/topdown/binary.go b/topdown/binary.go index 3cab5def1e..b4f9dbd392 100644 --- a/topdown/binary.go +++ b/topdown/binary.go @@ -9,37 +9,37 @@ import ( "github.com/open-policy-agent/opa/topdown/builtins" ) -func builtinBinaryAnd(a ast.Value, b ast.Value) (ast.Value, error) { +func builtinBinaryAnd(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - s1, err := builtins.SetOperand(a, 1) + s1, err := builtins.SetOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - s2, err := builtins.SetOperand(b, 2) + s2, err := builtins.SetOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - return s1.Intersect(s2), nil + return iter(ast.NewTerm(s1.Intersect(s2))) } -func builtinBinaryOr(a ast.Value, b ast.Value) (ast.Value, error) { +func builtinBinaryOr(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - s1, err := builtins.SetOperand(a, 1) + s1, err := builtins.SetOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - s2, err := builtins.SetOperand(b, 2) + s2, err := builtins.SetOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - return s1.Union(s2), nil + return iter(ast.NewTerm(s1.Union(s2))) } func init() { - RegisterFunctionalBuiltin2(ast.And.Name, builtinBinaryAnd) - RegisterFunctionalBuiltin2(ast.Or.Name, builtinBinaryOr) + RegisterBuiltinFunc(ast.And.Name, builtinBinaryAnd) + RegisterBuiltinFunc(ast.Or.Name, builtinBinaryOr) } diff --git a/topdown/builtins.go b/topdown/builtins.go index 85071235f1..42e95e8cdf 100644 --- a/topdown/builtins.go +++ b/topdown/builtins.go @@ -20,16 +20,16 @@ import ( ) type ( - // FunctionalBuiltin1 is deprecated. Use BuiltinFunc instead. + // Deprecated: Functional-style builtins are deprecated. Use BuiltinFunc instead. FunctionalBuiltin1 func(op1 ast.Value) (output ast.Value, err error) - // FunctionalBuiltin2 is deprecated. Use BuiltinFunc instead. + // Deprecated: Functional-style builtins are deprecated. Use BuiltinFunc instead. FunctionalBuiltin2 func(op1, op2 ast.Value) (output ast.Value, err error) - // FunctionalBuiltin3 is deprecated. Use BuiltinFunc instead. + // Deprecated: Functional-style builtins are deprecated. Use BuiltinFunc instead. FunctionalBuiltin3 func(op1, op2, op3 ast.Value) (output ast.Value, err error) - // FunctionalBuiltin4 is deprecated. Use BuiltinFunc instead. + // Deprecated: Functional-style builtins are deprecated. Use BuiltinFunc instead. FunctionalBuiltin4 func(op1, op2, op3, op4 ast.Value) (output ast.Value, err error) // BuiltinContext contains context from the evaluator that may be used by @@ -88,22 +88,22 @@ func RegisterBuiltinFunc(name string, f BuiltinFunc) { builtinFunctions[name] = builtinErrorWrapper(name, f) } -// RegisterFunctionalBuiltin1 is deprecated use RegisterBuiltinFunc instead. +// Deprecated: Functional-style builtins are deprecated. Use RegisterBuiltinFunc instead. func RegisterFunctionalBuiltin1(name string, fun FunctionalBuiltin1) { builtinFunctions[name] = functionalWrapper1(name, fun) } -// RegisterFunctionalBuiltin2 is deprecated use RegisterBuiltinFunc instead. +// Deprecated: Functional-style builtins are deprecated. Use RegisterBuiltinFunc instead. func RegisterFunctionalBuiltin2(name string, fun FunctionalBuiltin2) { builtinFunctions[name] = functionalWrapper2(name, fun) } -// RegisterFunctionalBuiltin3 is deprecated use RegisterBuiltinFunc instead. +// Deprecated: Functional-style builtins are deprecated. Use RegisterBuiltinFunc instead. func RegisterFunctionalBuiltin3(name string, fun FunctionalBuiltin3) { builtinFunctions[name] = functionalWrapper3(name, fun) } -// RegisterFunctionalBuiltin4 is deprecated use RegisterBuiltinFunc instead. +// Deprecated: Functional-style builtins are deprecated. Use RegisterBuiltinFunc instead. func RegisterFunctionalBuiltin4(name string, fun FunctionalBuiltin4) { builtinFunctions[name] = functionalWrapper4(name, fun) } @@ -113,7 +113,7 @@ func GetBuiltin(name string) BuiltinFunc { return builtinFunctions[name] } -// BuiltinEmpty is deprecated. +// Deprecated: The BuiltinEmpty type is no longer needed. Use nil return values instead. type BuiltinEmpty struct{} func (BuiltinEmpty) Error() string { @@ -204,3 +204,17 @@ func readInt64(r io.Reader) (int64, error) { } return int64(binary.BigEndian.Uint64(bs)), nil } + +// Used to get older-style (ast.Term, error) tuples out of newer functions. +func getResult(fn BuiltinFunc, operands ...*ast.Term) (*ast.Term, error) { + var result *ast.Term + extractionFn := func(r *ast.Term) error { + result = r + return nil + } + err := fn(BuiltinContext{}, operands, extractionFn) + if err != nil { + return nil, err + } + return result, nil +} diff --git a/topdown/casts.go b/topdown/casts.go index c207bfd142..2eb8f97fc9 100644 --- a/topdown/casts.go +++ b/topdown/casts.go @@ -11,32 +11,32 @@ import ( "github.com/open-policy-agent/opa/topdown/builtins" ) -func builtinToNumber(a ast.Value) (ast.Value, error) { - switch a := a.(type) { +func builtinToNumber(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch a := operands[0].Value.(type) { case ast.Null: - return ast.Number("0"), nil + return iter(ast.NumberTerm("0")) case ast.Boolean: if a { - return ast.Number("1"), nil + return iter(ast.NumberTerm("1")) } - return ast.Number("0"), nil + return iter(ast.NumberTerm("0")) case ast.Number: - return a, nil + return iter(ast.NewTerm(a)) case ast.String: _, err := strconv.ParseFloat(string(a), 64) if err != nil { - return nil, err + return err } - return ast.Number(a), nil + return iter(ast.NewTerm(ast.Number(a))) } - return nil, builtins.NewOperandTypeErr(1, a, "null", "boolean", "number", "string") + return builtins.NewOperandTypeErr(1, operands[0].Value, "null", "boolean", "number", "string") } // Deprecated in v0.13.0. -func builtinToArray(a ast.Value) (ast.Value, error) { - switch val := a.(type) { +func builtinToArray(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch val := operands[0].Value.(type) { case *ast.Array: - return val, nil + return iter(ast.NewTerm(val)) case ast.Set: arr := make([]*ast.Term, val.Len()) i := 0 @@ -44,74 +44,74 @@ func builtinToArray(a ast.Value) (ast.Value, error) { arr[i] = term i++ }) - return ast.NewArray(arr...), nil + return iter(ast.NewTerm(ast.NewArray(arr...))) default: - return nil, builtins.NewOperandTypeErr(1, a, "array", "set") + return builtins.NewOperandTypeErr(1, operands[0].Value, "array", "set") } } // Deprecated in v0.13.0. -func builtinToSet(a ast.Value) (ast.Value, error) { - switch val := a.(type) { +func builtinToSet(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch val := operands[0].Value.(type) { case *ast.Array: s := ast.NewSet() val.Foreach(func(v *ast.Term) { s.Add(v) }) - return s, nil + return iter(ast.NewTerm(s)) case ast.Set: - return val, nil + return iter(ast.NewTerm(val)) default: - return nil, builtins.NewOperandTypeErr(1, a, "array", "set") + return builtins.NewOperandTypeErr(1, operands[0].Value, "array", "set") } } // Deprecated in v0.13.0. -func builtinToString(a ast.Value) (ast.Value, error) { - switch val := a.(type) { +func builtinToString(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch val := operands[0].Value.(type) { case ast.String: - return val, nil + return iter(ast.NewTerm(val)) default: - return nil, builtins.NewOperandTypeErr(1, a, "string") + return builtins.NewOperandTypeErr(1, operands[0].Value, "string") } } // Deprecated in v0.13.0. -func builtinToBoolean(a ast.Value) (ast.Value, error) { - switch val := a.(type) { +func builtinToBoolean(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch val := operands[0].Value.(type) { case ast.Boolean: - return val, nil + return iter(ast.NewTerm(val)) default: - return nil, builtins.NewOperandTypeErr(1, a, "boolean") + return builtins.NewOperandTypeErr(1, operands[0].Value, "boolean") } } // Deprecated in v0.13.0. -func builtinToNull(a ast.Value) (ast.Value, error) { - switch val := a.(type) { +func builtinToNull(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch val := operands[0].Value.(type) { case ast.Null: - return val, nil + return iter(ast.NewTerm(val)) default: - return nil, builtins.NewOperandTypeErr(1, a, "null") + return builtins.NewOperandTypeErr(1, operands[0].Value, "null") } } // Deprecated in v0.13.0. -func builtinToObject(a ast.Value) (ast.Value, error) { - switch val := a.(type) { +func builtinToObject(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch val := operands[0].Value.(type) { case ast.Object: - return val, nil + return iter(ast.NewTerm(val)) default: - return nil, builtins.NewOperandTypeErr(1, a, "object") + return builtins.NewOperandTypeErr(1, operands[0].Value, "object") } } func init() { - RegisterFunctionalBuiltin1(ast.ToNumber.Name, builtinToNumber) - RegisterFunctionalBuiltin1(ast.CastArray.Name, builtinToArray) - RegisterFunctionalBuiltin1(ast.CastSet.Name, builtinToSet) - RegisterFunctionalBuiltin1(ast.CastString.Name, builtinToString) - RegisterFunctionalBuiltin1(ast.CastBoolean.Name, builtinToBoolean) - RegisterFunctionalBuiltin1(ast.CastNull.Name, builtinToNull) - RegisterFunctionalBuiltin1(ast.CastObject.Name, builtinToObject) + RegisterBuiltinFunc(ast.ToNumber.Name, builtinToNumber) + RegisterBuiltinFunc(ast.CastArray.Name, builtinToArray) + RegisterBuiltinFunc(ast.CastSet.Name, builtinToSet) + RegisterBuiltinFunc(ast.CastString.Name, builtinToString) + RegisterBuiltinFunc(ast.CastBoolean.Name, builtinToBoolean) + RegisterBuiltinFunc(ast.CastNull.Name, builtinToNull) + RegisterBuiltinFunc(ast.CastObject.Name, builtinToObject) } diff --git a/topdown/cidr.go b/topdown/cidr.go index e203021799..a54ba83425 100644 --- a/topdown/cidr.go +++ b/topdown/cidr.go @@ -61,44 +61,44 @@ func getLastIP(cidr *net.IPNet) (net.IP, error) { return lastIP, nil } -func builtinNetCIDRIntersects(a, b ast.Value) (ast.Value, error) { - cidrnetA, err := getNetFromOperand(a) +func builtinNetCIDRIntersects(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + cidrnetA, err := getNetFromOperand(operands[0].Value) if err != nil { - return nil, err + return err } - cidrnetB, err := getNetFromOperand(b) + cidrnetB, err := getNetFromOperand(operands[1].Value) if err != nil { - return nil, err + return err } // If either net contains the others starting IP they are overlapping cidrsOverlap := cidrnetA.Contains(cidrnetB.IP) || cidrnetB.Contains(cidrnetA.IP) - return ast.Boolean(cidrsOverlap), nil + return iter(ast.BooleanTerm(cidrsOverlap)) } -func builtinNetCIDRContains(a, b ast.Value) (ast.Value, error) { - cidrnetA, err := getNetFromOperand(a) +func builtinNetCIDRContains(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + cidrnetA, err := getNetFromOperand(operands[0].Value) if err != nil { - return nil, err + return err } // b could be either an IP addressor CIDR string, try to parse it as an IP first, fall back to CIDR - bStr, err := builtins.StringOperand(b, 1) + bStr, err := builtins.StringOperand(operands[1].Value, 1) if err != nil { - return nil, err + return err } ip := net.ParseIP(string(bStr)) if ip != nil { - return ast.Boolean(cidrnetA.Contains(ip)), nil + return iter(ast.BooleanTerm(cidrnetA.Contains(ip))) } // It wasn't an IP, try and parse it as a CIDR - cidrnetB, err := getNetFromOperand(b) + cidrnetB, err := getNetFromOperand(operands[1].Value) if err != nil { - return nil, fmt.Errorf("not a valid textual representation of an IP address or CIDR: %s", string(bStr)) + return fmt.Errorf("not a valid textual representation of an IP address or CIDR: %s", string(bStr)) } // We can determine if cidr A contains cidr B if and only if A contains @@ -108,12 +108,12 @@ func builtinNetCIDRContains(a, b ast.Value) (ast.Value, error) { // Only spend time calculating the last IP if the starting IP is already verified to be in cidr A lastIP, err := getLastIP(cidrnetB) if err != nil { - return nil, err + return err } cidrContained = cidrnetA.Contains(lastIP) } - return ast.Boolean(cidrContained), nil + return iter(ast.BooleanTerm(cidrContained)) } var errNetCIDRContainsMatchElementType = errors.New("element must be string or non-empty array") @@ -167,13 +167,13 @@ func evalNetCIDRContainsMatchesOperand(operand int, a *ast.Term, iter func(cidr, return nil } -func builtinNetCIDRContainsMatches(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinNetCIDRContainsMatches(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { result := ast.NewSet() - err := evalNetCIDRContainsMatchesOperand(1, args[0], func(cidr1 *ast.Term, index1 *ast.Term) error { - return evalNetCIDRContainsMatchesOperand(2, args[1], func(cidr2 *ast.Term, index2 *ast.Term) error { - if v, err := builtinNetCIDRContains(cidr1.Value, cidr2.Value); err != nil { + err := evalNetCIDRContainsMatchesOperand(1, operands[0], func(cidr1 *ast.Term, index1 *ast.Term) error { + return evalNetCIDRContainsMatchesOperand(2, operands[1], func(cidr2 *ast.Term, index2 *ast.Term) error { + if v, err := getResult(builtinNetCIDRContains, cidr1, cidr2); err != nil { return err - } else if vb, ok := v.(ast.Boolean); ok && bool(vb) { + } else if vb, ok := v.Value.(ast.Boolean); ok && bool(vb) { result.Add(ast.ArrayTerm(index1, index2)) } return nil @@ -257,7 +257,7 @@ func (c cidrBlockRanges) Less(i, j int) bool { // builtinNetCIDRMerge merges the provided list of IP addresses and subnets into the smallest possible list of CIDRs. // It merges adjacent subnets where possible, those contained within others and also removes any duplicates. // Original Algorithm: https://github.com/netaddr/netaddr. -func builtinNetCIDRMerge(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { +func builtinNetCIDRMerge(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { networks := []*net.IPNet{} switch v := operands[0].Value.(type) { @@ -396,9 +396,9 @@ func incIP(ip net.IP) { } func init() { - RegisterFunctionalBuiltin2(ast.NetCIDROverlap.Name, builtinNetCIDRContains) - RegisterFunctionalBuiltin2(ast.NetCIDRIntersects.Name, builtinNetCIDRIntersects) - RegisterFunctionalBuiltin2(ast.NetCIDRContains.Name, builtinNetCIDRContains) + RegisterBuiltinFunc(ast.NetCIDROverlap.Name, builtinNetCIDRContains) + RegisterBuiltinFunc(ast.NetCIDRIntersects.Name, builtinNetCIDRIntersects) + RegisterBuiltinFunc(ast.NetCIDRContains.Name, builtinNetCIDRContains) RegisterBuiltinFunc(ast.NetCIDRContainsMatches.Name, builtinNetCIDRContainsMatches) RegisterBuiltinFunc(ast.NetCIDRExpand.Name, builtinNetCIDRExpand) RegisterBuiltinFunc(ast.NetCIDRMerge.Name, builtinNetCIDRMerge) diff --git a/topdown/comparison.go b/topdown/comparison.go index 96be984ac4..0d033d2c32 100644 --- a/topdown/comparison.go +++ b/topdown/comparison.go @@ -32,17 +32,17 @@ func compareEq(a, b ast.Value) bool { return ast.Compare(a, b) == 0 } -func builtinCompare(cmp compareFunc) FunctionalBuiltin2 { - return func(a, b ast.Value) (ast.Value, error) { - return ast.Boolean(cmp(a, b)), nil +func builtinCompare(cmp compareFunc) BuiltinFunc { + return func(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + return iter(ast.BooleanTerm(cmp(operands[0].Value, operands[1].Value))) } } func init() { - RegisterFunctionalBuiltin2(ast.GreaterThan.Name, builtinCompare(compareGreaterThan)) - RegisterFunctionalBuiltin2(ast.GreaterThanEq.Name, builtinCompare(compareGreaterThanEq)) - RegisterFunctionalBuiltin2(ast.LessThan.Name, builtinCompare(compareLessThan)) - RegisterFunctionalBuiltin2(ast.LessThanEq.Name, builtinCompare(compareLessThanEq)) - RegisterFunctionalBuiltin2(ast.NotEqual.Name, builtinCompare(compareNotEq)) - RegisterFunctionalBuiltin2(ast.Equal.Name, builtinCompare(compareEq)) + RegisterBuiltinFunc(ast.GreaterThan.Name, builtinCompare(compareGreaterThan)) + RegisterBuiltinFunc(ast.GreaterThanEq.Name, builtinCompare(compareGreaterThanEq)) + RegisterBuiltinFunc(ast.LessThan.Name, builtinCompare(compareLessThan)) + RegisterBuiltinFunc(ast.LessThanEq.Name, builtinCompare(compareLessThanEq)) + RegisterBuiltinFunc(ast.NotEqual.Name, builtinCompare(compareNotEq)) + RegisterBuiltinFunc(ast.Equal.Name, builtinCompare(compareEq)) } diff --git a/topdown/crypto.go b/topdown/crypto.go index 2b5a96eaff..4eb8c0a8f4 100644 --- a/topdown/crypto.go +++ b/topdown/crypto.go @@ -42,24 +42,28 @@ const ( blockTypePrivateKey = "PRIVATE KEY" ) -func builtinCryptoX509ParseCertificates(a ast.Value) (ast.Value, error) { - input, err := builtins.StringOperand(a, 1) +func builtinCryptoX509ParseCertificates(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + input, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } certs, err := getX509CertsFromString(string(input)) if err != nil { - return nil, err + return err } - return ast.InterfaceToValue(certs) + v, err := ast.InterfaceToValue(certs) + if err != nil { + return err + } + + return iter(ast.NewTerm(v)) } -func builtinCryptoX509ParseAndVerifyCertificates( - _ BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinCryptoX509ParseAndVerifyCertificates(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - a := args[0].Value + a := operands[0].Value input, err := builtins.StringOperand(a, 1) if err != nil { return err @@ -93,11 +97,10 @@ func builtinCryptoX509ParseAndVerifyCertificates( return iter(valid) } -func builtinCryptoX509ParseCertificateRequest(a ast.Value) (ast.Value, error) { - - input, err := builtins.StringOperand(a, 1) +func builtinCryptoX509ParseCertificateRequest(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + input, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } // data to be passed to x509.ParseCertificateRequest @@ -107,13 +110,13 @@ func builtinCryptoX509ParseCertificateRequest(a ast.Value) (ast.Value, error) { if str := string(input); !strings.HasPrefix(str, "-----BEGIN CERTIFICATE REQUEST-----") { bytes, err = base64.StdEncoding.DecodeString(str) if err != nil { - return nil, err + return err } } p, _ := pem.Decode(bytes) if p != nil && p.Type != blockTypeCertificateRequest { - return nil, fmt.Errorf("invalid PEM-encoded certificate signing request") + return fmt.Errorf("invalid PEM-encoded certificate signing request") } if p != nil { bytes = p.Bytes @@ -121,24 +124,30 @@ func builtinCryptoX509ParseCertificateRequest(a ast.Value) (ast.Value, error) { csr, err := x509.ParseCertificateRequest(bytes) if err != nil { - return nil, err + return err } bs, err := json.Marshal(csr) if err != nil { - return nil, err + return err } var x interface{} if err := util.UnmarshalJSON(bs, &x); err != nil { - return nil, err + return err } - return ast.InterfaceToValue(x) + + v, err := ast.InterfaceToValue(x) + if err != nil { + return err + } + + return iter(ast.NewTerm(v)) } -func builtinCryptoX509ParseRSAPrivateKey(_ BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinCryptoX509ParseRSAPrivateKey(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - a := args[0].Value + a := operands[0].Value input, err := builtins.StringOperand(a, 1) if err != nil { return err @@ -181,26 +190,38 @@ func hashHelper(a ast.Value, h func(ast.String) string) (ast.Value, error) { return ast.String(h(s)), nil } -func builtinCryptoMd5(a ast.Value) (ast.Value, error) { - return hashHelper(a, func(s ast.String) string { return fmt.Sprintf("%x", md5.Sum([]byte(s))) }) +func builtinCryptoMd5(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + res, err := hashHelper(operands[0].Value, func(s ast.String) string { return fmt.Sprintf("%x", md5.Sum([]byte(s))) }) + if err != nil { + return err + } + return iter(ast.NewTerm(res)) } -func builtinCryptoSha1(a ast.Value) (ast.Value, error) { - return hashHelper(a, func(s ast.String) string { return fmt.Sprintf("%x", sha1.Sum([]byte(s))) }) +func builtinCryptoSha1(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + res, err := hashHelper(operands[0].Value, func(s ast.String) string { return fmt.Sprintf("%x", sha1.Sum([]byte(s))) }) + if err != nil { + return err + } + return iter(ast.NewTerm(res)) } -func builtinCryptoSha256(a ast.Value) (ast.Value, error) { - return hashHelper(a, func(s ast.String) string { return fmt.Sprintf("%x", sha256.Sum256([]byte(s))) }) +func builtinCryptoSha256(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + res, err := hashHelper(operands[0].Value, func(s ast.String) string { return fmt.Sprintf("%x", sha256.Sum256([]byte(s))) }) + if err != nil { + return err + } + return iter(ast.NewTerm(res)) } -func hmacHelper(args []*ast.Term, iter func(*ast.Term) error, h func() hash.Hash) error { - a1 := args[0].Value +func hmacHelper(operands []*ast.Term, iter func(*ast.Term) error, h func() hash.Hash) error { + a1 := operands[0].Value message, err := builtins.StringOperand(a1, 1) if err != nil { return err } - a2 := args[1].Value + a2 := operands[1].Value key, err := builtins.StringOperand(a2, 2) if err != nil { return err @@ -213,29 +234,29 @@ func hmacHelper(args []*ast.Term, iter func(*ast.Term) error, h func() hash.Hash return iter(ast.StringTerm(fmt.Sprintf("%x", messageDigest))) } -func builtinCryptoHmacMd5(_ BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - return hmacHelper(args, iter, md5.New) +func builtinCryptoHmacMd5(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + return hmacHelper(operands, iter, md5.New) } -func builtinCryptoHmacSha1(_ BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - return hmacHelper(args, iter, sha1.New) +func builtinCryptoHmacSha1(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + return hmacHelper(operands, iter, sha1.New) } -func builtinCryptoHmacSha256(_ BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - return hmacHelper(args, iter, sha256.New) +func builtinCryptoHmacSha256(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + return hmacHelper(operands, iter, sha256.New) } -func builtinCryptoHmacSha512(_ BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - return hmacHelper(args, iter, sha512.New) +func builtinCryptoHmacSha512(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + return hmacHelper(operands, iter, sha512.New) } func init() { - RegisterFunctionalBuiltin1(ast.CryptoX509ParseCertificates.Name, builtinCryptoX509ParseCertificates) + RegisterBuiltinFunc(ast.CryptoX509ParseCertificates.Name, builtinCryptoX509ParseCertificates) RegisterBuiltinFunc(ast.CryptoX509ParseAndVerifyCertificates.Name, builtinCryptoX509ParseAndVerifyCertificates) - RegisterFunctionalBuiltin1(ast.CryptoMd5.Name, builtinCryptoMd5) - RegisterFunctionalBuiltin1(ast.CryptoSha1.Name, builtinCryptoSha1) - RegisterFunctionalBuiltin1(ast.CryptoSha256.Name, builtinCryptoSha256) - RegisterFunctionalBuiltin1(ast.CryptoX509ParseCertificateRequest.Name, builtinCryptoX509ParseCertificateRequest) + RegisterBuiltinFunc(ast.CryptoMd5.Name, builtinCryptoMd5) + RegisterBuiltinFunc(ast.CryptoSha1.Name, builtinCryptoSha1) + RegisterBuiltinFunc(ast.CryptoSha256.Name, builtinCryptoSha256) + RegisterBuiltinFunc(ast.CryptoX509ParseCertificateRequest.Name, builtinCryptoX509ParseCertificateRequest) RegisterBuiltinFunc(ast.CryptoX509ParseRSAPrivateKey.Name, builtinCryptoX509ParseRSAPrivateKey) RegisterBuiltinFunc(ast.CryptoHmacMd5.Name, builtinCryptoHmacMd5) RegisterBuiltinFunc(ast.CryptoHmacSha1.Name, builtinCryptoHmacSha1) diff --git a/topdown/encoding.go b/topdown/encoding.go index fa9b197121..f2129d8cd0 100644 --- a/topdown/encoding.go +++ b/topdown/encoding.go @@ -20,97 +20,103 @@ import ( "github.com/open-policy-agent/opa/util" ) -func builtinJSONMarshal(a ast.Value) (ast.Value, error) { +func builtinJSONMarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - asJSON, err := ast.JSON(a) + asJSON, err := ast.JSON(operands[0].Value) if err != nil { - return nil, err + return err } bs, err := json.Marshal(asJSON) if err != nil { - return nil, err + return err } - return ast.String(string(bs)), nil + return iter(ast.StringTerm(string(bs))) } -func builtinJSONUnmarshal(a ast.Value) (ast.Value, error) { +func builtinJSONUnmarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - str, err := builtins.StringOperand(a, 1) + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } var x interface{} if err := util.UnmarshalJSON([]byte(str), &x); err != nil { - return nil, err + return err } - - return ast.InterfaceToValue(x) + v, err := ast.InterfaceToValue(x) + if err != nil { + return err + } + return iter(ast.NewTerm(v)) } -func builtinJSONIsValid(a ast.Value) (ast.Value, error) { +func builtinJSONIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - str, err := builtins.StringOperand(a, 1) + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return ast.Boolean(false), nil + return iter(ast.BooleanTerm(false)) } - return ast.Boolean(json.Valid([]byte(str))), nil + return iter(ast.BooleanTerm(json.Valid([]byte(str)))) } -func builtinBase64Encode(a ast.Value) (ast.Value, error) { - str, err := builtins.StringOperand(a, 1) +func builtinBase64Encode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - return ast.String(base64.StdEncoding.EncodeToString([]byte(str))), nil + return iter(ast.StringTerm(base64.StdEncoding.EncodeToString([]byte(str)))) } -func builtinBase64Decode(a ast.Value) (ast.Value, error) { - str, err := builtins.StringOperand(a, 1) +func builtinBase64Decode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } result, err := base64.StdEncoding.DecodeString(string(str)) - return ast.String(result), err + if err != nil { + return err + } + return iter(ast.NewTerm(ast.String(result))) } -func builtinBase64IsValid(a ast.Value) (ast.Value, error) { - str, err := builtins.StringOperand(a, 1) +func builtinBase64IsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return ast.Boolean(false), nil + return iter(ast.BooleanTerm(false)) } _, err = base64.StdEncoding.DecodeString(string(str)) - return ast.Boolean(err == nil), nil + return iter(ast.BooleanTerm(err == nil)) } -func builtinBase64UrlEncode(a ast.Value) (ast.Value, error) { - str, err := builtins.StringOperand(a, 1) +func builtinBase64UrlEncode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - return ast.String(base64.URLEncoding.EncodeToString([]byte(str))), nil + return iter(ast.StringTerm(base64.URLEncoding.EncodeToString([]byte(str)))) } -func builtinBase64UrlEncodeNoPad(a ast.Value) (ast.Value, error) { - str, err := builtins.StringOperand(a, 1) +func builtinBase64UrlEncodeNoPad(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - return ast.String(base64.RawURLEncoding.EncodeToString([]byte(str))), nil + return iter(ast.StringTerm(base64.RawURLEncoding.EncodeToString([]byte(str)))) } -func builtinBase64UrlDecode(a ast.Value) (ast.Value, error) { - str, err := builtins.StringOperand(a, 1) +func builtinBase64UrlDecode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } s := string(str) @@ -125,44 +131,47 @@ func builtinBase64UrlDecode(a ast.Value) (ast.Value, error) { case 3: s += "=" default: - return nil, fmt.Errorf("illegal base64url string: %s", s) + return fmt.Errorf("illegal base64url string: %s", s) } } result, err := base64.URLEncoding.DecodeString(s) - return ast.String(result), err -} - -func builtinURLQueryEncode(a ast.Value) (ast.Value, error) { - str, err := builtins.StringOperand(a, 1) if err != nil { - return nil, err + return err } - return ast.String(url.QueryEscape(string(str))), nil + return iter(ast.NewTerm(ast.String(result))) } -func builtinURLQueryDecode(a ast.Value) (ast.Value, error) { - str, err := builtins.StringOperand(a, 1) +func builtinURLQueryEncode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err + } + return iter(ast.StringTerm(url.QueryEscape(string(str)))) +} + +func builtinURLQueryDecode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + str, err := builtins.StringOperand(operands[0].Value, 1) + if err != nil { + return err } s, err := url.QueryUnescape(string(str)) if err != nil { - return nil, err + return err } - return ast.String(s), nil + return iter(ast.StringTerm(s)) } var encodeObjectErr = builtins.NewOperandErr(1, "values must be string, array[string], or set[string]") -func builtinURLQueryEncodeObject(a ast.Value) (ast.Value, error) { - asJSON, err := ast.JSON(a) +func builtinURLQueryEncodeObject(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + asJSON, err := ast.JSON(operands[0].Value) if err != nil { - return nil, err + return err } inputs, ok := asJSON.(map[string]interface{}) if !ok { - return nil, builtins.NewOperandTypeErr(1, a, "object") + return builtins.NewOperandTypeErr(1, operands[0].Value, "object") } query := url.Values{} @@ -175,19 +184,19 @@ func builtinURLQueryEncodeObject(a ast.Value) (ast.Value, error) { for _, val := range vv { strVal, ok := val.(string) if !ok { - return nil, encodeObjectErr + return encodeObjectErr } query.Add(k, strVal) } default: - return nil, encodeObjectErr + return encodeObjectErr } } - return ast.String(query.Encode()), nil + return iter(ast.StringTerm(query.Encode())) } -func builtinURLQueryDecodeObject(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { +func builtinURLQueryDecodeObject(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { query, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { return err @@ -210,37 +219,37 @@ func builtinURLQueryDecodeObject(bctx BuiltinContext, operands []*ast.Term, iter return iter(ast.NewTerm(queryObject)) } -func builtinYAMLMarshal(a ast.Value) (ast.Value, error) { +func builtinYAMLMarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - asJSON, err := ast.JSON(a) + asJSON, err := ast.JSON(operands[0].Value) if err != nil { - return nil, err + return err } var buf bytes.Buffer encoder := json.NewEncoder(&buf) if err := encoder.Encode(asJSON); err != nil { - return nil, err + return err } bs, err := ghodss.JSONToYAML(buf.Bytes()) if err != nil { - return nil, err + return err } - return ast.String(string(bs)), nil + return iter(ast.StringTerm(string(bs))) } -func builtinYAMLUnmarshal(a ast.Value) (ast.Value, error) { +func builtinYAMLUnmarshal(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - str, err := builtins.StringOperand(a, 1) + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } bs, err := ghodss.YAMLToJSON([]byte(str)) if err != nil { - return nil, err + return err } buf := bytes.NewBuffer(bs) @@ -248,60 +257,63 @@ func builtinYAMLUnmarshal(a ast.Value) (ast.Value, error) { var val interface{} err = decoder.Decode(&val) if err != nil { - return nil, err + return err } - - return ast.InterfaceToValue(val) + v, err := ast.InterfaceToValue(val) + if err != nil { + return err + } + return iter(ast.NewTerm(v)) } -func builtinYAMLIsValid(a ast.Value) (ast.Value, error) { - str, err := builtins.StringOperand(a, 1) +func builtinYAMLIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return ast.Boolean(false), nil + return iter(ast.BooleanTerm(false)) } var x interface{} err = ghodss.Unmarshal([]byte(str), &x) - return ast.Boolean(err == nil), nil + return iter(ast.BooleanTerm(err == nil)) } -func builtinHexEncode(a ast.Value) (ast.Value, error) { - str, err := builtins.StringOperand(a, 1) +func builtinHexEncode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - return ast.String(hex.EncodeToString([]byte(str))), nil + return iter(ast.StringTerm(hex.EncodeToString([]byte(str)))) } -func builtinHexDecode(a ast.Value) (ast.Value, error) { - str, err := builtins.StringOperand(a, 1) +func builtinHexDecode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } val, err := hex.DecodeString(string(str)) if err != nil { - return nil, err + return err } - return ast.String(val), nil + return iter(ast.NewTerm(ast.String(val))) } func init() { - RegisterFunctionalBuiltin1(ast.JSONMarshal.Name, builtinJSONMarshal) - RegisterFunctionalBuiltin1(ast.JSONUnmarshal.Name, builtinJSONUnmarshal) - RegisterFunctionalBuiltin1(ast.JSONIsValid.Name, builtinJSONIsValid) - RegisterFunctionalBuiltin1(ast.Base64Encode.Name, builtinBase64Encode) - RegisterFunctionalBuiltin1(ast.Base64Decode.Name, builtinBase64Decode) - RegisterFunctionalBuiltin1(ast.Base64IsValid.Name, builtinBase64IsValid) - RegisterFunctionalBuiltin1(ast.Base64UrlEncode.Name, builtinBase64UrlEncode) - RegisterFunctionalBuiltin1(ast.Base64UrlEncodeNoPad.Name, builtinBase64UrlEncodeNoPad) - RegisterFunctionalBuiltin1(ast.Base64UrlDecode.Name, builtinBase64UrlDecode) - RegisterFunctionalBuiltin1(ast.URLQueryDecode.Name, builtinURLQueryDecode) - RegisterFunctionalBuiltin1(ast.URLQueryEncode.Name, builtinURLQueryEncode) - RegisterFunctionalBuiltin1(ast.URLQueryEncodeObject.Name, builtinURLQueryEncodeObject) + RegisterBuiltinFunc(ast.JSONMarshal.Name, builtinJSONMarshal) + RegisterBuiltinFunc(ast.JSONUnmarshal.Name, builtinJSONUnmarshal) + RegisterBuiltinFunc(ast.JSONIsValid.Name, builtinJSONIsValid) + RegisterBuiltinFunc(ast.Base64Encode.Name, builtinBase64Encode) + RegisterBuiltinFunc(ast.Base64Decode.Name, builtinBase64Decode) + RegisterBuiltinFunc(ast.Base64IsValid.Name, builtinBase64IsValid) + RegisterBuiltinFunc(ast.Base64UrlEncode.Name, builtinBase64UrlEncode) + RegisterBuiltinFunc(ast.Base64UrlEncodeNoPad.Name, builtinBase64UrlEncodeNoPad) + RegisterBuiltinFunc(ast.Base64UrlDecode.Name, builtinBase64UrlDecode) + RegisterBuiltinFunc(ast.URLQueryDecode.Name, builtinURLQueryDecode) + RegisterBuiltinFunc(ast.URLQueryEncode.Name, builtinURLQueryEncode) + RegisterBuiltinFunc(ast.URLQueryEncodeObject.Name, builtinURLQueryEncodeObject) RegisterBuiltinFunc(ast.URLQueryDecodeObject.Name, builtinURLQueryDecodeObject) - RegisterFunctionalBuiltin1(ast.YAMLMarshal.Name, builtinYAMLMarshal) - RegisterFunctionalBuiltin1(ast.YAMLUnmarshal.Name, builtinYAMLUnmarshal) - RegisterFunctionalBuiltin1(ast.YAMLIsValid.Name, builtinYAMLIsValid) - RegisterFunctionalBuiltin1(ast.HexEncode.Name, builtinHexEncode) - RegisterFunctionalBuiltin1(ast.HexDecode.Name, builtinHexDecode) + RegisterBuiltinFunc(ast.YAMLMarshal.Name, builtinYAMLMarshal) + RegisterBuiltinFunc(ast.YAMLUnmarshal.Name, builtinYAMLUnmarshal) + RegisterBuiltinFunc(ast.YAMLIsValid.Name, builtinYAMLIsValid) + RegisterBuiltinFunc(ast.HexEncode.Name, builtinHexEncode) + RegisterBuiltinFunc(ast.HexDecode.Name, builtinHexDecode) } diff --git a/topdown/glob.go b/topdown/glob.go index e22cda44fd..5bdb7e2565 100644 --- a/topdown/glob.go +++ b/topdown/glob.go @@ -13,30 +13,30 @@ import ( var globCacheLock = sync.Mutex{} var globCache map[string]glob.Glob -func builtinGlobMatch(a, b, c ast.Value) (ast.Value, error) { - pattern, err := builtins.StringOperand(a, 1) +func builtinGlobMatch(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + pattern, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } var delimiters []rune - switch b.(type) { + switch operands[1].Value.(type) { case ast.Null: delimiters = []rune{} case *ast.Array: - delimiters, err = builtins.RuneSliceOperand(b, 2) + delimiters, err = builtins.RuneSliceOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - if len(delimiters) == 0 { delimiters = []rune{'.'} } default: - return nil, builtins.NewOperandTypeErr(2, b, "array", "null") + return builtins.NewOperandTypeErr(2, operands[1].Value, "array", "null") } - match, err := builtins.StringOperand(c, 3) + match, err := builtins.StringOperand(operands[2].Value, 3) + if err != nil { - return nil, err + return err } builder := strings.Builder{} @@ -53,26 +53,26 @@ func builtinGlobMatch(a, b, c ast.Value) (ast.Value, error) { if !ok { var err error if p, err = glob.Compile(string(pattern), delimiters...); err != nil { - return nil, err + return err } globCache[id] = p } m := p.Match(string(match)) - return ast.Boolean(m), nil + return iter(ast.BooleanTerm(m)) } -func builtinGlobQuoteMeta(a ast.Value) (ast.Value, error) { - pattern, err := builtins.StringOperand(a, 1) +func builtinGlobQuoteMeta(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + pattern, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - return ast.String(glob.QuoteMeta(string(pattern))), nil + return iter(ast.StringTerm(glob.QuoteMeta(string(pattern)))) } func init() { globCache = map[string]glob.Glob{} - RegisterFunctionalBuiltin3(ast.GlobMatch.Name, builtinGlobMatch) - RegisterFunctionalBuiltin1(ast.GlobQuoteMeta.Name, builtinGlobQuoteMeta) + RegisterBuiltinFunc(ast.GlobMatch.Name, builtinGlobMatch) + RegisterBuiltinFunc(ast.GlobQuoteMeta.Name, builtinGlobQuoteMeta) } diff --git a/topdown/http.go b/topdown/http.go index 810ac7412f..6734f7a437 100644 --- a/topdown/http.go +++ b/topdown/http.go @@ -90,8 +90,8 @@ const ( HTTPSendNetworkErr string = "eval_http_send_network_error" ) -func builtinHTTPSend(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - req, err := validateHTTPRequestOperand(args[0], 1) +func builtinHTTPSend(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + req, err := validateHTTPRequestOperand(operands[0], 1) if err != nil { return handleBuiltinErr(ast.HTTPSend.Name, bctx.Location, err) } diff --git a/topdown/numbers.go b/topdown/numbers.go index 9d57c8790a..b0953b0fdb 100644 --- a/topdown/numbers.go +++ b/topdown/numbers.go @@ -56,15 +56,15 @@ func builtinNumbersRange(bctx BuiltinContext, operands []*ast.Term, iter func(*a return iter(ast.NewTerm(result)) } -func builtinRandIntn(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinRandIntn(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - strOp, err := builtins.StringOperand(args[0].Value, 1) + strOp, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { return err } - n, err := builtins.IntOperand(args[1].Value, 2) + n, err := builtins.IntOperand(operands[1].Value, 2) if err != nil { return err } diff --git a/topdown/parse.go b/topdown/parse.go index df12cbc905..c46222b413 100644 --- a/topdown/parse.go +++ b/topdown/parse.go @@ -13,34 +13,34 @@ import ( "github.com/open-policy-agent/opa/topdown/builtins" ) -func builtinRegoParseModule(a, b ast.Value) (ast.Value, error) { +func builtinRegoParseModule(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - filename, err := builtins.StringOperand(a, 1) + filename, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - input, err := builtins.StringOperand(b, 1) + input, err := builtins.StringOperand(operands[1].Value, 1) if err != nil { - return nil, err + return err } module, err := ast.ParseModule(string(filename), string(input)) if err != nil { - return nil, err + return err } var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(module); err != nil { - return nil, err + return err } term, err := ast.ParseTerm(buf.String()) if err != nil { - return nil, err + return err } - return term.Value, nil + return iter(term) } func registerRegoMetadataBuiltinFunction(builtin *ast.Builtin) { @@ -53,7 +53,7 @@ func registerRegoMetadataBuiltinFunction(builtin *ast.Builtin) { } func init() { - RegisterFunctionalBuiltin2(ast.RegoParseModule.Name, builtinRegoParseModule) + RegisterBuiltinFunc(ast.RegoParseModule.Name, builtinRegoParseModule) registerRegoMetadataBuiltinFunction(ast.RegoMetadataChain) registerRegoMetadataBuiltinFunction(ast.RegoMetadataRule) } diff --git a/topdown/reachable.go b/topdown/reachable.go index a212d22144..a950eb0501 100644 --- a/topdown/reachable.go +++ b/topdown/reachable.go @@ -31,15 +31,15 @@ func numberOfEdges(collection *ast.Term) int { return 0 } -func builtinReachable(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinReachable(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { // Error on wrong types for args. - graph, err := builtins.ObjectOperand(args[0].Value, 1) + graph, err := builtins.ObjectOperand(operands[0].Value, 1) if err != nil { return err } var queue []*ast.Term - switch initial := args[1].Value.(type) { + switch initial := operands[1].Value.(type) { case *ast.Array, ast.Set: foreachVertex(ast.NewTerm(initial), func(t *ast.Term) { queue = append(queue, t) @@ -98,9 +98,9 @@ func pathBuilder(graph ast.Object, root *ast.Term, path []*ast.Term, paths []*as return paths } -func builtinReachablePaths(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - // Error on wrong types for args. - graph, err := builtins.ObjectOperand(args[0].Value, 1) +func builtinReachablePaths(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + // Return an error if the first argument is not an object. + graph, err := builtins.ObjectOperand(operands[0].Value, 1) if err != nil { return err } @@ -108,7 +108,7 @@ func builtinReachablePaths(bctx BuiltinContext, args []*ast.Term, iter func(*ast // This is a queue that holds all nodes we still need to visit. It is // initialised to the initial set of nodes we start out with. var queue []*ast.Term - switch initial := args[1].Value.(type) { + switch initial := operands[1].Value.(type) { case *ast.Array, ast.Set: foreachVertex(ast.NewTerm(initial), func(t *ast.Term) { queue = append(queue, t) diff --git a/topdown/regex.go b/topdown/regex.go index 53197626f7..8afe1c41bc 100644 --- a/topdown/regex.go +++ b/topdown/regex.go @@ -33,64 +33,64 @@ func builtinRegexIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast. return iter(ast.BooleanTerm(true)) } -func builtinRegexMatch(a, b ast.Value) (ast.Value, error) { - s1, err := builtins.StringOperand(a, 1) +func builtinRegexMatch(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s1, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - s2, err := builtins.StringOperand(b, 2) + s2, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } re, err := getRegexp(string(s1)) if err != nil { - return nil, err + return err } - return ast.Boolean(re.Match([]byte(s2))), nil + return iter(ast.BooleanTerm(re.Match([]byte(s2)))) } -func builtinRegexMatchTemplate(a, b, c, d ast.Value) (ast.Value, error) { - pattern, err := builtins.StringOperand(a, 1) +func builtinRegexMatchTemplate(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + pattern, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - match, err := builtins.StringOperand(b, 2) + match, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - start, err := builtins.StringOperand(c, 3) + start, err := builtins.StringOperand(operands[2].Value, 3) if err != nil { - return nil, err + return err } - end, err := builtins.StringOperand(d, 4) + end, err := builtins.StringOperand(operands[3].Value, 4) if err != nil { - return nil, err + return err } if len(start) != 1 { - return nil, fmt.Errorf("start delimiter has to be exactly one character long but is %d long", len(start)) + return fmt.Errorf("start delimiter has to be exactly one character long but is %d long", len(start)) } if len(end) != 1 { - return nil, fmt.Errorf("end delimiter has to be exactly one character long but is %d long", len(start)) + return fmt.Errorf("end delimiter has to be exactly one character long but is %d long", len(start)) } re, err := getRegexpTemplate(string(pattern), string(start)[0], string(end)[0]) if err != nil { - return nil, err + return err } - return ast.Boolean(re.MatchString(string(match))), nil + return iter(ast.BooleanTerm(re.MatchString(string(match)))) } -func builtinRegexSplit(a, b ast.Value) (ast.Value, error) { - s1, err := builtins.StringOperand(a, 1) +func builtinRegexSplit(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s1, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - s2, err := builtins.StringOperand(b, 2) + s2, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } re, err := getRegexp(string(s1)) if err != nil { - return nil, err + return err } elems := re.Split(string(s2), -1) @@ -98,7 +98,7 @@ func builtinRegexSplit(a, b ast.Value) (ast.Value, error) { for i := range elems { arr[i] = ast.StringTerm(elems[i]) } - return ast.NewArray(arr...), nil + return iter(ast.NewTerm(ast.NewArray(arr...))) } func getRegexp(pat string) (*regexp.Regexp, error) { @@ -131,38 +131,38 @@ func getRegexpTemplate(pat string, delimStart, delimEnd byte) (*regexp.Regexp, e return re, nil } -func builtinGlobsMatch(a, b ast.Value) (ast.Value, error) { - s1, err := builtins.StringOperand(a, 1) +func builtinGlobsMatch(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s1, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - s2, err := builtins.StringOperand(b, 2) + s2, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } ne, err := gintersect.NonEmpty(string(s1), string(s2)) if err != nil { - return nil, err + return err } - return ast.Boolean(ne), nil + return iter(ast.BooleanTerm(ne)) } -func builtinRegexFind(a, b, c ast.Value) (ast.Value, error) { - s1, err := builtins.StringOperand(a, 1) +func builtinRegexFind(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s1, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - s2, err := builtins.StringOperand(b, 2) + s2, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - n, err := builtins.IntOperand(c, 3) + n, err := builtins.IntOperand(operands[2].Value, 3) if err != nil { - return nil, err + return err } re, err := getRegexp(string(s1)) if err != nil { - return nil, err + return err } elems := re.FindAllString(string(s2), n) @@ -170,26 +170,26 @@ func builtinRegexFind(a, b, c ast.Value) (ast.Value, error) { for i := range elems { arr[i] = ast.StringTerm(elems[i]) } - return ast.NewArray(arr...), nil + return iter(ast.NewTerm(ast.NewArray(arr...))) } -func builtinRegexFindAllStringSubmatch(a, b, c ast.Value) (ast.Value, error) { - s1, err := builtins.StringOperand(a, 1) +func builtinRegexFindAllStringSubmatch(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s1, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - s2, err := builtins.StringOperand(b, 2) + s2, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - n, err := builtins.IntOperand(c, 3) + n, err := builtins.IntOperand(operands[2].Value, 3) if err != nil { - return nil, err + return err } re, err := getRegexp(string(s1)) if err != nil { - return nil, err + return err } matches := re.FindAllStringSubmatch(string(s2), n) @@ -202,7 +202,7 @@ func builtinRegexFindAllStringSubmatch(a, b, c ast.Value) (ast.Value, error) { outer[i] = ast.NewTerm(ast.NewArray(inner...)) } - return ast.NewArray(outer...), nil + return iter(ast.NewTerm(ast.NewArray(outer...))) } func builtinRegexReplace(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { @@ -234,12 +234,12 @@ func builtinRegexReplace(_ BuiltinContext, operands []*ast.Term, iter func(*ast. func init() { regexpCache = map[string]*regexp.Regexp{} RegisterBuiltinFunc(ast.RegexIsValid.Name, builtinRegexIsValid) - RegisterFunctionalBuiltin2(ast.RegexMatch.Name, builtinRegexMatch) - RegisterFunctionalBuiltin2(ast.RegexMatchDeprecated.Name, builtinRegexMatch) - RegisterFunctionalBuiltin2(ast.RegexSplit.Name, builtinRegexSplit) - RegisterFunctionalBuiltin2(ast.GlobsMatch.Name, builtinGlobsMatch) - RegisterFunctionalBuiltin4(ast.RegexTemplateMatch.Name, builtinRegexMatchTemplate) - RegisterFunctionalBuiltin3(ast.RegexFind.Name, builtinRegexFind) - RegisterFunctionalBuiltin3(ast.RegexFindAllStringSubmatch.Name, builtinRegexFindAllStringSubmatch) + RegisterBuiltinFunc(ast.RegexMatch.Name, builtinRegexMatch) + RegisterBuiltinFunc(ast.RegexMatchDeprecated.Name, builtinRegexMatch) + RegisterBuiltinFunc(ast.RegexSplit.Name, builtinRegexSplit) + RegisterBuiltinFunc(ast.GlobsMatch.Name, builtinGlobsMatch) + RegisterBuiltinFunc(ast.RegexTemplateMatch.Name, builtinRegexMatchTemplate) + RegisterBuiltinFunc(ast.RegexFind.Name, builtinRegexFind) + RegisterBuiltinFunc(ast.RegexFindAllStringSubmatch.Name, builtinRegexFindAllStringSubmatch) RegisterBuiltinFunc(ast.RegexReplace.Name, builtinRegexReplace) } diff --git a/topdown/semver.go b/topdown/semver.go index 20c02d2365..ab5aed3eec 100644 --- a/topdown/semver.go +++ b/topdown/semver.go @@ -12,13 +12,13 @@ import ( "github.com/open-policy-agent/opa/topdown/builtins" ) -func builtinSemVerCompare(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - versionStringA, err := builtins.StringOperand(args[0].Value, 1) +func builtinSemVerCompare(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + versionStringA, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { return err } - versionStringB, err := builtins.StringOperand(args[1].Value, 2) + versionStringB, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { return err } @@ -37,8 +37,8 @@ func builtinSemVerCompare(bctx BuiltinContext, args []*ast.Term, iter func(*ast. return iter(ast.IntNumberTerm(result)) } -func builtinSemVerIsValid(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - versionString, err := builtins.StringOperand(args[0].Value, 1) +func builtinSemVerIsValid(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + versionString, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { return iter(ast.BooleanTerm(false)) } diff --git a/topdown/sets.go b/topdown/sets.go index cb0b1d7d37..a973404f3f 100644 --- a/topdown/sets.go +++ b/topdown/sets.go @@ -10,32 +10,32 @@ import ( ) // Deprecated in v0.4.2 in favour of minus/infix "-" operation. -func builtinSetDiff(a, b ast.Value) (ast.Value, error) { +func builtinSetDiff(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - s1, err := builtins.SetOperand(a, 1) + s1, err := builtins.SetOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - s2, err := builtins.SetOperand(b, 2) + s2, err := builtins.SetOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - return s1.Diff(s2), nil + return iter(ast.NewTerm(s1.Diff(s2))) } // builtinSetIntersection returns the intersection of the given input sets -func builtinSetIntersection(a ast.Value) (ast.Value, error) { +func builtinSetIntersection(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - inputSet, err := builtins.SetOperand(a, 1) + inputSet, err := builtins.SetOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } // empty input set if inputSet.Len() == 0 { - return ast.NewSet(), nil + return iter(ast.NewTerm(ast.NewSet())) } var result ast.Set @@ -53,20 +53,23 @@ func builtinSetIntersection(a ast.Value) (ast.Value, error) { } return nil }) - return result, err + if err != nil { + return err + } + return iter(ast.NewTerm(result)) } // builtinSetUnion returns the union of the given input sets -func builtinSetUnion(a ast.Value) (ast.Value, error) { +func builtinSetUnion(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { // The set union logic here is duplicated and manually inlined on // purpose. By lifting this logic up a level, and not doing pairwise // set unions, we avoid a number of heap allocations. This improves // performance dramatically over the naive approach. result := ast.NewSet() - inputSet, err := builtins.SetOperand(a, 1) + inputSet, err := builtins.SetOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } err = inputSet.Iter(func(x *ast.Term) error { @@ -77,12 +80,15 @@ func builtinSetUnion(a ast.Value) (ast.Value, error) { item.Foreach(result.Add) return nil }) + if err != nil { + return err + } - return result, err + return iter(ast.NewTerm(result)) } func init() { - RegisterFunctionalBuiltin2(ast.SetDiff.Name, builtinSetDiff) - RegisterFunctionalBuiltin1(ast.Intersection.Name, builtinSetIntersection) - RegisterFunctionalBuiltin1(ast.Union.Name, builtinSetUnion) + RegisterBuiltinFunc(ast.SetDiff.Name, builtinSetDiff) + RegisterBuiltinFunc(ast.Intersection.Name, builtinSetIntersection) + RegisterBuiltinFunc(ast.Union.Name, builtinSetUnion) } diff --git a/topdown/sets_test.go b/topdown/sets_test.go index 2b93302661..c999bb004a 100644 --- a/topdown/sets_test.go +++ b/topdown/sets_test.go @@ -48,7 +48,7 @@ func TestSetUnionBuiltin(t *testing.T) { for _, tc := range tests { inputs := ast.MustParseTerm(tc.input) - result, err := getResult(functionalWrapper1("union", builtinSetUnion), inputs) + result, err := getResult(builtinSetUnion, inputs) if err != nil { t.Fatal(err) } @@ -59,17 +59,3 @@ func TestSetUnionBuiltin(t *testing.T) { } } } - -// Used to get older-style (ast.Term, error) tuples out of newer functions. -func getResult(fn BuiltinFunc, operands ...*ast.Term) (*ast.Term, error) { - var result *ast.Term - extractionFn := func(r *ast.Term) error { - result = r - return nil - } - err := fn(BuiltinContext{}, operands, extractionFn) - if err != nil { - return nil, err - } - return result, nil -} diff --git a/topdown/strings.go b/topdown/strings.go index 1a3d3d564c..4a59bf7dd3 100644 --- a/topdown/strings.go +++ b/topdown/strings.go @@ -112,16 +112,16 @@ func anyStartsWithAny(strs []string, prefixes []string) bool { return false } -func builtinFormatInt(a, b ast.Value) (ast.Value, error) { +func builtinFormatInt(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - input, err := builtins.NumberOperand(a, 1) + input, err := builtins.NumberOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - base, err := builtins.NumberOperand(b, 2) + base, err := builtins.NumberOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } var format string @@ -135,54 +135,54 @@ func builtinFormatInt(a, b ast.Value) (ast.Value, error) { case ast.Number("16"): format = "%x" default: - return nil, builtins.NewOperandEnumErr(2, "2", "8", "10", "16") + return builtins.NewOperandEnumErr(2, "2", "8", "10", "16") } f := builtins.NumberToFloat(input) i, _ := f.Int(nil) - return ast.String(fmt.Sprintf(format, i)), nil + return iter(ast.StringTerm(fmt.Sprintf(format, i))) } -func builtinConcat(a, b ast.Value) (ast.Value, error) { +func builtinConcat(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - join, err := builtins.StringOperand(a, 1) + join, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } strs := []string{} - switch b := b.(type) { + switch b := operands[1].Value.(type) { case *ast.Array: err := b.Iter(func(x *ast.Term) error { s, ok := x.Value.(ast.String) if !ok { - return builtins.NewOperandElementErr(2, b, x.Value, "string") + return builtins.NewOperandElementErr(2, operands[1].Value, x.Value, "string") } strs = append(strs, string(s)) return nil }) if err != nil { - return nil, err + return err } case ast.Set: err := b.Iter(func(x *ast.Term) error { s, ok := x.Value.(ast.String) if !ok { - return builtins.NewOperandElementErr(2, b, x.Value, "string") + return builtins.NewOperandElementErr(2, operands[1].Value, x.Value, "string") } strs = append(strs, string(s)) return nil }) if err != nil { - return nil, err + return err } default: - return nil, builtins.NewOperandTypeErr(2, b, "set", "array") + return builtins.NewOperandTypeErr(2, operands[1].Value, "set", "array") } - return ast.String(strings.Join(strs, string(join))), nil + return iter(ast.StringTerm(strings.Join(strs, string(join)))) } func runesEqual(a, b []rune) bool { @@ -197,18 +197,18 @@ func runesEqual(a, b []rune) bool { return true } -func builtinIndexOf(a, b ast.Value) (ast.Value, error) { - base, err := builtins.StringOperand(a, 1) +func builtinIndexOf(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + base, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - search, err := builtins.StringOperand(b, 2) + search, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } if len(string(search)) == 0 { - return nil, fmt.Errorf("empty search character") + return fmt.Errorf("empty search character") } baseRunes := []rune(string(base)) @@ -218,28 +218,28 @@ func builtinIndexOf(a, b ast.Value) (ast.Value, error) { for i, r := range baseRunes { if len(baseRunes) >= i+searchLen { if r == searchRunes[0] && runesEqual(baseRunes[i:i+searchLen], searchRunes) { - return ast.IntNumberTerm(i).Value, nil + return iter(ast.IntNumberTerm(i)) } } else { break } } - return ast.IntNumberTerm(-1).Value, nil + return iter(ast.IntNumberTerm(-1)) } -func builtinIndexOfN(a, b ast.Value) (ast.Value, error) { - base, err := builtins.StringOperand(a, 1) +func builtinIndexOfN(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + base, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - search, err := builtins.StringOperand(b, 2) + search, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } if len(string(search)) == 0 { - return nil, fmt.Errorf("empty search character") + return fmt.Errorf("empty search character") } baseRunes := []rune(string(base)) @@ -257,29 +257,29 @@ func builtinIndexOfN(a, b ast.Value) (ast.Value, error) { } } - return ast.NewArray(arr...), nil + return iter(ast.ArrayTerm(arr...)) } -func builtinSubstring(a, b, c ast.Value) (ast.Value, error) { +func builtinSubstring(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - base, err := builtins.StringOperand(a, 1) + base, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } runes := []rune(base) - startIndex, err := builtins.IntOperand(b, 2) + startIndex, err := builtins.IntOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } else if startIndex >= len(runes) { - return ast.String(""), nil + return iter(ast.StringTerm("")) } else if startIndex < 0 { - return nil, fmt.Errorf("negative offset") + return fmt.Errorf("negative offset") } - length, err := builtins.IntOperand(c, 3) + length, err := builtins.IntOperand(operands[2].Value, 3) if err != nil { - return nil, err + return err } var s ast.String @@ -293,229 +293,229 @@ func builtinSubstring(a, b, c ast.Value) (ast.Value, error) { s = ast.String(runes[startIndex:upto]) } - return s, nil + return iter(ast.NewTerm(s)) } -func builtinContains(a, b ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinContains(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - substr, err := builtins.StringOperand(b, 2) + substr, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - return ast.Boolean(strings.Contains(string(s), string(substr))), nil + return iter(ast.BooleanTerm(strings.Contains(string(s), string(substr)))) } -func builtinStartsWith(a, b ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinStartsWith(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - prefix, err := builtins.StringOperand(b, 2) + prefix, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - return ast.Boolean(strings.HasPrefix(string(s), string(prefix))), nil + return iter(ast.BooleanTerm(strings.HasPrefix(string(s), string(prefix)))) } -func builtinEndsWith(a, b ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinEndsWith(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - suffix, err := builtins.StringOperand(b, 2) + suffix, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - return ast.Boolean(strings.HasSuffix(string(s), string(suffix))), nil + return iter(ast.BooleanTerm(strings.HasSuffix(string(s), string(suffix)))) } -func builtinLower(a ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinLower(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - return ast.String(strings.ToLower(string(s))), nil + return iter(ast.StringTerm(strings.ToLower(string(s)))) } -func builtinUpper(a ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinUpper(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - return ast.String(strings.ToUpper(string(s))), nil + return iter(ast.StringTerm(strings.ToUpper(string(s)))) } -func builtinSplit(a, b ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinSplit(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - d, err := builtins.StringOperand(b, 2) + d, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } elems := strings.Split(string(s), string(d)) arr := make([]*ast.Term, len(elems)) for i := range elems { arr[i] = ast.StringTerm(elems[i]) } - return ast.NewArray(arr...), nil + return iter(ast.ArrayTerm(arr...)) } -func builtinReplace(a, b, c ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinReplace(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - old, err := builtins.StringOperand(b, 2) + old, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - new, err := builtins.StringOperand(c, 3) + new, err := builtins.StringOperand(operands[2].Value, 3) if err != nil { - return nil, err + return err } - return ast.String(strings.Replace(string(s), string(old), string(new), -1)), nil + return iter(ast.StringTerm(strings.Replace(string(s), string(old), string(new), -1))) } -func builtinReplaceN(a, b ast.Value) (ast.Value, error) { - patterns, err := builtins.ObjectOperand(a, 1) +func builtinReplaceN(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + patterns, err := builtins.ObjectOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } keys := patterns.Keys() sort.Slice(keys, func(i, j int) bool { return ast.Compare(keys[i].Value, keys[j].Value) < 0 }) - s, err := builtins.StringOperand(b, 2) + s, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } oldnewArr := make([]string, 0, len(keys)*2) for _, k := range keys { keyVal, ok := k.Value.(ast.String) if !ok { - return nil, builtins.NewOperandErr(1, "non-string key found in pattern object") + return builtins.NewOperandErr(1, "non-string key found in pattern object") } val := patterns.Get(k) // cannot be nil strVal, ok := val.Value.(ast.String) if !ok { - return nil, builtins.NewOperandErr(1, "non-string value found in pattern object") + return builtins.NewOperandErr(1, "non-string value found in pattern object") } oldnewArr = append(oldnewArr, string(keyVal), string(strVal)) } if err != nil { - return nil, err + return err } r := strings.NewReplacer(oldnewArr...) replaced := r.Replace(string(s)) - return ast.String(replaced), nil + return iter(ast.StringTerm(replaced)) } -func builtinTrim(a, b ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinTrim(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - c, err := builtins.StringOperand(b, 2) + c, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - return ast.String(strings.Trim(string(s), string(c))), nil + return iter(ast.StringTerm(strings.Trim(string(s), string(c)))) } -func builtinTrimLeft(a, b ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinTrimLeft(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - c, err := builtins.StringOperand(b, 2) + c, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - return ast.String(strings.TrimLeft(string(s), string(c))), nil + return iter(ast.StringTerm(strings.TrimLeft(string(s), string(c)))) } -func builtinTrimPrefix(a, b ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinTrimPrefix(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - pre, err := builtins.StringOperand(b, 2) + pre, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - return ast.String(strings.TrimPrefix(string(s), string(pre))), nil + return iter(ast.StringTerm(strings.TrimPrefix(string(s), string(pre)))) } -func builtinTrimRight(a, b ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinTrimRight(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - c, err := builtins.StringOperand(b, 2) + c, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - return ast.String(strings.TrimRight(string(s), string(c))), nil + return iter(ast.StringTerm(strings.TrimRight(string(s), string(c)))) } -func builtinTrimSuffix(a, b ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinTrimSuffix(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - suf, err := builtins.StringOperand(b, 2) + suf, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { - return nil, err + return err } - return ast.String(strings.TrimSuffix(string(s), string(suf))), nil + return iter(ast.StringTerm(strings.TrimSuffix(string(s), string(suf)))) } -func builtinTrimSpace(a ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinTrimSpace(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - return ast.String(strings.TrimSpace(string(s))), nil + return iter(ast.StringTerm(strings.TrimSpace(string(s)))) } -func builtinSprintf(a, b ast.Value) (ast.Value, error) { - s, err := builtins.StringOperand(a, 1) +func builtinSprintf(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } - astArr, ok := b.(*ast.Array) + astArr, ok := operands[1].Value.(*ast.Array) if !ok { - return nil, builtins.NewOperandTypeErr(2, b, "array") + return builtins.NewOperandTypeErr(2, operands[1].Value, "array") } args := make([]interface{}, astArr.Len()) @@ -539,10 +539,10 @@ func builtinSprintf(a, b ast.Value) (ast.Value, error) { } } - return ast.String(fmt.Sprintf(string(s), args...)), nil + return iter(ast.StringTerm(fmt.Sprintf(string(s), args...))) } -func builtinReverse(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { +func builtinReverse(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { s, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { return err @@ -564,26 +564,26 @@ func reverseString(str string) string { } func init() { - RegisterFunctionalBuiltin2(ast.FormatInt.Name, builtinFormatInt) - RegisterFunctionalBuiltin2(ast.Concat.Name, builtinConcat) - RegisterFunctionalBuiltin2(ast.IndexOf.Name, builtinIndexOf) - RegisterFunctionalBuiltin2(ast.IndexOfN.Name, builtinIndexOfN) - RegisterFunctionalBuiltin3(ast.Substring.Name, builtinSubstring) - RegisterFunctionalBuiltin2(ast.Contains.Name, builtinContains) - RegisterFunctionalBuiltin2(ast.StartsWith.Name, builtinStartsWith) - RegisterFunctionalBuiltin2(ast.EndsWith.Name, builtinEndsWith) - RegisterFunctionalBuiltin1(ast.Upper.Name, builtinUpper) - RegisterFunctionalBuiltin1(ast.Lower.Name, builtinLower) - RegisterFunctionalBuiltin2(ast.Split.Name, builtinSplit) - RegisterFunctionalBuiltin3(ast.Replace.Name, builtinReplace) - RegisterFunctionalBuiltin2(ast.ReplaceN.Name, builtinReplaceN) - RegisterFunctionalBuiltin2(ast.Trim.Name, builtinTrim) - RegisterFunctionalBuiltin2(ast.TrimLeft.Name, builtinTrimLeft) - RegisterFunctionalBuiltin2(ast.TrimPrefix.Name, builtinTrimPrefix) - RegisterFunctionalBuiltin2(ast.TrimRight.Name, builtinTrimRight) - RegisterFunctionalBuiltin2(ast.TrimSuffix.Name, builtinTrimSuffix) - RegisterFunctionalBuiltin1(ast.TrimSpace.Name, builtinTrimSpace) - RegisterFunctionalBuiltin2(ast.Sprintf.Name, builtinSprintf) + RegisterBuiltinFunc(ast.FormatInt.Name, builtinFormatInt) + RegisterBuiltinFunc(ast.Concat.Name, builtinConcat) + RegisterBuiltinFunc(ast.IndexOf.Name, builtinIndexOf) + RegisterBuiltinFunc(ast.IndexOfN.Name, builtinIndexOfN) + RegisterBuiltinFunc(ast.Substring.Name, builtinSubstring) + RegisterBuiltinFunc(ast.Contains.Name, builtinContains) + RegisterBuiltinFunc(ast.StartsWith.Name, builtinStartsWith) + RegisterBuiltinFunc(ast.EndsWith.Name, builtinEndsWith) + RegisterBuiltinFunc(ast.Upper.Name, builtinUpper) + RegisterBuiltinFunc(ast.Lower.Name, builtinLower) + RegisterBuiltinFunc(ast.Split.Name, builtinSplit) + RegisterBuiltinFunc(ast.Replace.Name, builtinReplace) + RegisterBuiltinFunc(ast.ReplaceN.Name, builtinReplaceN) + RegisterBuiltinFunc(ast.Trim.Name, builtinTrim) + RegisterBuiltinFunc(ast.TrimLeft.Name, builtinTrimLeft) + RegisterBuiltinFunc(ast.TrimPrefix.Name, builtinTrimPrefix) + RegisterBuiltinFunc(ast.TrimRight.Name, builtinTrimRight) + RegisterBuiltinFunc(ast.TrimSuffix.Name, builtinTrimSuffix) + RegisterBuiltinFunc(ast.TrimSpace.Name, builtinTrimSpace) + RegisterBuiltinFunc(ast.Sprintf.Name, builtinSprintf) RegisterBuiltinFunc(ast.AnyPrefixMatch.Name, builtinAnyPrefixMatch) RegisterBuiltinFunc(ast.AnySuffixMatch.Name, builtinAnySuffixMatch) RegisterBuiltinFunc(ast.StringReverse.Name, builtinReverse) diff --git a/topdown/time.go b/topdown/time.go index 481326dade..bcaa1c55f6 100644 --- a/topdown/time.go +++ b/topdown/time.go @@ -39,14 +39,12 @@ func builtinTimeNowNanos(bctx BuiltinContext, _ []*ast.Term, iter func(*ast.Term } func builtinTimeParseNanos(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - a := operands[0].Value - format, err := builtins.StringOperand(a, 1) + format, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { return err } - b := operands[1].Value - value, err := builtins.StringOperand(b, 2) + value, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { return err } @@ -60,8 +58,7 @@ func builtinTimeParseNanos(_ BuiltinContext, operands []*ast.Term, iter func(*as } func builtinTimeParseRFC3339Nanos(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - a := operands[0].Value - value, err := builtins.StringOperand(a, 1) + value, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { return err } @@ -73,46 +70,45 @@ func builtinTimeParseRFC3339Nanos(_ BuiltinContext, operands []*ast.Term, iter f return toSafeUnixNano(result, iter) } -func builtinParseDurationNanos(a ast.Value) (ast.Value, error) { - - duration, err := builtins.StringOperand(a, 1) +func builtinParseDurationNanos(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + duration, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { - return nil, err + return err } value, err := time.ParseDuration(string(duration)) if err != nil { - return nil, err + return err } - return ast.Number(int64ToJSONNumber(int64(value))), nil + return iter(ast.NumberTerm(int64ToJSONNumber(int64(value)))) } -func builtinDate(a ast.Value) (ast.Value, error) { - t, err := tzTime(a) +func builtinDate(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + t, err := tzTime(operands[0].Value) if err != nil { - return nil, err + return err } year, month, day := t.Date() result := ast.NewArray(ast.IntNumberTerm(year), ast.IntNumberTerm(int(month)), ast.IntNumberTerm(day)) - return result, nil + return iter(ast.NewTerm(result)) } -func builtinClock(a ast.Value) (ast.Value, error) { - t, err := tzTime(a) +func builtinClock(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + t, err := tzTime(operands[0].Value) if err != nil { - return nil, err + return err } hour, minute, second := t.Clock() result := ast.NewArray(ast.IntNumberTerm(hour), ast.IntNumberTerm(minute), ast.IntNumberTerm(second)) - return result, nil + return iter(ast.NewTerm(result)) } -func builtinWeekday(a ast.Value) (ast.Value, error) { - t, err := tzTime(a) +func builtinWeekday(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + t, err := tzTime(operands[0].Value) if err != nil { - return nil, err + return err } weekday := t.Weekday().String() - return ast.String(weekday), nil + return iter(ast.StringTerm(weekday)) } func builtinAddDate(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { @@ -286,10 +282,10 @@ func init() { RegisterBuiltinFunc(ast.NowNanos.Name, builtinTimeNowNanos) RegisterBuiltinFunc(ast.ParseRFC3339Nanos.Name, builtinTimeParseRFC3339Nanos) RegisterBuiltinFunc(ast.ParseNanos.Name, builtinTimeParseNanos) - RegisterFunctionalBuiltin1(ast.ParseDurationNanos.Name, builtinParseDurationNanos) - RegisterFunctionalBuiltin1(ast.Date.Name, builtinDate) - RegisterFunctionalBuiltin1(ast.Clock.Name, builtinClock) - RegisterFunctionalBuiltin1(ast.Weekday.Name, builtinWeekday) + RegisterBuiltinFunc(ast.ParseDurationNanos.Name, builtinParseDurationNanos) + RegisterBuiltinFunc(ast.Date.Name, builtinDate) + RegisterBuiltinFunc(ast.Clock.Name, builtinClock) + RegisterBuiltinFunc(ast.Weekday.Name, builtinWeekday) RegisterBuiltinFunc(ast.AddDate.Name, builtinAddDate) RegisterBuiltinFunc(ast.Diff.Name, builtinDiff) tzCacheMutex = &sync.Mutex{} diff --git a/topdown/tokens.go b/topdown/tokens.go index 5309cd0be6..3670665544 100644 --- a/topdown/tokens.go +++ b/topdown/tokens.go @@ -52,11 +52,11 @@ type JSONWebToken struct { // decodeHeader populates the decodedHeader field. func (token *JSONWebToken) decodeHeader() error { - h, err := builtinBase64UrlDecode(ast.String(token.header)) + result, err := getResult(builtinBase64UrlDecode, ast.StringTerm(token.header)) if err != nil { return fmt.Errorf("JWT header had invalid encoding: %w", err) } - decodedHeader, err := validateJWTHeader(string(h.(ast.String))) + decodedHeader, err := validateJWTHeader(string(result.Value.(ast.String))) if err != nil { return err } @@ -69,19 +69,19 @@ func (token *JSONWebToken) decodeHeader() error { // It does no data validation, it merely checks that the given string // represents a structurally valid JWT. It supports JWTs using JWS compact // serialization. -func builtinJWTDecode(a ast.Value) (ast.Value, error) { - token, err := decodeJWT(a) +func builtinJWTDecode(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + token, err := decodeJWT(operands[0].Value) if err != nil { - return nil, err + return err } if err = token.decodeHeader(); err != nil { - return nil, err + return err } - p, err := builtinBase64UrlDecode(ast.String(token.payload)) + p, err := getResult(builtinBase64UrlDecode, ast.StringTerm(token.payload)) if err != nil { - return nil, fmt.Errorf("JWT payload had invalid encoding: %v", err) + return fmt.Errorf("JWT payload had invalid encoding: %v", err) } if cty := token.decodedHeader.Get(jwtCtyKey); cty != nil { @@ -95,24 +95,28 @@ func builtinJWTDecode(a ast.Value) (ast.Value, error) { // contents are quoted (behavior of https://jwt.io/). To fix // this, remove leading and trailing quotes. if ctyVal == headerJwt { - p, err = builtinTrim(p, ast.String(`"'`)) + p, err = getResult(builtinTrim, p, ast.StringTerm(`"'`)) if err != nil { panic("not reached") } - return builtinJWTDecode(p) + result, err := getResult(builtinJWTDecode, p) + if err != nil { + return err + } + return iter(result) } } - payload, err := extractJSONObject(string(p.(ast.String))) + payload, err := extractJSONObject(string(p.Value.(ast.String))) if err != nil { - return nil, err + return err } - s, err := builtinBase64UrlDecode(ast.String(token.signature)) + s, err := getResult(builtinBase64UrlDecode, ast.StringTerm(token.signature)) if err != nil { - return nil, fmt.Errorf("JWT signature had invalid encoding: %v", err) + return fmt.Errorf("JWT signature had invalid encoding: %v", err) } - sign := hex.EncodeToString([]byte(s.(ast.String))) + sign := hex.EncodeToString([]byte(s.Value.(ast.String))) arr := []*ast.Term{ ast.NewTerm(token.decodedHeader), @@ -120,12 +124,12 @@ func builtinJWTDecode(a ast.Value) (ast.Value, error) { ast.StringTerm(sign), } - return ast.NewArray(arr...), nil + return iter(ast.ArrayTerm(arr...)) } // Implements RS256 JWT signature verification -func builtinJWTVerifyRS256(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - result, err := builtinJWTVerifyRSA(args[0].Value, args[1].Value, sha256.New, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { +func builtinJWTVerifyRS256(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerifyRSA(operands[0].Value, operands[1].Value, sha256.New, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { return rsa.VerifyPKCS1v15( publicKey, crypto.SHA256, @@ -139,8 +143,8 @@ func builtinJWTVerifyRS256(bctx BuiltinContext, args []*ast.Term, iter func(*ast } // Implements RS384 JWT signature verification -func builtinJWTVerifyRS384(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - result, err := builtinJWTVerifyRSA(args[0].Value, args[1].Value, sha512.New384, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { +func builtinJWTVerifyRS384(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerifyRSA(operands[0].Value, operands[1].Value, sha512.New384, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { return rsa.VerifyPKCS1v15( publicKey, crypto.SHA384, @@ -154,8 +158,8 @@ func builtinJWTVerifyRS384(bctx BuiltinContext, args []*ast.Term, iter func(*ast } // Implements RS512 JWT signature verification -func builtinJWTVerifyRS512(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - result, err := builtinJWTVerifyRSA(args[0].Value, args[1].Value, sha512.New, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { +func builtinJWTVerifyRS512(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerifyRSA(operands[0].Value, operands[1].Value, sha512.New, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { return rsa.VerifyPKCS1v15( publicKey, crypto.SHA512, @@ -169,8 +173,8 @@ func builtinJWTVerifyRS512(bctx BuiltinContext, args []*ast.Term, iter func(*ast } // Implements PS256 JWT signature verification -func builtinJWTVerifyPS256(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - result, err := builtinJWTVerifyRSA(args[0].Value, args[1].Value, sha256.New, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { +func builtinJWTVerifyPS256(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerifyRSA(operands[0].Value, operands[1].Value, sha256.New, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { return rsa.VerifyPSS( publicKey, crypto.SHA256, @@ -185,8 +189,8 @@ func builtinJWTVerifyPS256(bctx BuiltinContext, args []*ast.Term, iter func(*ast } // Implements PS384 JWT signature verification -func builtinJWTVerifyPS384(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - result, err := builtinJWTVerifyRSA(args[0].Value, args[1].Value, sha512.New384, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { +func builtinJWTVerifyPS384(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerifyRSA(operands[0].Value, operands[1].Value, sha512.New384, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { return rsa.VerifyPSS( publicKey, crypto.SHA384, @@ -201,8 +205,8 @@ func builtinJWTVerifyPS384(bctx BuiltinContext, args []*ast.Term, iter func(*ast } // Implements PS512 JWT signature verification -func builtinJWTVerifyPS512(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - result, err := builtinJWTVerifyRSA(args[0].Value, args[1].Value, sha512.New, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { +func builtinJWTVerifyPS512(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerifyRSA(operands[0].Value, operands[1].Value, sha512.New, func(publicKey *rsa.PublicKey, digest []byte, signature []byte) error { return rsa.VerifyPSS( publicKey, crypto.SHA512, @@ -228,8 +232,8 @@ func builtinJWTVerifyRSA(a ast.Value, b ast.Value, hasher func() hash.Hash, veri } // Implements ES256 JWT signature verification. -func builtinJWTVerifyES256(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - result, err := builtinJWTVerify(args[0].Value, args[1].Value, sha256.New, verifyES) +func builtinJWTVerifyES256(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerify(operands[0].Value, operands[1].Value, sha256.New, verifyES) if err == nil { return iter(ast.NewTerm(result)) } @@ -237,8 +241,8 @@ func builtinJWTVerifyES256(bctx BuiltinContext, args []*ast.Term, iter func(*ast } // Implements ES384 JWT signature verification -func builtinJWTVerifyES384(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - result, err := builtinJWTVerify(args[0].Value, args[1].Value, sha512.New384, verifyES) +func builtinJWTVerifyES384(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerify(operands[0].Value, operands[1].Value, sha512.New384, verifyES) if err == nil { return iter(ast.NewTerm(result)) } @@ -246,8 +250,8 @@ func builtinJWTVerifyES384(bctx BuiltinContext, args []*ast.Term, iter func(*ast } // Implements ES512 JWT signature verification -func builtinJWTVerifyES512(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - result, err := builtinJWTVerify(args[0].Value, args[1].Value, sha512.New, verifyES) +func builtinJWTVerifyES512(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerify(operands[0].Value, operands[1].Value, sha512.New, verifyES) if err == nil { return iter(ast.NewTerm(result)) } @@ -408,15 +412,15 @@ func builtinJWTVerify(a ast.Value, b ast.Value, hasher func() hash.Hash, verify } // Implements HS256 (secret) JWT signature verification -func builtinJWTVerifyHS256(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinJWTVerifyHS256(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { // Decode the JSON Web Token - token, err := decodeJWT(args[0].Value) + token, err := decodeJWT(operands[0].Value) if err != nil { return err } // Process Secret input - astSecret, err := builtins.StringOperand(args[1].Value, 2) + astSecret, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { return err } @@ -437,15 +441,15 @@ func builtinJWTVerifyHS256(bctx BuiltinContext, args []*ast.Term, iter func(*ast } // Implements HS384 JWT signature verification -func builtinJWTVerifyHS384(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinJWTVerifyHS384(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { // Decode the JSON Web Token - token, err := decodeJWT(args[0].Value) + token, err := decodeJWT(operands[0].Value) if err != nil { return err } // Process Secret input - astSecret, err := builtins.StringOperand(args[1].Value, 2) + astSecret, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { return err } @@ -466,15 +470,15 @@ func builtinJWTVerifyHS384(bctx BuiltinContext, args []*ast.Term, iter func(*ast } // Implements HS512 JWT signature verification -func builtinJWTVerifyHS512(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinJWTVerifyHS512(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { // Decode the JSON Web Token - token, err := decodeJWT(args[0].Value) + token, err := decodeJWT(operands[0].Value) if err != nil { return err } // Process Secret input - astSecret, err := builtins.StringOperand(args[1].Value, 2) + astSecret, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { return err } @@ -945,26 +949,26 @@ func commonBuiltinJWTEncodeSign(bctx BuiltinContext, inputHeaders, jwsPayload, j } -func builtinJWTEncodeSign(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinJWTEncodeSign(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - inputHeaders := args[0].String() - jwsPayload := args[1].String() - jwkSrc := args[2].String() + inputHeaders := operands[0].String() + jwsPayload := operands[1].String() + jwkSrc := operands[2].String() return commonBuiltinJWTEncodeSign(bctx, inputHeaders, jwsPayload, jwkSrc, iter) } -func builtinJWTEncodeSignRaw(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinJWTEncodeSignRaw(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - jwkSrc, err := builtins.StringOperand(args[2].Value, 3) + jwkSrc, err := builtins.StringOperand(operands[2].Value, 3) if err != nil { return err } - inputHeaders, err := builtins.StringOperand(args[0].Value, 1) + inputHeaders, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { return err } - jwsPayload, err := builtins.StringOperand(args[1].Value, 2) + jwsPayload, err := builtins.StringOperand(operands[1].Value, 2) if err != nil { return err } @@ -972,7 +976,7 @@ func builtinJWTEncodeSignRaw(bctx BuiltinContext, args []*ast.Term, iter func(*a } // Implements full JWT decoding, validation and verification. -func builtinJWTDecodeVerify(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinJWTDecodeVerify(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { // io.jwt.decode_verify(string, constraints, [valid, header, payload]) // // If valid is true then the signature verifies and all constraints are met. @@ -980,9 +984,9 @@ func builtinJWTDecodeVerify(bctx BuiltinContext, args []*ast.Term, iter func(*as // was not met. // // Decoding errors etc are returned as errors. - a := args[0].Value + a := operands[0].Value - b, err := builtins.ObjectOperand(args[1].Value, 2) + b, err := builtins.ObjectOperand(operands[1].Value, 2) if err != nil { return err } @@ -1000,7 +1004,7 @@ func builtinJWTDecodeVerify(bctx BuiltinContext, args []*ast.Term, iter func(*as return err } var token *JSONWebToken - var p ast.Value + var p *ast.Term for { // RFC7519 7.2 #1-2 split into parts if token, err = decodeJWT(a); err != nil { @@ -1034,21 +1038,21 @@ func builtinJWTDecodeVerify(bctx BuiltinContext, args []*ast.Term, iter func(*as return err } // RFC7159 7.2 #9-10 decode the payload - p, err = builtinBase64UrlDecode(ast.String(token.payload)) + p, err = getResult(builtinBase64UrlDecode, ast.StringTerm(token.payload)) if err != nil { return fmt.Errorf("JWT payload had invalid encoding: %v", err) } // RFC7159 7.2 #8 and 5.2 cty if strings.ToUpper(header.cty) == headerJwt { // Nested JWT, go round again with payload as first argument - a = p + a = p.Value continue } else { // Non-nested JWT (or we've reached the bottom of the nesting). break } } - payload, err := extractJSONObject(string(p.(ast.String))) + payload, err := extractJSONObject(string(p.Value.(ast.String))) if err != nil { return err } @@ -1130,12 +1134,12 @@ func decodeJWT(a ast.Value) (*JSONWebToken, error) { } func (token *JSONWebToken) decodeSignature() (string, error) { - decodedSignature, err := builtinBase64UrlDecode(ast.String(token.signature)) + decodedSignature, err := getResult(builtinBase64UrlDecode, ast.StringTerm(token.signature)) if err != nil { return "", err } - signatureAst, err := builtins.StringOperand(decodedSignature, 1) + signatureAst, err := builtins.StringOperand(decodedSignature.Value, 1) if err != nil { return "", err } @@ -1169,12 +1173,12 @@ func extractJSONObject(s string) (ast.Object, error) { // to parsing it ourselves, we're relying on the Go implementation // using the last occurring instance of the key, which is the behavior // as of Go 1.8.1. - v, err := builtinJSONUnmarshal(ast.String(s)) + v, err := getResult(builtinJSONUnmarshal, ast.StringTerm(s)) if err != nil { return nil, fmt.Errorf("invalid JSON: %v", err) } - o, ok := v.(ast.Object) + o, ok := v.Value.(ast.Object) if !ok { return nil, errors.New("decoded JSON type was not an Object") } @@ -1190,7 +1194,7 @@ func getInputSHA(input []byte, h func() hash.Hash) []byte { } func init() { - RegisterFunctionalBuiltin1(ast.JWTDecode.Name, builtinJWTDecode) + RegisterBuiltinFunc(ast.JWTDecode.Name, builtinJWTDecode) RegisterBuiltinFunc(ast.JWTVerifyRS256.Name, builtinJWTVerifyRS256) RegisterBuiltinFunc(ast.JWTVerifyRS384.Name, builtinJWTVerifyRS384) RegisterBuiltinFunc(ast.JWTVerifyRS512.Name, builtinJWTVerifyRS512) diff --git a/topdown/topdown_test.go b/topdown/topdown_test.go index 087ae4915a..d0c0041b32 100644 --- a/topdown/topdown_test.go +++ b/topdown/topdown_test.go @@ -1273,10 +1273,10 @@ func init() { ), }) - RegisterFunctionalBuiltin1("test.sleep", func(a ast.Value) (ast.Value, error) { - d, _ := time.ParseDuration(string(a.(ast.String))) + RegisterBuiltinFunc("test.sleep", func(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + d, _ := time.ParseDuration(string(operands[0].Value.(ast.String))) time.Sleep(d) - return ast.Null{}, nil + return iter(ast.NullTerm()) }) } diff --git a/topdown/trace.go b/topdown/trace.go index 9bf172ba01..727938d9c6 100644 --- a/topdown/trace.go +++ b/topdown/trace.go @@ -387,9 +387,9 @@ func (ds depths) GetOrSet(qid uint64, pqid uint64) int { return depth } -func builtinTrace(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinTrace(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - str, err := builtins.StringOperand(args[0].Value, 1) + str, err := builtins.StringOperand(operands[0].Value, 1) if err != nil { return handleBuiltinErr(ast.Trace.Name, bctx.Location, err) } diff --git a/topdown/type.go b/topdown/type.go index ff35f777f5..dab5c853cd 100644 --- a/topdown/type.go +++ b/topdown/type.go @@ -8,75 +8,75 @@ import ( "github.com/open-policy-agent/opa/ast" ) -func builtinIsNumber(a ast.Value) (ast.Value, error) { - switch a.(type) { +func builtinIsNumber(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch operands[0].Value.(type) { case ast.Number: - return ast.Boolean(true), nil + return iter(ast.BooleanTerm(true)) default: - return ast.Boolean(false), nil + return iter(ast.BooleanTerm(false)) } } -func builtinIsString(a ast.Value) (ast.Value, error) { - switch a.(type) { +func builtinIsString(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch operands[0].Value.(type) { case ast.String: - return ast.Boolean(true), nil + return iter(ast.BooleanTerm(true)) default: - return ast.Boolean(false), nil + return iter(ast.BooleanTerm(false)) } } -func builtinIsBoolean(a ast.Value) (ast.Value, error) { - switch a.(type) { +func builtinIsBoolean(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch operands[0].Value.(type) { case ast.Boolean: - return ast.Boolean(true), nil + return iter(ast.BooleanTerm(true)) default: - return ast.Boolean(false), nil + return iter(ast.BooleanTerm(false)) } } -func builtinIsArray(a ast.Value) (ast.Value, error) { - switch a.(type) { +func builtinIsArray(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch operands[0].Value.(type) { case *ast.Array: - return ast.Boolean(true), nil + return iter(ast.BooleanTerm(true)) default: - return ast.Boolean(false), nil + return iter(ast.BooleanTerm(false)) } } -func builtinIsSet(a ast.Value) (ast.Value, error) { - switch a.(type) { +func builtinIsSet(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch operands[0].Value.(type) { case ast.Set: - return ast.Boolean(true), nil + return iter(ast.BooleanTerm(true)) default: - return ast.Boolean(false), nil + return iter(ast.BooleanTerm(false)) } } -func builtinIsObject(a ast.Value) (ast.Value, error) { - switch a.(type) { +func builtinIsObject(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch operands[0].Value.(type) { case ast.Object: - return ast.Boolean(true), nil + return iter(ast.BooleanTerm(true)) default: - return ast.Boolean(false), nil + return iter(ast.BooleanTerm(false)) } } -func builtinIsNull(a ast.Value) (ast.Value, error) { - switch a.(type) { +func builtinIsNull(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch operands[0].Value.(type) { case ast.Null: - return ast.Boolean(true), nil + return iter(ast.BooleanTerm(true)) default: - return ast.Boolean(false), nil + return iter(ast.BooleanTerm(false)) } } func init() { - RegisterFunctionalBuiltin1(ast.IsNumber.Name, builtinIsNumber) - RegisterFunctionalBuiltin1(ast.IsString.Name, builtinIsString) - RegisterFunctionalBuiltin1(ast.IsBoolean.Name, builtinIsBoolean) - RegisterFunctionalBuiltin1(ast.IsArray.Name, builtinIsArray) - RegisterFunctionalBuiltin1(ast.IsSet.Name, builtinIsSet) - RegisterFunctionalBuiltin1(ast.IsObject.Name, builtinIsObject) - RegisterFunctionalBuiltin1(ast.IsNull.Name, builtinIsNull) + RegisterBuiltinFunc(ast.IsNumber.Name, builtinIsNumber) + RegisterBuiltinFunc(ast.IsString.Name, builtinIsString) + RegisterBuiltinFunc(ast.IsBoolean.Name, builtinIsBoolean) + RegisterBuiltinFunc(ast.IsArray.Name, builtinIsArray) + RegisterBuiltinFunc(ast.IsSet.Name, builtinIsSet) + RegisterBuiltinFunc(ast.IsObject.Name, builtinIsObject) + RegisterBuiltinFunc(ast.IsNull.Name, builtinIsNull) } diff --git a/topdown/type_name.go b/topdown/type_name.go index 2154abb5c2..0a8b44aed3 100644 --- a/topdown/type_name.go +++ b/topdown/type_name.go @@ -10,27 +10,27 @@ import ( "github.com/open-policy-agent/opa/ast" ) -func builtinTypeName(a ast.Value) (ast.Value, error) { - switch a.(type) { +func builtinTypeName(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + switch operands[0].Value.(type) { case ast.Null: - return ast.String("null"), nil + return iter(ast.StringTerm("null")) case ast.Boolean: - return ast.String("boolean"), nil + return iter(ast.StringTerm("boolean")) case ast.Number: - return ast.String("number"), nil + return iter(ast.StringTerm("number")) case ast.String: - return ast.String("string"), nil + return iter(ast.StringTerm("string")) case *ast.Array: - return ast.String("array"), nil + return iter(ast.StringTerm("array")) case ast.Object: - return ast.String("object"), nil + return iter(ast.StringTerm("object")) case ast.Set: - return ast.String("set"), nil + return iter(ast.StringTerm("set")) } - return nil, fmt.Errorf("illegal value") + return fmt.Errorf("illegal value") } func init() { - RegisterFunctionalBuiltin1(ast.TypeNameBuiltin.Name, builtinTypeName) + RegisterBuiltinFunc(ast.TypeNameBuiltin.Name, builtinTypeName) } diff --git a/topdown/uuid.go b/topdown/uuid.go index d08adb0ac3..2fdbd36983 100644 --- a/topdown/uuid.go +++ b/topdown/uuid.go @@ -11,9 +11,9 @@ import ( type uuidCachingKey string -func builtinUUIDRFC4122(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { +func builtinUUIDRFC4122(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { - var key = uuidCachingKey(args[0].Value.String()) + var key = uuidCachingKey(operands[0].Value.String()) val, ok := bctx.Cache.Get(key) if ok { diff --git a/topdown/walk.go b/topdown/walk.go index 092014f12e..8e0a346f24 100644 --- a/topdown/walk.go +++ b/topdown/walk.go @@ -8,9 +8,9 @@ import ( "github.com/open-policy-agent/opa/ast" ) -func evalWalk(_ BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error { - input := args[0] - filter := getOutputPath(args) +func evalWalk(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + input := operands[0] + filter := getOutputPath(operands) return walk(filter, nil, input, iter) } @@ -78,9 +78,9 @@ func pathAppend(path *ast.Array, key *ast.Term) *ast.Array { return path.Append(key) } -func getOutputPath(args []*ast.Term) *ast.Array { - if len(args) == 2 { - if arr, ok := args[1].Value.(*ast.Array); ok { +func getOutputPath(operands []*ast.Term) *ast.Array { + if len(operands) == 2 { + if arr, ok := operands[1].Value.(*ast.Array); ok { if arr.Len() == 2 { if path, ok := arr.Elem(0).Value.(*ast.Array); ok { return path