diff --git a/builtins.go b/builtins.go index 8b5eebd..4ec495c 100644 --- a/builtins.go +++ b/builtins.go @@ -285,6 +285,59 @@ func builtinFlatMap(e *evaluator, funcp potentialValue, arrp potentialValue) (va return makeValueArray(elems), nil } +func joinArrays(e *evaluator, sep *valueArray, arr *valueArray) (value, error) { + result := make([]potentialValue, 0, arr.length()) + for i, elem := range arr.elements { + if i != 0 { + for _, subElem := range sep.elements { + result = append(result, subElem) + } + } + elemArr, err := e.evaluateArray(elem) + if err != nil { + return nil, err + } + for _, subElem := range elemArr.elements { + result = append(result, subElem) + } + } + return makeValueArray(result), nil +} + +func joinStrings(e *evaluator, sep *valueString, arr *valueArray) (value, error) { + result := make([]rune, 0, arr.length()) + for i, elem := range arr.elements { + if i != 0 { + result = append(result, sep.value...) + } + elemString, err := e.evaluateString(elem) + if err != nil { + return nil, err + } + result = append(result, elemString.value...) + } + return &valueString{value: result}, nil +} + +func builtinJoin(e *evaluator, sepp potentialValue, arrp potentialValue) (value, error) { + arr, err := e.evaluateArray(arrp) + if err != nil { + return nil, err + } + sep, err := e.evaluate(sepp) + if err != nil { + return nil, err + } + switch sep := sep.(type) { + case *valueString: + return joinStrings(e, sep, arr) + case *valueArray: + return joinArrays(e, sep, arr) + default: + return nil, e.Error("join first parameter should be string or array, got " + sep.getType().name) + } +} + func builtinFilter(e *evaluator, funcp potentialValue, arrp potentialValue) (value, error) { arr, err := e.evaluateArray(arrp) if err != nil { @@ -771,6 +824,7 @@ var funcBuiltins = buildBuiltinMap([]builtin{ &UnaryBuiltin{name: "toString", function: builtinToString, parameters: ast.Identifiers{"a"}}, &BinaryBuiltin{name: "makeArray", function: builtinMakeArray, parameters: ast.Identifiers{"sz", "func"}}, &BinaryBuiltin{name: "flatMap", function: builtinFlatMap, parameters: ast.Identifiers{"func", "arr"}}, + &BinaryBuiltin{name: "join", function: builtinJoin, parameters: ast.Identifiers{"sep", "arr"}}, &BinaryBuiltin{name: "filter", function: builtinFilter, parameters: ast.Identifiers{"func", "arr"}}, &BinaryBuiltin{name: "range", function: builtinRange, parameters: ast.Identifiers{"from", "to"}}, &BinaryBuiltin{name: "primitiveEquals", function: primitiveEquals, parameters: ast.Identifiers{"sz", "func"}}, diff --git a/testdata/std.join.golden b/testdata/std.join.golden new file mode 100644 index 0000000..1e3ec72 --- /dev/null +++ b/testdata/std.join.golden @@ -0,0 +1 @@ +[ ] diff --git a/testdata/std.join.jsonnet b/testdata/std.join.jsonnet new file mode 100644 index 0000000..ca3fc66 --- /dev/null +++ b/testdata/std.join.jsonnet @@ -0,0 +1 @@ +std.join([], []) diff --git a/testdata/std.join2.golden b/testdata/std.join2.golden new file mode 100644 index 0000000..1e3ec72 --- /dev/null +++ b/testdata/std.join2.golden @@ -0,0 +1 @@ +[ ] diff --git a/testdata/std.join2.jsonnet b/testdata/std.join2.jsonnet new file mode 100644 index 0000000..dd401c2 --- /dev/null +++ b/testdata/std.join2.jsonnet @@ -0,0 +1 @@ +std.join([42], []) diff --git a/testdata/std.join3.golden b/testdata/std.join3.golden new file mode 100644 index 0000000..d67ec3c --- /dev/null +++ b/testdata/std.join3.golden @@ -0,0 +1,3 @@ +[ + 1 +] diff --git a/testdata/std.join3.jsonnet b/testdata/std.join3.jsonnet new file mode 100644 index 0000000..1965840 --- /dev/null +++ b/testdata/std.join3.jsonnet @@ -0,0 +1 @@ +std.join([42], [[1]]) diff --git a/testdata/std.join4.golden b/testdata/std.join4.golden new file mode 100644 index 0000000..be32693 --- /dev/null +++ b/testdata/std.join4.golden @@ -0,0 +1,5 @@ +[ + 1, + 42, + 2 +] diff --git a/testdata/std.join4.jsonnet b/testdata/std.join4.jsonnet new file mode 100644 index 0000000..471d721 --- /dev/null +++ b/testdata/std.join4.jsonnet @@ -0,0 +1 @@ +std.join([42], [[1], [2]]) diff --git a/testdata/std.join5.golden b/testdata/std.join5.golden new file mode 100644 index 0000000..98ee12c --- /dev/null +++ b/testdata/std.join5.golden @@ -0,0 +1,7 @@ +[ + 1, + 42, + 2, + 42, + 3 +] diff --git a/testdata/std.join5.jsonnet b/testdata/std.join5.jsonnet new file mode 100644 index 0000000..c83e34e --- /dev/null +++ b/testdata/std.join5.jsonnet @@ -0,0 +1 @@ +std.join([42], [[1], [2], [3]]) diff --git a/testdata/std.join6.golden b/testdata/std.join6.golden new file mode 100644 index 0000000..338e281 --- /dev/null +++ b/testdata/std.join6.golden @@ -0,0 +1 @@ +"aaxxxbb" diff --git a/testdata/std.join6.jsonnet b/testdata/std.join6.jsonnet new file mode 100644 index 0000000..3231b85 --- /dev/null +++ b/testdata/std.join6.jsonnet @@ -0,0 +1 @@ +std.join("xxx", ["aa", "bb"]) diff --git a/testdata/std.join7.golden b/testdata/std.join7.golden new file mode 100644 index 0000000..57c2329 --- /dev/null +++ b/testdata/std.join7.golden @@ -0,0 +1,8 @@ +RUNTIME ERROR: Unexpected type array, expected string +------------------------------------------------- + builtin function + +------------------------------------------------- + During evaluation + + diff --git a/testdata/std.join7.jsonnet b/testdata/std.join7.jsonnet new file mode 100644 index 0000000..f57dc9e --- /dev/null +++ b/testdata/std.join7.jsonnet @@ -0,0 +1 @@ +std.join("aa", [[1], [2]]) diff --git a/testdata/std.join8.golden b/testdata/std.join8.golden new file mode 100644 index 0000000..f167beb --- /dev/null +++ b/testdata/std.join8.golden @@ -0,0 +1,8 @@ +RUNTIME ERROR: Unexpected type string, expected array +------------------------------------------------- + builtin function + +------------------------------------------------- + During evaluation + + diff --git a/testdata/std.join8.jsonnet b/testdata/std.join8.jsonnet new file mode 100644 index 0000000..013f48f --- /dev/null +++ b/testdata/std.join8.jsonnet @@ -0,0 +1 @@ +std.join([3, 4], [[1, 2], "56"])