From 8331570aafe66d35a0416c5033d1e50e1ab2568a Mon Sep 17 00:00:00 2001 From: Alexandre Kohler <64209066+kwy404@users.noreply.github.com> Date: Wed, 30 Sep 2026 01:52:12 -0300 Subject: [PATCH] Fix `String.endsWith` for overlapping regex matches (#1880) --- .../java/org/pkl/core/stdlib/base/StringNodes.java | 11 +++++------ .../files/LanguageSnippetTests/input/api/string.pkl | 5 +++++ .../files/LanguageSnippetTests/output/api/string.pcf | 5 +++++ 3 files changed, 15 insertions(+), 6 deletions(-) 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 c92da1ffe..c125bd7b3 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 @@ -333,14 +333,13 @@ public final class StringNodes { @TruffleBoundary @Specialization - // inefficient but at least correct protected boolean eval(String self, VmRegex regex) { - var matcher = regex.matcher(self); - var end = -1; - while (matcher.find()) { - end = matcher.end(); + // try every suffix; `find()` would skip matches that overlap an earlier one + var matcher = regex.matcher(self).useTransparentBounds(true).useAnchoringBounds(false); + for (var start = self.length(); ; start = self.offsetByCodePoints(start, -1)) { + if (matcher.region(start, self.length()).matches()) return true; + if (start == 0) return false; } - return end == self.length(); } } 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 29939fac7..a5ab43ee7 100644 --- a/pkl-core/src/test/files/LanguageSnippetTests/input/api/string.pkl +++ b/pkl-core/src/test/files/LanguageSnippetTests/input/api/string.pkl @@ -76,7 +76,12 @@ facts { ["endsWith()"] { str1.endsWith("") str1.endsWith("efg") + str1.endsWith(Regex(#"\w"#)) + "aaa".endsWith(Regex("aa")) !str1.endsWith("efx") + !str1.endsWith(Regex(#"\d"#)) + !str1.endsWith(Regex(#"\bfg"#)) + !str1.endsWith(Regex("^fg")) } ["isRegex"] { 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 1c39c1683..bda6f39e8 100644 --- a/pkl-core/src/test/files/LanguageSnippetTests/output/api/string.pcf +++ b/pkl-core/src/test/files/LanguageSnippetTests/output/api/string.pcf @@ -59,6 +59,11 @@ facts { true true true + true + true + true + true + true } ["isRegex"] { true