1// Copyright 2018 The OPA Authors.  All rights reserved.
2// Use of this source code is governed by an Apache2
3// license that can be found in the LICENSE file.
4
5package topdown
6
7import (
8	"github.com/open-policy-agent/opa/ast"
9	"github.com/open-policy-agent/opa/topdown/builtins"
10)
11
12func builtinArrayConcat(a, b ast.Value) (ast.Value, error) {
13	arrA, err := builtins.ArrayOperand(a, 1)
14	if err != nil {
15		return nil, err
16	}
17
18	arrB, err := builtins.ArrayOperand(b, 2)
19	if err != nil {
20		return nil, err
21	}
22
23	arrC := make(ast.Array, 0, len(arrA)+len(arrB))
24
25	for _, elemA := range arrA {
26		arrC = append(arrC, elemA)
27	}
28
29	for _, elemB := range arrB {
30		arrC = append(arrC, elemB)
31	}
32
33	return arrC, nil
34}
35
36func builtinArraySlice(a, i, j ast.Value) (ast.Value, error) {
37	arr, err := builtins.ArrayOperand(a, 1)
38	if err != nil {
39		return nil, err
40	}
41
42	startIndex, err := builtins.IntOperand(i, 2)
43	if err != nil {
44		return nil, err
45	}
46
47	stopIndex, err := builtins.IntOperand(j, 3)
48	if err != nil {
49		return nil, err
50	}
51
52	// Return empty array if bounds cannot be clamped sensibly.
53	if (startIndex >= stopIndex) || (startIndex <= 0 && stopIndex <= 0) {
54		return arr[0:0], nil
55	}
56
57	// Clamp bounds to avoid out-of-range errors.
58	if startIndex < 0 {
59		startIndex = 0
60	}
61
62	if stopIndex > len(arr) {
63		stopIndex = len(arr)
64	}
65
66	arrb := arr[startIndex:stopIndex]
67
68	return arrb, nil
69
70}
71
72func init() {
73	RegisterFunctionalBuiltin2(ast.ArrayConcat.Name, builtinArrayConcat)
74	RegisterFunctionalBuiltin3(ast.ArraySlice.Name, builtinArraySlice)
75}
76