diff --git a/pkl-core/src/main/java/org/pkl/core/stdlib/base/StringNodes.java b/pkl-core/src/main/java/org/pkl/core/stdlib/base/StringNodes.java index b6f0fa5e..7ad4ef93 100644 --- a/pkl-core/src/main/java/org/pkl/core/stdlib/base/StringNodes.java +++ b/pkl-core/src/main/java/org/pkl/core/stdlib/base/StringNodes.java @@ -739,6 +739,22 @@ public final class StringNodes { } } + public abstract static class splitLimit extends ExternalMethod2Node { + @TruffleBoundary + @Specialization + protected VmList eval(String self, String separator, long limit) { + var parts = self.split(Pattern.quote(separator), (int) limit); + return VmList.create(parts); + } + + @TruffleBoundary + @Specialization + protected VmList eval(String self, VmRegex separator, long limit) { + var parts = separator.getPattern().split(self, (int) limit); + return VmList.create(parts); + } + } + public abstract static class capitalize extends ExternalMethod0Node { @TruffleBoundary @Specialization diff --git a/pkl-core/src/test/files/LanguageSnippetTests/input/api/string.pkl b/pkl-core/src/test/files/LanguageSnippetTests/input/api/string.pkl index 4f234ff1..c36b0e0c 100644 --- a/pkl-core/src/test/files/LanguageSnippetTests/input/api/string.pkl +++ b/pkl-core/src/test/files/LanguageSnippetTests/input/api/string.pkl @@ -138,6 +138,19 @@ examples { str4.split("cc") } + local str7 = "aabbccaabbccaabbccaabbcc" + + ["splitLimit()"] { + str7.splitLimit(Regex("b+c"), 1) + str7.splitLimit(Regex("b+c"), 2) + str7.splitLimit(Regex("b+c"), 4) + str7.splitLimit("cc", 1) + str7.splitLimit("cc", 2) + str7.splitLimit("cc", 4) + module.catch(() -> str7.splitLimit(Regex("b+c"), 0)) + module.catch(() -> str7.splitLimit(Regex("b+c"), -1)) + } + ["replaceAll()"] { str4.replaceAll("aa", "xx") str4.replaceAll(Regex("(b+)c"), "($0|$1)") diff --git a/pkl-core/src/test/files/LanguageSnippetTests/output/api/reflectedDeclaration.pcf b/pkl-core/src/test/files/LanguageSnippetTests/output/api/reflectedDeclaration.pcf index 57d3d478..3eef3444 100644 --- a/pkl-core/src/test/files/LanguageSnippetTests/output/api/reflectedDeclaration.pcf +++ b/pkl-core/src/test/files/LanguageSnippetTests/output/api/reflectedDeclaration.pcf @@ -1333,11 +1333,42 @@ alias { parameters = Map("pattern", new { name = "pattern" }) + }, "splitLimit", new { + location { + line = 1383 + column = 3 + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1383" + } + docComment = """ + Splits this string matches of [pattern], up to [limit] substrings. + + Returns a [List] with at most [limit] elements. + If the limit has been reached, the last entry will contain the un-split remainder of this string. + + Facts: + ``` + "a.b.c".splitLimit(".", 2) == List("a", "b.c") + "a.b.c".splitLimit(".", 1) == List("a.b.c") + "a.b.c".splitLimit(".", 50) == List("a", "b", "c") + "a.b:c".splitLimit(Regex("[.:]"), 3) == List("a", "b", "c") + ``` + """ + annotations = List(new { + version = "0.27.0" + }) + modifiers = Set() + name = "splitLimit" + typeParameters = List() + parameters = Map("pattern", new { + name = "pattern" + }, "limit", new { + name = "limit" + }) }, "capitalize", new { location { - line = 1378 + line = 1393 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1378" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1393" } docComment = """ Converts the first character of this string to title case. @@ -1356,9 +1387,9 @@ alias { parameters = Map() }, "decapitalize", new { location { - line = 1388 + line = 1403 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1388" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1403" } docComment = """ Converts the first character of this string to lower case. @@ -1377,9 +1408,9 @@ alias { parameters = Map() }, "toInt", new { location { - line = 1394 + line = 1409 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1394" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1409" } docComment = """ Parses this string as a signed decimal (base 10) integer. @@ -1394,9 +1425,9 @@ alias { parameters = Map() }, "toIntOrNull", new { location { - line = 1400 + line = 1415 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1400" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1415" } docComment = """ Parses this string as a signed decimal (base 10) integer. @@ -1411,9 +1442,9 @@ alias { parameters = Map() }, "toFloat", new { location { - line = 1405 + line = 1420 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1405" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1420" } docComment = """ Parses this string as a floating point number. @@ -1427,9 +1458,9 @@ alias { parameters = Map() }, "toFloatOrNull", new { location { - line = 1410 + line = 1425 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1410" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1425" } docComment = """ Parses this string as a floating point number. @@ -1443,9 +1474,9 @@ alias { parameters = Map() }, "toBoolean", new { location { - line = 1415 + line = 1430 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1415" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1430" } docComment = """ Parses `"true"` to [true] and `"false"` to [false] (case-insensitive). @@ -1459,9 +1490,9 @@ alias { parameters = Map() }, "toBooleanOrNull", new { location { - line = 1420 + line = 1435 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1420" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1435" } docComment = """ Parses `"true"` to [true] and `"false"` to [false] (case-insensitive). @@ -1493,9 +1524,9 @@ rec { typeParameters = List() superclass { location { - line = 1706 + line = 1721 column = 1 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1706" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1721" } docComment = """ Base class for objects whose members are described by a class definition. @@ -1508,9 +1539,9 @@ rec { typeParameters = List() superclass { location { - line = 1701 + line = 1716 column = 1 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1701" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1716" } docComment = """ A composite value containing members (properties, elements, entries). @@ -1734,9 +1765,9 @@ rec { supertype { referent { location { - line = 1701 + line = 1716 column = 1 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1701" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1716" } docComment = """ A composite value containing members (properties, elements, entries). @@ -1962,9 +1993,9 @@ rec { properties = Map() methods = Map("hasProperty", new { location { - line = 1708 + line = 1723 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1708" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1723" } docComment = "Tells if this object has a property with the given [name]." annotations = List() @@ -1976,9 +2007,9 @@ rec { }) }, "getProperty", new { location { - line = 1713 + line = 1728 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1713" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1728" } docComment = """ Returns the value of the property with the given [name]. @@ -1994,9 +2025,9 @@ rec { }) }, "getPropertyOrNull", new { location { - line = 1718 + line = 1733 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1718" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1733" } docComment = """ Returns the value of the property with the given [name]. @@ -2012,9 +2043,9 @@ rec { }) }, "toDynamic", new { location { - line = 1721 + line = 1736 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1721" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1736" } docComment = "Converts this object to a [Dynamic] object." annotations = List() @@ -2024,9 +2055,9 @@ rec { parameters = Map() }, "toMap", new { location { - line = 1724 + line = 1739 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1724" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1739" } docComment = "Converts this object to a [Map]." annotations = List() @@ -2039,9 +2070,9 @@ rec { supertype { referent { location { - line = 1706 + line = 1721 column = 1 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1706" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1721" } docComment = """ Base class for objects whose members are described by a class definition. @@ -2054,9 +2085,9 @@ rec { typeParameters = List() superclass { location { - line = 1701 + line = 1716 column = 1 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1701" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1716" } docComment = """ A composite value containing members (properties, elements, entries). @@ -2280,9 +2311,9 @@ rec { supertype { referent { location { - line = 1701 + line = 1716 column = 1 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1701" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1716" } docComment = """ A composite value containing members (properties, elements, entries). @@ -2508,9 +2539,9 @@ rec { properties = Map() methods = Map("hasProperty", new { location { - line = 1708 + line = 1723 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1708" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1723" } docComment = "Tells if this object has a property with the given [name]." annotations = List() @@ -2522,9 +2553,9 @@ rec { }) }, "getProperty", new { location { - line = 1713 + line = 1728 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1713" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1728" } docComment = """ Returns the value of the property with the given [name]. @@ -2540,9 +2571,9 @@ rec { }) }, "getPropertyOrNull", new { location { - line = 1718 + line = 1733 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1718" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1733" } docComment = """ Returns the value of the property with the given [name]. @@ -2558,9 +2589,9 @@ rec { }) }, "toDynamic", new { location { - line = 1721 + line = 1736 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1721" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1736" } docComment = "Converts this object to a [Dynamic] object." annotations = List() @@ -2570,9 +2601,9 @@ rec { parameters = Map() }, "toMap", new { location { - line = 1724 + line = 1739 column = 3 - displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1724" + displayUri = "https://github.com/apple/pkl/blob/$commitId/stdlib/base.pkl#L1739" } docComment = "Converts this object to a [Map]." annotations = List() diff --git a/pkl-core/src/test/files/LanguageSnippetTests/output/api/string.pcf b/pkl-core/src/test/files/LanguageSnippetTests/output/api/string.pcf index 2cae3c92..64389769 100644 --- a/pkl-core/src/test/files/LanguageSnippetTests/output/api/string.pcf +++ b/pkl-core/src/test/files/LanguageSnippetTests/output/api/string.pcf @@ -109,6 +109,16 @@ examples { List("aa", "caa", "c") List("aabb", "aabb") } + ["splitLimit()"] { + List("aabbccaabbccaabbccaabbcc") + List("aa", "caabbccaabbccaabbcc") + List("aa", "caa", "caa", "caabbcc") + List("aabbccaabbccaabbccaabbcc") + List("aabb", "aabbccaabbccaabbcc") + List("aabb", "aabb", "aabb", "aabbcc") + "Type constraint `this > 0` violated. Value: 0" + "Type constraint `this > 0` violated. Value: -1" + } ["replaceAll()"] { "xxbbccxxbbcc" "aa(bbc|bb)caa(bbc|bb)c" diff --git a/stdlib/base.pkl b/stdlib/base.pkl index 880cc92e..cffae7cb 100644 --- a/stdlib/base.pkl +++ b/stdlib/base.pkl @@ -1367,6 +1367,21 @@ external class String extends Any { /// Splits this string around matches of [pattern]. external function split(pattern: String|Regex): List + /// Splits this string matches of [pattern], up to [limit] substrings. + /// + /// Returns a [List] with at most [limit] elements. + /// If the limit has been reached, the last entry will contain the un-split remainder of this string. + /// + /// Facts: + /// ``` + /// "a.b.c".splitLimit(".", 2) == List("a", "b.c") + /// "a.b.c".splitLimit(".", 1) == List("a.b.c") + /// "a.b.c".splitLimit(".", 50) == List("a", "b", "c") + /// "a.b:c".splitLimit(Regex("[.:]"), 3) == List("a", "b", "c") + /// ``` + @Since { version = "0.27.0" } + external function splitLimit(pattern: String|Regex, limit: Int(this > 0)): List + /// Converts the first character of this string to title case. /// /// Facts: