From 7c1d9b5c1d4cf0c8e8a57543456055eab264fa6f Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sat, 11 Jan 2025 22:18:47 +0100 Subject: [PATCH 1/3] Add trim method to string_rt --- media/test-project/test.spice | 13 +++------- src-bootstrap/util/common-util.spice | 5 +--- src/util/CommonUtil.cpp | 5 ++-- std/runtime/string_rt.spice | 26 +++++++++++++++++++ .../source.spice | 3 +++ 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/media/test-project/test.spice b/media/test-project/test.spice index c00ae09fd..19abcd670 100644 --- a/media/test-project/test.spice +++ b/media/test-project/test.spice @@ -1,11 +1,6 @@ -type T dyn; - -f print(T g) { - printf("%d", g); - return 0; -} - f main() { - print(1); - print("string"); + String test = String("String to be trimmed "); + printf("'%s'\n", test); + String trimmed = test.trim(); + printf("'%s'\n", trimmed); } \ No newline at end of file diff --git a/src-bootstrap/util/common-util.spice b/src-bootstrap/util/common-util.spice index 6c2261b97..a2756ef04 100644 --- a/src-bootstrap/util/common-util.spice +++ b/src-bootstrap/util/common-util.spice @@ -13,10 +13,7 @@ import "bootstrap/source-file-intf"; */ public f getLastFragment(const String &haystack, const string needle) { const unsigned long index = haystack.rfind(needle); - if index == -1l { - return haystack; - } - return haystack.getSubstring(index + getRawLength(needle)); + return index != -1l ? haystack.getSubstring(index + getRawLength(needle)) : haystack; } /** diff --git a/src/util/CommonUtil.cpp b/src/util/CommonUtil.cpp index 4e3296acc..464681a81 100644 --- a/src/util/CommonUtil.cpp +++ b/src/util/CommonUtil.cpp @@ -51,10 +51,11 @@ std::string CommonUtil::getLastFragment(const std::string &haystack, const std:: */ std::string CommonUtil::trim(const std::string &input) { const size_t first = input.find_first_not_of(' '); - if (std::string::npos == first) + if (first == std::string::npos) return input; const size_t last = input.find_last_not_of(' '); - return input.substr(first, (last - first + 1)); + const size_t newLength = last - first + 1; + return input.substr(first, newLength); } /** diff --git a/std/runtime/string_rt.spice b/std/runtime/string_rt.spice index 7c9ce13c9..1f8df23ad 100644 --- a/std/runtime/string_rt.spice +++ b/std/runtime/string_rt.spice @@ -1,5 +1,8 @@ #![core.compiler.alwaysKeepOnNameCollision = true] +// Std imports +import "std/text/analysis"; + // Link external functions // We intentionally do not use the memory_rt here to avoid dependency circles ext f malloc(unsigned long); @@ -604,6 +607,29 @@ public f String.getSubstring(unsigned IntLongShort startId return substring; } +/** + * Returns a new string without leading or trailing whitespaces. + * + * @return Trimmed string + */ +public f String.trim() { + if this.length == 0l { + return String(); + } + unsigned long startIdx = 0l; + unsigned long endIdx = this.length - 1l; + + unsafe { + // Find first char that is not a whitespace + while isWhitespace(this.contents[startIdx]) { startIdx++; } + // Find last char that is not a whitespace + while isWhitespace(this.contents[endIdx]) { endIdx--; } + } + + const unsigned long newLength = endIdx - startIdx + 1; + return this.getSubstring(startIdx, newLength); +} + /** * Reserves `charCount` items * diff --git a/test/test-files/std/runtime/string-basic-methods-non-modifying/source.spice b/test/test-files/std/runtime/string-basic-methods-non-modifying/source.spice index a94aa75ea..869536c90 100644 --- a/test/test-files/std/runtime/string-basic-methods-non-modifying/source.spice +++ b/test/test-files/std/runtime/string-basic-methods-non-modifying/source.spice @@ -4,6 +4,7 @@ f main() { dyn s2 = String("Hello"); dyn s3 = String("Hello!"); dyn s4 = String("Hello World!"); + dyn s5 = String(" \n\tString to be trimmed \r "); assert s1.isEmpty(); assert !s2.isEmpty(); @@ -40,6 +41,8 @@ f main() { assert !s4.startsWith("World"); assert s4.endsWith("!"); assert !s2.endsWith("!"); + assert s5.trim() == "String to be trimmed"; + assert s1.trim() == ""; printf("All assertions passed!"); } \ No newline at end of file From 7e95d4ad1b4dcc90add83522b65d865fbc692ef0 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sat, 11 Jan 2025 22:33:39 +0100 Subject: [PATCH 2/3] Fix refs --- .../debug-info/success-dbg-info-simple/ir-code.ll | 8 ++++---- .../string-basic-methods-non-modifying/source.spice | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/test-files/irgenerator/debug-info/success-dbg-info-simple/ir-code.ll b/test/test-files/irgenerator/debug-info/success-dbg-info-simple/ir-code.ll index ef54533f9..bcd90027c 100644 --- a/test/test-files/irgenerator/debug-info/success-dbg-info-simple/ir-code.ll +++ b/test/test-files/irgenerator/debug-info/success-dbg-info-simple/ir-code.ll @@ -118,14 +118,14 @@ attributes #2 = { nofree nounwind } !30 = !DIDerivedType(tag: DW_TAG_member, name: "lng", scope: !28, file: !7, line: 2, baseType: !31, size: 64) !31 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) !32 = !DIDerivedType(tag: DW_TAG_member, name: "str", scope: !28, file: !7, line: 3, baseType: !33, size: 192, align: 8, offset: 64) -!33 = !DICompositeType(tag: DW_TAG_structure_type, name: "String", scope: !7, file: !7, line: 18, size: 192, align: 8, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !34, identifier: "struct.String") +!33 = !DICompositeType(tag: DW_TAG_structure_type, name: "String", scope: !7, file: !7, line: 21, size: 192, align: 8, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !34, identifier: "struct.String") !34 = !{!35, !38, !40} -!35 = !DIDerivedType(tag: DW_TAG_member, name: "contents", scope: !33, file: !7, line: 19, baseType: !36, size: 64) +!35 = !DIDerivedType(tag: DW_TAG_member, name: "contents", scope: !33, file: !7, line: 22, baseType: !36, size: 64) !36 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !37, size: 64) !37 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char) -!38 = !DIDerivedType(tag: DW_TAG_member, name: "capacity", scope: !33, file: !7, line: 20, baseType: !39, size: 64, offset: 64) +!38 = !DIDerivedType(tag: DW_TAG_member, name: "capacity", scope: !33, file: !7, line: 23, baseType: !39, size: 64, offset: 64) !39 = !DIBasicType(name: "unsigned long", size: 64, encoding: DW_ATE_unsigned) -!40 = !DIDerivedType(tag: DW_TAG_member, name: "length", scope: !33, file: !7, line: 21, baseType: !39, size: 64, offset: 128) +!40 = !DIDerivedType(tag: DW_TAG_member, name: "length", scope: !33, file: !7, line: 24, baseType: !39, size: 64, offset: 128) !41 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !28, file: !7, line: 4, baseType: !42, size: 32, offset: 256) !42 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !43 = !{} diff --git a/test/test-files/std/runtime/string-basic-methods-non-modifying/source.spice b/test/test-files/std/runtime/string-basic-methods-non-modifying/source.spice index 869536c90..aa297686a 100644 --- a/test/test-files/std/runtime/string-basic-methods-non-modifying/source.spice +++ b/test/test-files/std/runtime/string-basic-methods-non-modifying/source.spice @@ -43,6 +43,7 @@ f main() { assert !s2.endsWith("!"); assert s5.trim() == "String to be trimmed"; assert s1.trim() == ""; + assert s3.trim() == s3; printf("All assertions passed!"); } \ No newline at end of file From 45317c1d04555b52a2c00a40748969bdc9f86a88 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sat, 11 Jan 2025 22:52:25 +0100 Subject: [PATCH 3/3] Fix bug in getSubstring --- std/runtime/string_rt.spice | 1 + 1 file changed, 1 insertion(+) diff --git a/std/runtime/string_rt.spice b/std/runtime/string_rt.spice index 1f8df23ad..3235553c6 100644 --- a/std/runtime/string_rt.spice +++ b/std/runtime/string_rt.spice @@ -591,6 +591,7 @@ public f String.getSubstring(unsigned IntLongShort startId // Get substring String substring = String(""); substring.reserve(length); + substring.length = length; const unsigned long endIdx = startIdx + length; for unsigned long charIndex = (unsigned long) startIdx; charIndex < endIdx; charIndex++ { unsafe {