From 24cc95abccdbf074a088f850622829d451cbb2a6 Mon Sep 17 00:00:00 2001 From: Islon Scherer Date: Tue, 16 Jul 2024 19:24:59 +0200 Subject: [PATCH] Support `_` in String[toInt|toIntOrNull|toFloat|toFloatOrNull] (#580) The logic is the same as the Pkl parser --- .../org/pkl/core/stdlib/base/StringNodes.java | 27 ++++++++++++++++--- .../LanguageSnippetTests/input/api/string.pkl | 10 +++++-- .../output/api/string.pcf | 6 +++++ 3 files changed, 37 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 6bc04b66..b6f0fa5e 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 @@ -768,7 +768,7 @@ public final class StringNodes { @Specialization protected long eval(String self) { try { - return Long.parseLong(self.replaceAll("_", "")); + return Long.parseLong(removeUnderlinesFromNumber(self)); } catch (NumberFormatException e) { throw exceptionBuilder() .evalError("cannotParseStringAs", "Int") @@ -783,7 +783,7 @@ public final class StringNodes { @Specialization protected Object eval(String self) { try { - return Long.parseLong(self.replaceAll("_", "")); + return Long.parseLong(removeUnderlinesFromNumber(self)); } catch (NumberFormatException e) { return VmNull.withoutDefault(); } @@ -795,7 +795,7 @@ public final class StringNodes { @Specialization protected double eval(String self) { try { - return Double.parseDouble(self); + return Double.parseDouble(removeUnderlinesFromNumber(self)); } catch (NumberFormatException e) { throw exceptionBuilder() .evalError("cannotParseStringAs", "Float") @@ -810,7 +810,7 @@ public final class StringNodes { @Specialization protected Object eval(String self) { try { - return Double.parseDouble(self); + return Double.parseDouble(removeUnderlinesFromNumber(self)); } catch (NumberFormatException e) { return VmNull.withoutDefault(); } @@ -934,4 +934,23 @@ public final class StringNodes { var replacement = mapper.applyString(regexMatch); return Matcher.quoteReplacement(replacement); } + + /** + * Removes `_` from numbers to be parsed to be compatible with how Pkl parses numbers. Will return + * the string unmodified if it's invalid. + */ + private static String removeUnderlinesFromNumber(String number) { + var builder = new StringBuilder(); + var numberStart = true; + for (var i = 0; i < number.length(); i++) { + var c = number.charAt(i); + if (c != '_') { + builder.append(c); + } else if (numberStart) return number; + + numberStart = c == '.' || c == 'e' || c == 'E'; + } + + return builder.toString(); + } } 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 4a033059..4f234ff1 100644 --- a/pkl-core/src/test/files/LanguageSnippetTests/input/api/string.pkl +++ b/pkl-core/src/test/files/LanguageSnippetTests/input/api/string.pkl @@ -233,19 +233,21 @@ examples { module.catch(() -> "9223372036854775808".toInt()) module.catch(() -> "-9223372036854775809".toInt()) module.catch(() -> "abc".toInt()) + module.catch(() -> "_1_000".toInt()) } ["toIntOrNull()"] { "123".toIntOrNull() "-123".toIntOrNull() - "1_2__3___".toInt() - "-1_2__3___".toInt() + "1_2__3___".toIntOrNull() + "-1_2__3___".toIntOrNull() "0".toIntOrNull() "-0".toIntOrNull() "1.2".toIntOrNull() "9223372036854775808".toIntOrNull() "-9223372036854775809".toIntOrNull() "abc".toIntOrNull() + "_1_2__3___".toIntOrNull() } ["toFloat()"] { @@ -282,13 +284,17 @@ examples { "-.45e-9".toFloat() "9e1024".toFloat() "-9e1024".toFloat() + "-1_2__3___.2_e+1_".toFloat() module.catch(() -> "abc".toFloat()) + module.catch(() -> "123._34".toFloat()) + module.catch(() -> "123e_34".toFloat()) } ["toFloatOrNull()"] { "0".toFloatOrNull() "-0".toFloatOrNull() "abc".toFloatOrNull() + "_123_.1_".toFloatOrNull() } ["take()"] { 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 b97c39ae..2cae3c92 100644 --- a/pkl-core/src/test/files/LanguageSnippetTests/output/api/string.pcf +++ b/pkl-core/src/test/files/LanguageSnippetTests/output/api/string.pcf @@ -191,6 +191,7 @@ examples { "Cannot parse string as `Int`. String: \"9223372036854775808\"" "Cannot parse string as `Int`. String: \"-9223372036854775809\"" "Cannot parse string as `Int`. String: \"abc\"" + "Cannot parse string as `Int`. String: \"_1_000\"" } ["toIntOrNull()"] { 123 @@ -203,6 +204,7 @@ examples { null null null + null } ["toFloat()"] { 0.0 @@ -238,12 +240,16 @@ examples { -4.5E-10 Infinity -Infinity + -1232.0 "Cannot parse string as `Float`. String: \"abc\"" + "Cannot parse string as `Float`. String: \"123._34\"" + "Cannot parse string as `Float`. String: \"123e_34\"" } ["toFloatOrNull()"] { 0.0 -0.0 null + null } ["take()"] { ""