diff --git a/vlib/builtin/int.v b/vlib/builtin/int.v index 00a44820a2..43e66566a7 100644 --- a/vlib/builtin/int.v +++ b/vlib/builtin/int.v @@ -484,7 +484,10 @@ pub fn (b byte) str_escaped() string { return str } -// Define this on byte as well, so that we can do `s[0].is_capital()` +// is_capital returns `true`, if the byte is a Latin capital letter. +// Example: assert `H`.is_capital() == true +// Example: assert 'h`.is_capital() == false +[inline] pub fn (c byte) is_capital() bool { return c >= `A` && c <= `Z` } diff --git a/vlib/builtin/js/byte.js.v b/vlib/builtin/js/byte.js.v index 0a75772f10..48e18e46ed 100644 --- a/vlib/builtin/js/byte.js.v +++ b/vlib/builtin/js/byte.js.v @@ -30,6 +30,7 @@ pub fn (c byte) repeat(count int) string { return res } +[inline] pub fn (c byte) is_digit() bool { return c >= `0` && c <= `9` } @@ -38,7 +39,7 @@ pub fn (c byte) is_digit() bool { // Example: assert byte(`F`) == true [inline] pub fn (c byte) is_hex_digit() bool { - return c.is_digit() || (c >= `a` && c <= `f`) || (c >= `A` && c <= `F`) + return (c >= `0` && c <= `9`) || (c >= `a` && c <= `f`) || (c >= `A` && c <= `F`) } // is_oct_digit returns `true` if the byte is in range 0-7 and `false` otherwise. @@ -66,10 +67,13 @@ pub fn (c byte) is_letter() bool { // Example: assert byte(`V`) == true [inline] pub fn (c byte) is_alnum() bool { - return c.is_letter() || c.is_digit() + return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) || (c >= `0` && c <= `9`) } -// Define this on byte as well, so that we can do `s[0].is_capital()` +// is_capital returns `true`, if the byte is a Latin capital letter. +// Example: assert `H`.is_capital() == true +// Example: assert 'h`.is_capital() == false +[inline] pub fn (c byte) is_capital() bool { return c >= `A` && c <= `Z` } diff --git a/vlib/builtin/js/string.js.v b/vlib/builtin/js/string.js.v index 9e51b9a3c1..7fecc19ef9 100644 --- a/vlib/builtin/js/string.js.v +++ b/vlib/builtin/js/string.js.v @@ -817,8 +817,10 @@ pub fn (s string) is_title() bool { return true } -// is_capital returns `true` if the first character in the string is a capital letter. +// is_capital returns `true`, if the first character in the string `s`, +// is a capital letter, and the rest are NOT. // Example: assert 'Hello'.is_capital() == true +// Example: assert 'HelloWorld'.is_capital() == false [direct_array_access] pub fn (s string) is_capital() bool { if s.len == 0 || !(s[0] >= `A` && s[0] <= `Z`) { @@ -832,6 +834,18 @@ pub fn (s string) is_capital() bool { return true } +// starts_with_capital returns `true`, if the first character in the string `s`, +// is a capital letter, even if the rest are not. +// Example: assert 'Hello'.starts_with_capital() == true +// Example: assert 'Hello. World.'.starts_with_capital() == true +[direct_array_access] +pub fn (s string) starts_with_capital() bool { + if s.len == 0 || !(s[0] >= `A` && s[0] <= `Z`) { + return false + } + return true +} + // is_upper returns `true` if all characters in the string is uppercase. // Example: assert 'HELLO V'.is_upper() == true pub fn (s string) is_upper() bool { diff --git a/vlib/builtin/js/string_test.js.v b/vlib/builtin/js/string_test.js.v index 71c608658e..953e7480bb 100644 --- a/vlib/builtin/js/string_test.js.v +++ b/vlib/builtin/js/string_test.js.v @@ -669,6 +669,14 @@ fn test_starts_with() { assert s.starts_with('Language') == false } +fn test_starts_with_capital() { + assert 'A sentence'.starts_with_capital() + assert 'A paragraph. It also does.'.starts_with_capital() + assert ''.starts_with_capital() == false + assert 'no'.starts_with_capital() == false + assert ' No'.starts_with_capital() == false +} + fn test_trim_prefix() { s := 'V Programming Language' assert s.trim_prefix('V ') == 'Programming Language' diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 50659192c8..6c54feedf7 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -1041,8 +1041,10 @@ pub fn (s string) capitalize() string { return res } -// is_capital returns `true` if the first character in the string is a capital letter. +// is_capital returns `true`, if the first character in the string `s`, +// is a capital letter, and the rest are NOT. // Example: assert 'Hello'.is_capital() == true +// Example: assert 'HelloWorld'.is_capital() == false [direct_array_access] pub fn (s string) is_capital() bool { if s.len == 0 || !(s[0] >= `A` && s[0] <= `Z`) { @@ -1056,6 +1058,18 @@ pub fn (s string) is_capital() bool { return true } +// starts_with_capital returns `true`, if the first character in the string `s`, +// is a capital letter, even if the rest are not. +// Example: assert 'Hello'.starts_with_capital() == true +// Example: assert 'Hello. World.'.starts_with_capital() == true +[direct_array_access] +pub fn (s string) starts_with_capital() bool { + if s.len == 0 || !(s[0] >= `A` && s[0] <= `Z`) { + return false + } + return true +} + // title returns the string with each word capitalized. // Example: assert 'hello v developer'.title() == 'Hello V Developer' pub fn (s string) title() string { @@ -1068,7 +1082,7 @@ pub fn (s string) title() string { return title } -// is_title returns true if all words of the string is capitalized. +// is_title returns true if all words of the string are capitalized. // Example: assert 'Hello V Developer'.is_title() == true pub fn (s string) is_title() bool { words := s.split(' ') @@ -1292,7 +1306,7 @@ pub fn (c byte) is_digit() bool { // Example: assert byte(`F`) == true [inline] pub fn (c byte) is_hex_digit() bool { - return c.is_digit() || (c >= `a` && c <= `f`) || (c >= `A` && c <= `F`) + return (c >= `0` && c <= `9`) || (c >= `a` && c <= `f`) || (c >= `A` && c <= `F`) } // is_oct_digit returns `true` if the byte is in range 0-7 and `false` otherwise. @@ -1320,7 +1334,7 @@ pub fn (c byte) is_letter() bool { // Example: assert byte(`V`) == true [inline] pub fn (c byte) is_alnum() bool { - return c.is_letter() || c.is_digit() + return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) || (c >= `0` && c <= `9`) } // free allows for manually freeing the memory occupied by the string diff --git a/vlib/builtin/string_test.v b/vlib/builtin/string_test.v index 0773006f6e..e04b8c25a4 100644 --- a/vlib/builtin/string_test.v +++ b/vlib/builtin/string_test.v @@ -686,6 +686,14 @@ fn test_starts_with() { assert s.starts_with('Language') == false } +fn test_starts_with_capital() { + assert 'A sentence'.starts_with_capital() + assert 'A paragraph. It also does.'.starts_with_capital() + assert ''.starts_with_capital() == false + assert 'no'.starts_with_capital() == false + assert ' No'.starts_with_capital() == false +} + fn test_trim_prefix() { s := 'V Programming Language' assert s.trim_prefix('V ') == 'Programming Language' diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 07c9ae9195..ab3ae1ec38 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -1184,8 +1184,12 @@ pub fn (t &TypeSymbol) embed_name() string { } pub fn (t &TypeSymbol) has_method(name string) bool { - t.find_method(name) or { return false } - return true + for method in t.methods { + if method.name == name { + return true + } + } + return false } pub fn (t &TypeSymbol) has_method_with_generic_parent(name string) bool { @@ -1295,8 +1299,10 @@ pub fn (i &Interface) find_method(name string) ?Fn { } pub fn (i &Interface) has_method(name string) bool { - if _ := i.find_method(name) { - return true + for method in i.methods { + if method.name == name { + return true + } } return false } diff --git a/vlib/v/util/scanning.v b/vlib/v/util/scanning.v index 997ffa666d..eee3c5129b 100644 --- a/vlib/v/util/scanning.v +++ b/vlib/v/util/scanning.v @@ -7,7 +7,7 @@ pub fn is_name_char(c byte) bool { [inline] pub fn is_func_char(c byte) bool { - return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) || c == `_` || c.is_digit() + return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) || c == `_` || (c >= `0` && c <= `9`) } pub fn contains_capital(s string) bool { @@ -21,6 +21,7 @@ pub fn contains_capital(s string) bool { // HTTPRequest bad // HttpRequest good +[direct_array_access] pub fn good_type_name(s string) bool { if s.len < 4 { return true @@ -34,9 +35,9 @@ pub fn good_type_name(s string) bool { } // is_generic_type_name returns true if the current token is a generic type name. -[inline] +[direct_array_access; inline] pub fn is_generic_type_name(name string) bool { - return name.len == 1 && name.is_capital() && name != 'C' + return name.len == 1 && name[0] != `C` && (name[0] >= `A` && name[0] <= `Z`) } pub fn cescaped_path(s string) string {