From 8c87a25e069726db56c52b0a4a01ff91c54fb217 Mon Sep 17 00:00:00 2001 From: itchyny Date: Fri, 23 Feb 2024 10:57:11 +0900 Subject: [PATCH] feat: implement std.splitLimitR --- builtins.go | 42 ++++++++++++++++++++++ linter/internal/types/stdlib.go | 1 + testdata/builtinSplitLimitR.golden | 5 +++ testdata/builtinSplitLimitR.jsonnet | 1 + testdata/builtinSplitLimitR.linter.golden | 0 testdata/builtinSplitLimitR2.golden | 3 ++ testdata/builtinSplitLimitR2.jsonnet | 1 + testdata/builtinSplitLimitR2.linter.golden | 0 testdata/builtinSplitLimitR3.golden | 6 ++++ testdata/builtinSplitLimitR3.jsonnet | 1 + testdata/builtinSplitLimitR3.linter.golden | 0 testdata/builtinSplitLimitR4.golden | 6 ++++ testdata/builtinSplitLimitR4.jsonnet | 1 + testdata/builtinSplitLimitR4.linter.golden | 0 testdata/builtinSplitLimitR5.golden | 10 ++++++ testdata/builtinSplitLimitR5.jsonnet | 1 + testdata/builtinSplitLimitR5.linter.golden | 0 testdata/builtinSplitLimitR6.golden | 10 ++++++ testdata/builtinSplitLimitR6.jsonnet | 1 + testdata/builtinSplitLimitR6.linter.golden | 0 testdata/stdlib_smoke_test.golden | 4 +++ testdata/stdlib_smoke_test.jsonnet | 1 + 22 files changed, 94 insertions(+) create mode 100644 testdata/builtinSplitLimitR.golden create mode 100644 testdata/builtinSplitLimitR.jsonnet create mode 100644 testdata/builtinSplitLimitR.linter.golden create mode 100644 testdata/builtinSplitLimitR2.golden create mode 100644 testdata/builtinSplitLimitR2.jsonnet create mode 100644 testdata/builtinSplitLimitR2.linter.golden create mode 100644 testdata/builtinSplitLimitR3.golden create mode 100644 testdata/builtinSplitLimitR3.jsonnet create mode 100644 testdata/builtinSplitLimitR3.linter.golden create mode 100644 testdata/builtinSplitLimitR4.golden create mode 100644 testdata/builtinSplitLimitR4.jsonnet create mode 100644 testdata/builtinSplitLimitR4.linter.golden create mode 100644 testdata/builtinSplitLimitR5.golden create mode 100644 testdata/builtinSplitLimitR5.jsonnet create mode 100644 testdata/builtinSplitLimitR5.linter.golden create mode 100644 testdata/builtinSplitLimitR6.golden create mode 100644 testdata/builtinSplitLimitR6.jsonnet create mode 100644 testdata/builtinSplitLimitR6.linter.golden diff --git a/builtins.go b/builtins.go index e426b069c..1d7344018 100644 --- a/builtins.go +++ b/builtins.go @@ -1324,6 +1324,47 @@ func builtinSplitLimit(i *interpreter, strv, cv, maxSplitsV value) (value, error return makeValueArray(res), nil } +func builtinSplitLimitR(i *interpreter, strv, cv, maxSplitsV value) (value, error) { + str, err := i.getString(strv) + if err != nil { + return nil, err + } + c, err := i.getString(cv) + if err != nil { + return nil, err + } + maxSplits, err := i.getInt(maxSplitsV) + if err != nil { + return nil, err + } + if maxSplits < -1 { + return nil, i.Error(fmt.Sprintf("std.splitLimitR third parameter should be -1 or non-negative, got %v", maxSplits)) + } + sStr := str.getGoString() + sC := c.getGoString() + if len(sC) < 1 { + return nil, i.Error(fmt.Sprintf("std.splitLimitR second parameter should have length 1 or greater, got %v", len(sC))) + } + + count := strings.Count(sStr, sC) + if maxSplits > -1 && count > maxSplits { + count = maxSplits + } + strs := make([]string, count+1) + for i := count; i > 0; i-- { + index := strings.LastIndex(sStr, sC) + strs[i] = sStr[index+len(sC):] + sStr = sStr[:index] + } + strs[0] = sStr + res := make([]*cachedThunk, len(strs)) + for i := range strs { + res[i] = readyThunk(makeValueString(strs[i])) + } + + return makeValueArray(res), nil +} + func builtinStrReplace(i *interpreter, strv, fromv, tov value) (value, error) { str, err := i.getString(strv) if err != nil { @@ -2511,6 +2552,7 @@ var funcBuiltins = buildBuiltinMap([]builtin{ &binaryBuiltin{name: "stripChars", function: builtinStripChars, params: ast.Identifiers{"str", "chars"}}, &ternaryBuiltin{name: "substr", function: builtinSubstr, params: ast.Identifiers{"str", "from", "len"}}, &ternaryBuiltin{name: "splitLimit", function: builtinSplitLimit, params: ast.Identifiers{"str", "c", "maxsplits"}}, + &ternaryBuiltin{name: "splitLimitR", function: builtinSplitLimitR, params: ast.Identifiers{"str", "c", "maxsplits"}}, &ternaryBuiltin{name: "strReplace", function: builtinStrReplace, params: ast.Identifiers{"str", "from", "to"}}, &unaryBuiltin{name: "isEmpty", function: builtinIsEmpty, params: ast.Identifiers{"str"}}, &binaryBuiltin{name: "equalsIgnoreCase", function: builtinEqualsIgnoreCase, params: ast.Identifiers{"str1", "str2"}}, diff --git a/linter/internal/types/stdlib.go b/linter/internal/types/stdlib.go index 63c0eed34..2bbc27709 100644 --- a/linter/internal/types/stdlib.go +++ b/linter/internal/types/stdlib.go @@ -90,6 +90,7 @@ func prepareStdlib(g *typeGraph) { "rstripChars": g.newSimpleFuncType(stringType, "str", "chars"), "split": g.newSimpleFuncType(arrayOfString, "str", "c"), "splitLimit": g.newSimpleFuncType(arrayOfString, "str", "c", "maxsplits"), + "splitLimitR": g.newSimpleFuncType(arrayOfString, "str", "c", "maxsplits"), "strReplace": g.newSimpleFuncType(stringType, "str", "from", "to"), "asciiUpper": g.newSimpleFuncType(stringType, "str"), "asciiLower": g.newSimpleFuncType(stringType, "str"), diff --git a/testdata/builtinSplitLimitR.golden b/testdata/builtinSplitLimitR.golden new file mode 100644 index 000000000..711ef61d6 --- /dev/null +++ b/testdata/builtinSplitLimitR.golden @@ -0,0 +1,5 @@ +[ + "foo,bar", + "baz", + "qux" +] diff --git a/testdata/builtinSplitLimitR.jsonnet b/testdata/builtinSplitLimitR.jsonnet new file mode 100644 index 000000000..85aa16cbf --- /dev/null +++ b/testdata/builtinSplitLimitR.jsonnet @@ -0,0 +1 @@ +std.splitLimitR('foo,bar,baz,qux', ',', 2) diff --git a/testdata/builtinSplitLimitR.linter.golden b/testdata/builtinSplitLimitR.linter.golden new file mode 100644 index 000000000..e69de29bb diff --git a/testdata/builtinSplitLimitR2.golden b/testdata/builtinSplitLimitR2.golden new file mode 100644 index 000000000..890b11bfa --- /dev/null +++ b/testdata/builtinSplitLimitR2.golden @@ -0,0 +1,3 @@ +[ + "foo,bar,baz,qux" +] diff --git a/testdata/builtinSplitLimitR2.jsonnet b/testdata/builtinSplitLimitR2.jsonnet new file mode 100644 index 000000000..802e95ac8 --- /dev/null +++ b/testdata/builtinSplitLimitR2.jsonnet @@ -0,0 +1 @@ +std.splitLimitR('foo,bar,baz,qux', ',', 0) diff --git a/testdata/builtinSplitLimitR2.linter.golden b/testdata/builtinSplitLimitR2.linter.golden new file mode 100644 index 000000000..e69de29bb diff --git a/testdata/builtinSplitLimitR3.golden b/testdata/builtinSplitLimitR3.golden new file mode 100644 index 000000000..054ad80ff --- /dev/null +++ b/testdata/builtinSplitLimitR3.golden @@ -0,0 +1,6 @@ +[ + "foo", + "bar", + "baz", + "qux" +] diff --git a/testdata/builtinSplitLimitR3.jsonnet b/testdata/builtinSplitLimitR3.jsonnet new file mode 100644 index 000000000..5e6dda8c8 --- /dev/null +++ b/testdata/builtinSplitLimitR3.jsonnet @@ -0,0 +1 @@ +std.splitLimitR('foo,bar,baz,qux', ',', -1) diff --git a/testdata/builtinSplitLimitR3.linter.golden b/testdata/builtinSplitLimitR3.linter.golden new file mode 100644 index 000000000..e69de29bb diff --git a/testdata/builtinSplitLimitR4.golden b/testdata/builtinSplitLimitR4.golden new file mode 100644 index 000000000..054ad80ff --- /dev/null +++ b/testdata/builtinSplitLimitR4.golden @@ -0,0 +1,6 @@ +[ + "foo", + "bar", + "baz", + "qux" +] diff --git a/testdata/builtinSplitLimitR4.jsonnet b/testdata/builtinSplitLimitR4.jsonnet new file mode 100644 index 000000000..31a59c313 --- /dev/null +++ b/testdata/builtinSplitLimitR4.jsonnet @@ -0,0 +1 @@ +std.splitLimitR('foo,bar,baz,qux', ',', 4) diff --git a/testdata/builtinSplitLimitR4.linter.golden b/testdata/builtinSplitLimitR4.linter.golden new file mode 100644 index 000000000..e69de29bb diff --git a/testdata/builtinSplitLimitR5.golden b/testdata/builtinSplitLimitR5.golden new file mode 100644 index 000000000..1d2d01e75 --- /dev/null +++ b/testdata/builtinSplitLimitR5.golden @@ -0,0 +1,10 @@ +RUNTIME ERROR: std.splitLimitR third parameter should be -1 or non-negative, got -2 +------------------------------------------------- + testdata/builtinSplitLimitR5:1:1-44 $ + +std.splitLimitR('foo,bar,baz,qux', ',', -2) + +------------------------------------------------- + During evaluation + + diff --git a/testdata/builtinSplitLimitR5.jsonnet b/testdata/builtinSplitLimitR5.jsonnet new file mode 100644 index 000000000..bced0a5d5 --- /dev/null +++ b/testdata/builtinSplitLimitR5.jsonnet @@ -0,0 +1 @@ +std.splitLimitR('foo,bar,baz,qux', ',', -2) diff --git a/testdata/builtinSplitLimitR5.linter.golden b/testdata/builtinSplitLimitR5.linter.golden new file mode 100644 index 000000000..e69de29bb diff --git a/testdata/builtinSplitLimitR6.golden b/testdata/builtinSplitLimitR6.golden new file mode 100644 index 000000000..ebd988365 --- /dev/null +++ b/testdata/builtinSplitLimitR6.golden @@ -0,0 +1,10 @@ +RUNTIME ERROR: std.splitLimitR second parameter should have length 1 or greater, got 0 +------------------------------------------------- + testdata/builtinSplitLimitR6:1:1-43 $ + +std.splitLimitR('foo,bar,baz,qux', '', -1) + +------------------------------------------------- + During evaluation + + diff --git a/testdata/builtinSplitLimitR6.jsonnet b/testdata/builtinSplitLimitR6.jsonnet new file mode 100644 index 000000000..d90ffbe0e --- /dev/null +++ b/testdata/builtinSplitLimitR6.jsonnet @@ -0,0 +1 @@ +std.splitLimitR('foo,bar,baz,qux', '', -1) diff --git a/testdata/builtinSplitLimitR6.linter.golden b/testdata/builtinSplitLimitR6.linter.golden new file mode 100644 index 000000000..e69de29bb diff --git a/testdata/stdlib_smoke_test.golden b/testdata/stdlib_smoke_test.golden index b2e507f81..184df1830 100644 --- a/testdata/stdlib_smoke_test.golden +++ b/testdata/stdlib_smoke_test.golden @@ -243,6 +243,10 @@ "a", "b,c" ], + "splitLimitR": [ + "a,b", + "c" + ], "sqrt": 2.2360679774997898, "startsWith": true, "strReplace": "bba", diff --git a/testdata/stdlib_smoke_test.jsonnet b/testdata/stdlib_smoke_test.jsonnet index 53a6d9537..1ac4f3317 100644 --- a/testdata/stdlib_smoke_test.jsonnet +++ b/testdata/stdlib_smoke_test.jsonnet @@ -72,6 +72,7 @@ rstripChars: std.rstripChars(str="aaabbbbcccc", chars="c"), split: std.split(str="a,b,c", c=","), splitLimit: std.splitLimit(str="a,b,c", c=",", maxsplits=1), + splitLimitR: std.splitLimitR(str="a,b,c", c=",", maxsplits=1), strReplace: std.strReplace(str="aaa", from="aa", to="bb"), asciiUpper: std.asciiUpper(str="Blah"), asciiLower: std.asciiLower(str="Blah"),