ctype.ha (3500B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 def U: u8 = 0o1; 5 def L: u8 = 0o2; 6 def N: u8 = 0o4; 7 def S: u8 = 0o10; 8 def P: u8 = 0o20; 9 def C: u8 = 0o40; 10 def B: u8 = 0o100; 11 def X: u8 = 0o200; 12 13 // LUT of bitfields with character attributes 14 const cclass: []u8 = [ 15 // 0 1 2 3 4 5 6 7 16 C, C, C, C, C, C, C, C, // 0 17 C, S|C, S|C, S|C, S|C, S|C, C, C, // 10 18 C, C, C, C, C, C, C, C, // 20 19 C, C, C, C, C, C, C, C, // 30 20 S|B, P, P, P, P, P, P, P, // 40 21 P, P, P, P, P, P, P, P, // 50 22 N|X, N|X, N|X, N|X, N|X, N|X, N|X, N|X, // 60 23 N|X, N|X, P, P, P, P, P, P, // 70 24 P, U|X, U|X, U|X, U|X, U|X, U|X, U, // 100 25 U, U, U, U, U, U, U, U, // 110 26 U, U, U, U, U, U, U, U, // 120 27 U, U, U, P, P, P, P, P, // 130 28 P, L|X, L|X, L|X, L|X, L|X, L|X, L, // 140 29 L, L, L, L, L, L, L, L, // 150 30 L, L, L, L, L, L, L, L, // 160 31 L, L, L, P, P, P, P, C, // 170 32 ]; 33 34 // Returns true if an ASCII character is a letter. 35 export fn isalpha(c: rune) bool = 36 if (!valid(c)) false else cclass[c: u32] & (U | L) > 0; 37 38 // Returns true if an ASCII character is uppercase. 39 export fn isupper(c: rune) bool = 40 if (!valid(c)) false else cclass[c: u32] & U > 0; 41 42 // Returns true if an ASCII character is lowercase. 43 export fn islower(c: rune) bool = 44 if (!valid(c)) false else cclass[c: u32] & L > 0; 45 46 // Returns true if an ASCII character is a digit. 47 export fn isdigit(c: rune) bool = 48 if (!valid(c)) false else cclass[c: u32] & N > 0; 49 50 // Returns true if an ASCII character is a hexadecimal digit. 51 export fn isxdigit(c: rune) bool = 52 if (!valid(c)) false else cclass[c: u32] & X > 0; 53 54 // Returns true if an ASCII character is a white-space character - 55 // one of '\f', '\n', '\r', '\t', '\v', ' '. 56 export fn isspace(c: rune) bool = 57 if (!valid(c)) false else cclass[c: u32] & S > 0; 58 59 // Returns true if an ASCII character is punctuation. 60 export fn ispunct(c: rune) bool = 61 if (!valid(c)) false else cclass[c: u32] & P > 0; 62 63 // Returns true if an ASCII character is alphanumeric. 64 export fn isalnum(c: rune) bool = 65 if (!valid(c)) false else cclass[c: u32] & (U | L | N) > 0; 66 67 // Returns true if an ASCII character is printable. 68 export fn isprint(c: rune) bool = 69 if (!valid(c)) false else cclass[c: u32] & (P | U | L | N | B ) > 0; 70 71 // Returns true if an ASCII character is any printable character other than 72 // space. 73 export fn isgraph(c: rune) bool = 74 if (!valid(c)) false else cclass[c: u32] & (P | U | L | N) > 0; 75 76 // Returns true if an ASCII character is a control character. 77 export fn iscntrl(c: rune) bool = 78 if (!valid(c)) false else cclass[c: u32] & C > 0; 79 80 // Returns true if a rune is a space or a tab. 81 export fn isblank(c: rune) bool = (c == ' ' || c == '\t'); 82 83 // Returns the uppercase form of an ASCII character, or the original character 84 // if it was not a lowercase letter (or was not ASCII). 85 export fn toupper(c: rune) rune = { 86 return if (islower(c)) { 87 yield (c: u32 - 'a' + 'A'): rune; 88 } else c; 89 }; 90 91 // Returns the lowercase form of an ASCII character, or the original character 92 // if it was not an uppercase letter (or was not ASCII). 93 export fn tolower(c: rune) rune = { 94 return if (isupper(c)) { 95 yield (c: u32 - 'A' + 'a'): rune; 96 } else c; 97 }; 98 99 @test fn ctype() void = { 100 // Just some simple tests 101 assert(isspace(' ') && !isspace('x') && !isspace('こ')); 102 assert(isalnum('a') && isalnum('8') && !isalnum('こ')); 103 assert(!ispunct('\0') && iscntrl('\b')); 104 assert(tolower('A') == 'a' && tolower('こ') == 'こ'); 105 assert(isblank(' ') && isblank('\t') && !isblank('6')); 106 };