From a8554b4233c08e65882ff6869b6d94f974204dec Mon Sep 17 00:00:00 2001 From: Maxime Beaudoin <45009344+MaxBeaud@users.noreply.github.com> Date: Tue, 25 Mar 2025 09:25:23 -0400 Subject: [PATCH] String.c3 function parameters ambiguous (#2061) * Some tweaks. Fixes regression in `format` --------- Co-authored-by: Christoffer Lerno --- .gitignore | 1 + lib/std/core/string.c3 | 376 +++++++++++++++++++-------------------- src/compiler/sema_expr.c | 4 +- 3 files changed, 191 insertions(+), 190 deletions(-) diff --git a/.gitignore b/.gitignore index 27309c909..0e5a5bb63 100644 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,4 @@ result # tests /test/tmp/* /test/testrun +/test/test_suite_runner \ No newline at end of file diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index 5f567e8ad..547bfa0f2 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -120,120 +120,120 @@ fn String join(Allocator allocator, String[] s, String joiner) <* Remove characters from the front and end of a string. - @param [in] string : `The string to trim` + @param [in] self : `The string to trim` @param [in] to_trim : `The set of characters to trim, defaults to whitespace` @pure @return `a substring of the string passed in` *> -fn String String.trim(string, String to_trim = "\t\n\r ") +fn String String.trim(self, String to_trim = "\t\n\r ") { - return string.trim_left(to_trim).trim_right(to_trim); + return self.trim_left(to_trim).trim_right(to_trim); } <* Remove characters from the front of a string. - @param [in] string : `The string to trim` + @param [in] self : `The string to trim` @param [in] to_trim : `The set of characters to trim, defaults to whitespace` @pure @return `a substring of the string passed in` *> -fn String String.trim_left(string, String to_trim = "\t\n\r ") +fn String String.trim_left(self, String to_trim = "\t\n\r ") { usz start = 0; - usz len = string.len; - while (start < len && char_in_set(string[start], to_trim)) start++; - if (start == len) return string[:0]; - return string[start..]; + usz len = self.len; + while (start < len && char_in_set(self[start], to_trim)) start++; + if (start == len) return self[:0]; + return self[start..]; } <* Remove characters from the end of a string. - @param [in] string : `The string to trim` + @param [in] self : `The string to trim` @param [in] to_trim : `The set of characters to trim, defaults to whitespace` @pure @return `a substring of the string passed in` *> -fn String String.trim_right(string, String to_trim = "\t\n\r ") +fn String String.trim_right(self, String to_trim = "\t\n\r ") { - usz len = string.len; - while (len > 0 && char_in_set(string[len - 1], to_trim)) len--; - return string[:len]; + usz len = self.len; + while (len > 0 && char_in_set(self[len - 1], to_trim)) len--; + return self[:len]; } <* - Check if the String starts with the needle. + Check if the String starts with the prefix. - @param [in] string - @param [in] needle + @param [in] self + @param [in] prefix @pure - @return `'true' if the string starts with the needle` + @return `'true' if the string starts with the prefix` *> -fn bool String.starts_with(string, String needle) +fn bool String.starts_with(self, String prefix) { - if (needle.len > string.len) return false; - if (!needle.len) return true; - return string[:needle.len] == needle; + if (prefix.len > self.len) return false; + if (!prefix.len) return true; + return self[:prefix.len] == prefix; } <* - Check if the String ends with the needle. + Check if the String ends with the suffix. - @param [in] string - @param [in] needle + @param [in] self + @param [in] suffix @pure - @return `'true' if the string ends with the needle` + @return `'true' if the string ends with the suffix` *> -fn bool String.ends_with(string, String needle) +fn bool String.ends_with(self, String suffix) { - if (needle.len > string.len) return false; - if (!needle.len) return true; - return string[^needle.len..] == needle; + if (suffix.len > self.len) return false; + if (!suffix.len) return true; + return self[^suffix.len..] == suffix; } <* Strip the front of the string if the prefix exists. - @param [in] string - @param [in] needle + @param [in] self + @param [in] prefix @pure @return `the substring with the prefix removed` *> -fn String String.strip(string, String needle) +fn String String.strip(self, String prefix) { - if (!needle.len || !string.starts_with(needle)) return string; - return string[needle.len..]; + if (!prefix.len || !self.starts_with(prefix)) return self; + return self[prefix.len..]; } <* Strip the end of the string if the suffix exists. - @param [in] string - @param [in] needle + @param [in] self + @param [in] suffix @pure @return `the substring with the suffix removed` *> -fn String String.strip_end(string, String needle) +fn String String.strip_end(self, String suffix) { - if (!needle.len || !string.ends_with(needle)) return string; + if (!suffix.len || !self.ends_with(suffix)) return self; // Note that this is the safe way if we want to support zero length. - return string[:(string.len - needle.len)]; + return self[:(self.len - suffix.len)]; } <* Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" } - @param [in] s - @param [in] needle + @param [in] self + @param [in] delimiter @param max : "Max number of elements, 0 means no limit, defaults to 0" @param skip_empty : "True to skip empty elements" @param [&inout] allocator : "The allocator to use for the String[]" - @require needle.len > 0 : "The needle must be at least 1 character long" + @require delimiter.len > 0 : "The delimiter must be at least 1 character long" @ensure return.len > 0 *> -fn String[] String.split(s, Allocator allocator, String needle, usz max = 0, bool skip_empty = false) +fn String[] String.split(self, Allocator allocator, String delimiter, usz max = 0, bool skip_empty = false) { usz capacity = 16; usz i = 0; @@ -241,16 +241,16 @@ fn String[] String.split(s, Allocator allocator, String needle, usz max = 0, boo bool no_more = false; while (!no_more) { - usz? index = i == max - 1 ? NOT_FOUND? : s.index_of(needle); + usz? index = i == max - 1 ? NOT_FOUND? : self.index_of(delimiter); String res @noinit; if (try index) { - res = s[:index]; - s = s[index + needle.len..]; + res = self[:index]; + self = self[index + delimiter.len..]; } else { - res = s; + res = self; no_more = true; } if (!res.len && skip_empty) @@ -274,11 +274,11 @@ fn String[] String.split(s, Allocator allocator, String needle, usz max = 0, boo temporary allocator. @param [in] s - @param [in] needle + @param [in] delimiter @param max : "Max number of elements, 0 means no limit, defaults to 0" @param skip_empty : "True to skip empty elements" *> -fn String[] String.tsplit(s, String needle, usz max = 0, bool skip_empty = false) => s.split(tmem, needle, max, skip_empty) @inline; +fn String[] String.tsplit(s, String delimiter, usz max = 0, bool skip_empty = false) => s.split(tmem, delimiter, max, skip_empty) @inline; faultdef BUFFER_EXCEEDED; @@ -286,26 +286,26 @@ faultdef BUFFER_EXCEEDED; Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" } @param [in] s - @param [in] needle + @param [in] delimiter @param [inout] buffer @param max : "Max number of elements, 0 means no limit, defaults to 0" - @require needle.len > 0 : "The needle must be at least 1 character long" + @require delimiter.len > 0 : "The delimiter must be at least 1 character long" @ensure return.len > 0 @return? BUFFER_EXCEEDED : `If there are more elements than would fit the buffer` *> -fn String[]? String.split_to_buffer(s, String needle, String[] buffer, usz max = 0, bool skip_empty = false) +fn String[]? String.split_to_buffer(s, String delimiter, String[] buffer, usz max = 0, bool skip_empty = false) { usz max_capacity = buffer.len; usz i = 0; bool no_more = false; while (!no_more) { - usz? index = i == max - 1 ? NOT_FOUND? : s.index_of(needle); + usz? index = i == max - 1 ? NOT_FOUND? : s.index_of(delimiter); String res @noinit; if (try index) { res = s[:index]; - s = s[index + needle.len..]; + s = s[index + delimiter.len..]; } else { @@ -329,30 +329,30 @@ fn String[]? String.split_to_buffer(s, String needle, String[] buffer, usz max = Check if a substring is found in the string. @param [in] s - @param [in] needle : "The string to look for." + @param [in] substr : "The string to look for." @pure @return "true if the string contains the substring, false otherwise" *> -fn bool String.contains(s, String needle) +fn bool String.contains(s, String substr) { - return @ok(s.index_of(needle)); + return @ok(s.index_of(substr)); } <* Find the index of the first incidence of a string. - @param [in] s - @param needle : "The character to look for" + @param [in] self + @param character : "The character to look for" @pure - @ensure return < s.len - @return "the index of the needle" - @return? NOT_FOUND : "if the needle cannot be found" + @ensure return < self.len + @return "the index of the character" + @return? NOT_FOUND : "if the character cannot be found" *> -fn usz? String.index_of_char(s, char needle) +fn usz? String.index_of_char(self, char character) { - foreach (i, c : s) + foreach (i, c : self) { - if (c == needle) return i; + if (c == character) return i; } return NOT_FOUND?; } @@ -360,18 +360,18 @@ fn usz? String.index_of_char(s, char needle) <* Find the index of the first incidence of a one of the chars. - @param [in] s - @param [in] needle : "The characters to look for" + @param [in] self + @param [in] characters : "The characters to look for" @pure - @ensure return < s.len - @return "the index of the needle" - @return? NOT_FOUND : "if the needle cannot be found" + @ensure return < self.len + @return "the index of the character" + @return? NOT_FOUND : "if the character cannot be found" *> -fn usz? String.index_of_chars(String s, char[] needle) +fn usz? String.index_of_chars(String self, char[] characters) { - foreach (i, c : s) + foreach (i, c : self) { - foreach (j, pin : needle) + foreach (j, pin : characters) { if (c == pin) return i; } @@ -383,21 +383,21 @@ fn usz? String.index_of_chars(String s, char[] needle) <* Find the index of the first incidence of a character. - @param [in] s - @param needle : "The character to look for" + @param [in] self + @param character : "The character to look for" @param start_index : "The index to start with, may exceed max index." @pure - @ensure return < s.len - @return "the index of the needle" - @return? NOT_FOUND : "if the needle cannot be found starting from the start_index" + @ensure return < self.len + @return "the index of the character" + @return? NOT_FOUND : "if the character cannot be found starting from the start_index" *> -fn usz? String.index_of_char_from(s, char needle, usz start_index) +fn usz? String.index_of_char_from(self, char character, usz start_index) { - usz len = s.len; + usz len = self.len; if (len <= start_index) return NOT_FOUND?; for (usz i = start_index; i < len; i++) { - if (s[i] == needle) return i; + if (self[i] == character) return i; } return NOT_FOUND?; } @@ -405,18 +405,18 @@ fn usz? String.index_of_char_from(s, char needle, usz start_index) <* Find the index of the first incidence of a character starting from the end. - @param [in] s - @param needle : "the character to find" + @param [in] self + @param character : "the character to find" @pure - @ensure return < s.len - @return "the index of the needle" - @return? NOT_FOUND : "if the needle cannot be found" + @ensure return < self.len + @return "the index of the character" + @return? NOT_FOUND : "if the character cannot be found" *> -fn usz? String.rindex_of_char(s, char needle) +fn usz? String.rindex_of_char(self, char character) { - foreach_r (i, c : s) + foreach_r (i, c : self) { - if (c == needle) return i; + if (c == character) return i; } return NOT_FOUND?; } @@ -424,23 +424,23 @@ fn usz? String.rindex_of_char(s, char needle) <* Find the index of the first incidence of a string. - @param [in] s - @param [in] needle + @param [in] self + @param [in] substr @pure - @ensure return < s.len - @require needle.len > 0 : "The needle must be len 1 or more" - @return "the index of the needle" - @return? NOT_FOUND : "if the needle cannot be found" + @ensure return < self.len + @require substr.len > 0 : "The string must be len 1 or more" + @return "the index of the substring" + @return? NOT_FOUND : "if the substring cannot be found" *> -fn usz? String.index_of(s, String needle) +fn usz? String.index_of(self, String substr) { - usz needed = needle.len; - if (needed > 0 && s.len >= needed) + usz needed = substr.len; + if (needed > 0 && self.len >= needed) { - char first = needle[0]; - foreach (i, c: s[..^needed]) + char first = substr[0]; + foreach (i, c: self[..^needed]) { - if (c == first && s[i:needed] == needle) return i; + if (c == first && self[i : needed] == substr) return i; } } return NOT_FOUND?; @@ -449,31 +449,31 @@ fn usz? String.index_of(s, String needle) <* Find the index of the last incidence of a string. - @param [in] s - @param [in] needle + @param [in] self + @param [in] substr @pure - @ensure return < s.len - @require needle.len > 0 : "The needle must be len 1 or more" - @return "the index of the needle" - @return? NOT_FOUND : "if the needle cannot be found" + @ensure return < self.len + @require substr.len > 0 : "The substring must be len 1 or more" + @return "the index of the substring" + @return? NOT_FOUND : "if the substring cannot be found" *> -fn usz? String.rindex_of(s, String needle) +fn usz? String.rindex_of(self, String substr) { - usz needed = needle.len; - if (needed > 0 && s.len >= needed) + usz needed = substr.len; + if (needed > 0 && self.len >= needed) { - char first = needle[0]; - foreach_r (i, c: s[..^needed]) + char first = substr[0]; + foreach_r (i, c: self[..^needed]) { - if (c == first && s[i:needed] == needle) return i; + if (c == first && self[i : needed] == substr) return i; } } return NOT_FOUND?; } -fn String ZString.str_view(str) +fn String ZString.str_view(self) { - return (String)(str[:str.len()]); + return (String)(self[:self.len()]); } fn usz ZString.char_len(str) @@ -487,71 +487,71 @@ fn usz ZString.char_len(str) return len; } -fn usz ZString.len(str) +fn usz ZString.len(self) { usz len = 0; - char* ptr = (char*)str; + char* ptr = (char*)self; while (char c = ptr++[0]) len++; return len; } -fn ZString String.zstr_copy(s, Allocator allocator) +fn ZString String.zstr_copy(self, Allocator allocator) { - usz len = s.len; + usz len = self.len; char* str = allocator::malloc(allocator, len + 1); - mem::copy(str, s.ptr, len); + mem::copy(str, self.ptr, len); str[len] = 0; return (ZString)str; } -fn String String.concat(s1, Allocator allocator, String s2) +fn String String.concat(self, Allocator allocator, String s2) { - usz full_len = s1.len + s2.len; + usz full_len = self.len + s2.len; char* str = allocator::malloc(allocator, full_len + 1); - usz s1_len = s1.len; - mem::copy(str, s1.ptr, s1_len); - mem::copy(str + s1_len, s2.ptr, s2.len); + usz self_len = self.len; + mem::copy(str, self.ptr, self_len); + mem::copy(str + self_len, s2.ptr, s2.len); str[full_len] = 0; return (String)str[:full_len]; } -fn String String.tconcat(s1, String s2) => s1.concat(tmem, s2); +fn String String.tconcat(self, String s2) => self.concat(tmem, s2); -fn ZString String.zstr_tcopy(s) => s.zstr_copy(tmem) @inline; +fn ZString String.zstr_tcopy(self) => self.zstr_copy(tmem) @inline; <* Copy this string, by duplicating the string, always adding a zero byte sentinel, so that it safely can be converted to a ZString by a cast. *> -fn String String.copy(s, Allocator allocator) +fn String String.copy(self, Allocator allocator) { - usz len = s.len; + usz len = self.len; char* str = allocator::malloc(allocator, len + 1); - mem::copy(str, s.ptr, len); + mem::copy(str, self.ptr, len); str[len] = 0; return (String)str[:len]; } -fn void String.free(&s, Allocator allocator) +fn void String.free(&self, Allocator allocator) { - if (!s.ptr) return; - allocator::free(allocator, s.ptr); - *s = ""; + if (!self.ptr) return; + allocator::free(allocator, self.ptr); + *self = ""; } -fn String String.tcopy(s) => s.copy(tmem) @inline; +fn String String.tcopy(self) => self.copy(tmem) @inline; -fn String ZString.copy(z, Allocator allocator) +fn String ZString.copy(self, Allocator allocator) { - return z.str_view().copy(allocator) @inline; + return self.str_view().copy(allocator) @inline; } -fn String ZString.tcopy(z) +fn String ZString.tcopy(self) { - return z.str_view().copy(tmem) @inline; + return self.str_view().copy(tmem) @inline; } <* @@ -559,96 +559,96 @@ fn String ZString.tcopy(z) @return "The UTF-16 string as a slice, allocated using the given allocator" @return? INVALID_UTF8 : "If the string contained an invalid UTF-8 sequence" *> -fn Char16[]? String.to_utf16(s, Allocator allocator) +fn Char16[]? String.to_utf16(self, Allocator allocator) { - usz len16 = conv::utf16len_for_utf8(s); + usz len16 = conv::utf16len_for_utf8(self); Char16* data = allocator::alloc_array_try(allocator, Char16, len16 + 1)!; - conv::utf8to16_unsafe(s, data)!; + conv::utf8to16_unsafe(self, data)!; data[len16] = 0; return data[:len16]; } -fn Char16[]? String.to_temp_utf16(s) => s.to_utf16(tmem); +fn Char16[]? String.to_temp_utf16(self) => self.to_utf16(tmem); -fn WString? String.to_wstring(s, Allocator allocator) +fn WString? String.to_wstring(self, Allocator allocator) { - return (WString)s.to_utf16(allocator).ptr; + return (WString)self.to_utf16(allocator).ptr; } -fn WString? String.to_temp_wstring(s) => s.to_wstring(tmem); +fn WString? String.to_temp_wstring(self) => self.to_wstring(tmem); -fn Char32[]? String.to_utf32(s, Allocator allocator) +fn Char32[]? String.to_utf32(self, Allocator allocator) { - usz codepoints = conv::utf8_codepoints(s); + usz codepoints = conv::utf8_codepoints(self); Char32* data = allocator::alloc_array_try(allocator, Char32, codepoints + 1)!; - conv::utf8to32_unsafe(s, data)!; + conv::utf8to32_unsafe(self, data)!; data[codepoints] = 0; return data[:codepoints]; } -fn Char32[]? String.to_temp_utf32(s) => s.to_utf32(tmem); +fn Char32[]? String.to_temp_utf32(self) => self.to_utf32(tmem); <* Convert a string to ASCII lower case in place. - @param [inout] s + @param [inout] self @pure *> -fn void String.convert_to_lower(s) +fn void String.convert_to_lower(self) { - foreach (&c : s) if (c.is_upper() @pure) *c += 'a' - 'A'; + foreach (&c : self) if (c.is_upper() @pure) *c += 'a' - 'A'; } -fn String String.to_lower_copy(s, Allocator allocator) +fn String String.to_lower_copy(self, Allocator allocator) { - String copy = s.copy(allocator); + String copy = self.copy(allocator); copy.convert_to_lower(); return copy; } -fn String String.to_lower_tcopy(s) +fn String String.to_lower_tcopy(self) { - return s.to_lower_copy(tmem); + return self.to_lower_copy(tmem); } <* Convert a string to ASCII upper case. - @param [inout] s + @param [inout] self @pure *> -fn void String.convert_to_upper(s) +fn void String.convert_to_upper(self) { - foreach (&c : s) if (c.is_lower() @pure) *c -= 'a' - 'A'; + foreach (&c : self) if (c.is_lower() @pure) *c -= 'a' - 'A'; } <* Returns a string converted to ASCII upper case. - @param [in] s + @param [in] self @param [inout] allocator @return `a new String converted to ASCII upper case.` *> -fn String String.to_upper_copy(s, Allocator allocator) +fn String String.to_upper_copy(self, Allocator allocator) { - String copy = s.copy(allocator); + String copy = self.copy(allocator); copy.convert_to_upper(); return copy; } -fn StringIterator String.iterator(s) +fn StringIterator String.iterator(self) { - return { s, 0 }; + return { self, 0 }; } <* - @param [in] s + @param [in] self @return `a temporary String converted to ASCII upper case.` *> -fn String String.to_upper_tcopy(s) +fn String String.to_upper_tcopy(self) { - return s.to_upper_copy(tmem); + return self.to_upper_copy(tmem); } fn String? from_utf32(Allocator allocator, Char32[] utf32) @@ -696,15 +696,15 @@ fn usz String.utf8_codepoints(s) <* @require (base <= 10 && base > 1) || base == 16 : "Unsupported base" *> -macro String.to_integer(string, $Type, int base = 10) +macro String.to_integer(self, $Type, int base = 10) { - usz len = string.len; + usz len = self.len; usz index = 0; - char* ptr = string.ptr; + char* ptr = self.ptr; while (index < len && ascii::is_blank_m(ptr[index])) index++; if (len == index) return EMPTY_STRING?; bool is_negative; - switch (string[index]) + switch (self[index]) { case '-': if ($Type.min == 0) return NEGATIVE_VALUE?; @@ -717,11 +717,11 @@ macro String.to_integer(string, $Type, int base = 10) } if (len == index) return MALFORMED_INTEGER?; $Type base_used = ($Type)base; - if (string[index] == '0' && base == 10) + if (self[index] == '0' && base == 10) { index++; if (index == len) return ($Type)0; - switch (string[index]) + switch (self[index]) { case 'x': case 'X': @@ -743,7 +743,7 @@ macro String.to_integer(string, $Type, int base = 10) $Type value = 0; while (index != len) { - char c = string[index++]; + char c = self[index++]; switch { case base_used != 16 || c < 'A': c -= '0'; @@ -769,20 +769,20 @@ macro String.to_integer(string, $Type, int base = 10) return value; } -fn int128? String.to_int128(s, int base = 10) => s.to_integer(int128, base); -fn long? String.to_long(s, int base = 10) => s.to_integer(long, base); -fn int? String.to_int(s, int base = 10) => s.to_integer(int, base); -fn short? String.to_short(s, int base = 10) => s.to_integer(short, base); -fn ichar? String.to_ichar(s, int base = 10) => s.to_integer(ichar, base); +fn int128? String.to_int128(self, int base = 10) => self.to_integer(int128, base); +fn long? String.to_long(self, int base = 10) => self.to_integer(long, base); +fn int? String.to_int(self, int base = 10) => self.to_integer(int, base); +fn short? String.to_short(self, int base = 10) => self.to_integer(short, base); +fn ichar? String.to_ichar(self, int base = 10) => self.to_integer(ichar, base); -fn uint128? String.to_uint128(s, int base = 10) => s.to_integer(uint128, base); -fn ulong? String.to_ulong(s, int base = 10) => s.to_integer(ulong, base); -fn uint? String.to_uint(s, int base = 10) => s.to_integer(uint, base); -fn ushort? String.to_ushort(s, int base = 10) => s.to_integer(ushort, base); -fn char? String.to_uchar(s, int base = 10) => s.to_integer(char, base); +fn uint128? String.to_uint128(self, int base = 10) => self.to_integer(uint128, base); +fn ulong? String.to_ulong(self, int base = 10) => self.to_integer(ulong, base); +fn uint? String.to_uint(self, int base = 10) => self.to_integer(uint, base); +fn ushort? String.to_ushort(self, int base = 10) => self.to_integer(ushort, base); +fn char? String.to_uchar(self, int base = 10) => self.to_integer(char, base); -fn double? String.to_double(s) => s.to_real(double); -fn float? String.to_float(s) => s.to_real(float); +fn double? String.to_double(self) => self.to_real(double); +fn float? String.to_float(self) => self.to_real(float); fn Splitter String.splitter(self, String split) { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 265c40777..eeba597b6 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1867,7 +1867,7 @@ CHECK_FORMAT:; case 'E': case 'g': case 'G': - if (!type_is_number_or_bool(type)) + if (!type_is_number_or_bool(type) && !type_is_pointer_type(type)) { if (type->type_kind == TYPE_ENUM) { @@ -1877,7 +1877,7 @@ CHECK_FORMAT:; } goto NEXT; case 'p': - if (!type_is_pointer(type) && !type_is_integer(type)) + if (!type_is_pointer_type(type) && !type_is_integer(type)) { RETURN_SEMA_ERROR(vaargs[idx], "Expected a pointer here."); }