AK: Remove the ctype adapters and use the actual ctype functions instead

This finally takes care of the kind-of excessive boilerplate code that were the
ctype adapters. On the other hand, I had to link `LibC/ctype.cpp` to the Kernel
(for `AK/JsonParser.cpp` and `AK/Format.cpp`). The previous commit actually makes
sense now: the `string.h` includes in `ctype.{h,cpp}` would require to link more LibC
stuff to the Kernel when it only needs the `_ctype_` array of `ctype.cpp`, and there
wasn't any string stuff used in ctype.
Instead of all this I could have put static derivatives of `is_any_of()` in the
concerned AK files, however that would have meant more boilerplate and workarounds;
so I went for the Kernel approach.
This commit is contained in:
Benoît Lormeau 2020-09-27 12:44:03 +02:00 committed by Andreas Kling
parent f158cb27ea
commit f0f6b09acb
Notes: sideshowbarker 2024-07-19 02:09:17 +09:00
8 changed files with 33 additions and 125 deletions

View file

@ -29,6 +29,7 @@
#include <AK/PrintfImplementation.h>
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <ctype.h>
namespace {
@ -79,7 +80,7 @@ static bool parse_number(GenericLexer& lexer, size_t& value)
bool consumed_at_least_one = false;
while (!lexer.is_eof()) {
if (lexer.next_is(is_digit)) {
if (lexer.next_is(isdigit)) {
value *= 10;
value += lexer.consume() - '0';
consumed_at_least_one = true;

View file

@ -188,7 +188,7 @@ StringView GenericLexer::consume_until(const char* stop)
*/
StringView GenericLexer::consume_quoted_string(char escape_char)
{
if (!is_quote(peek()))
if (!next_is(is_quote))
return {};
char quote_char = consume();
@ -264,75 +264,4 @@ void GenericLexer::ignore_until(const char* stop)
ignore(__builtin_strlen(stop));
}
// CType adapters
bool is_alpha(char c)
{
return is_lowercase(c) || is_uppercase(c);
}
bool is_alphanum(char c)
{
return is_alpha(c) || is_digit(c);
}
bool is_control(char c)
{
return (c >= 0 && c <= 31) || c == 127;
}
bool is_digit(char c)
{
return c >= '0' && c <= '9';
}
bool is_graphic(char c)
{
return c > ' ' && c <= '~';
}
bool is_hex_digit(char c)
{
return is_digit(c)
|| (c >= 'A' && c <= 'F')
|| (c >= 'a' && c <= 'f');
}
bool is_lowercase(char c)
{
return c >= 'a' && c <= 'z';
}
bool is_path_separator(char c)
{
return c == '/' || c == '\\';
}
bool is_printable(char c)
{
return c >= ' ' && c <= '~';
}
bool is_punctuation(char c)
{
return (c >= '!' && c <= '/')
|| (c >= ':' && c <= '@')
|| (c >= '[' && c <= '`')
|| (c >= '{' && c <= '~');
}
bool is_quote(char c)
{
return c == '\'' || c == '"';
}
bool is_uppercase(char c)
{
return c >= 'A' && c <= 'Z';
}
bool is_whitespace(char c)
{
return (c >= '\t' && c <= '\r') || c == ' ';
}
}

View file

@ -136,42 +136,12 @@ constexpr auto is_any_of(const StringView& values)
return [values](auto c) { return values.contains(c); };
}
/*
* CType adapters: pass them as Conditions to a GenericLexer's methods
* Examples:
* - `if (lexer.next_is(is_digit))`
* - `auto name = lexer.consume_while(is_alphanum);
* - `lexer.ignore_until(is_any_of("<^>"))`
*/
bool is_alpha(char);
bool is_alphanum(char);
bool is_control(char);
bool is_digit(char);
bool is_graphic(char);
bool is_hex_digit(char);
bool is_lowercase(char);
bool is_path_separator(char);
bool is_printable(char);
bool is_punctuation(char);
bool is_quote(char);
bool is_uppercase(char);
bool is_whitespace(char);
constexpr auto is_path_separator = is_any_of("/\\");
constexpr auto is_quote = is_any_of("'\"");
}
using AK::GenericLexer;
using AK::is_alpha;
using AK::is_alphanum;
using AK::is_any_of;
using AK::is_control;
using AK::is_digit;
using AK::is_graphic;
using AK::is_hex_digit;
using AK::is_lowercase;
using AK::is_path_separator;
using AK::is_printable;
using AK::is_punctuation;
using AK::is_quote;
using AK::is_uppercase;
using AK::is_whitespace;

View file

@ -28,6 +28,7 @@
#include <AK/JsonObject.h>
#include <AK/JsonParser.h>
#include <AK/Memory.h>
#include <ctype.h>
namespace AK {
@ -104,27 +105,27 @@ Optional<JsonValue> JsonParser::parse_object()
if (!consume_specific('{'))
return {};
for (;;) {
ignore_while(is_whitespace);
ignore_while(isspace);
if (peek() == '}')
break;
ignore_while(is_whitespace);
ignore_while(isspace);
auto name = consume_and_unescape_string();
if (name.is_null())
return {};
ignore_while(is_whitespace);
ignore_while(isspace);
if (!consume_specific(':'))
return {};
ignore_while(is_whitespace);
ignore_while(isspace);
auto value = parse_helper();
if (!value.has_value())
return {};
object.set(name, move(value.value()));
ignore_while(is_whitespace);
ignore_while(isspace);
if (peek() == '}')
break;
if (!consume_specific(','))
return {};
ignore_while(is_whitespace);
ignore_while(isspace);
if (peek() == '}')
return {};
}
@ -139,23 +140,23 @@ Optional<JsonValue> JsonParser::parse_array()
if (!consume_specific('['))
return {};
for (;;) {
ignore_while(is_whitespace);
ignore_while(isspace);
if (peek() == ']')
break;
auto element = parse_helper();
if (!element.has_value())
return {};
array.append(element.value());
ignore_while(is_whitespace);
ignore_while(isspace);
if (peek() == ']')
break;
if (!consume_specific(','))
return {};
ignore_while(is_whitespace);
ignore_while(isspace);
if (peek() == ']')
return {};
}
ignore_while(is_whitespace);
ignore_while(isspace);
if (!consume_specific(']'))
return {};
return array;
@ -260,7 +261,7 @@ Optional<JsonValue> JsonParser::parse_null()
Optional<JsonValue> JsonParser::parse_helper()
{
ignore_while(is_whitespace);
ignore_while(isspace);
auto type_hint = peek();
switch (type_hint) {
case '{':
@ -297,7 +298,7 @@ Optional<JsonValue> JsonParser::parse()
auto result = parse_helper();
if (!result.has_value())
return {};
ignore_while(is_whitespace);
ignore_while(isspace);
if (!is_eof())
return {};
return result;

View file

@ -34,6 +34,7 @@
#include <LibCore/File.h>
#include <LibJS/Parser.h>
#include <LibJS/Runtime/Function.h>
#include <ctype.h>
namespace Spreadsheet {
@ -192,8 +193,8 @@ Cell* Sheet::at(const Position& position)
Optional<Position> Sheet::parse_cell_name(const StringView& name)
{
GenericLexer lexer(name);
auto col = lexer.consume_while([](auto c) { return is_alpha(c); });
auto row = lexer.consume_while([](auto c) { return is_alphanum(c) && !is_alpha(c); });
auto col = lexer.consume_while(isalpha);
auto row = lexer.consume_while(isdigit);
if (!lexer.is_eof() || row.is_empty() || col.is_empty())
return {};

View file

@ -223,7 +223,6 @@ set(VT_SOURCES
../Libraries/LibVT/Line.cpp
)
set(KEYBOARD_SOURCES
../Libraries/LibKeyboard/CharacterMap.cpp
)
@ -233,6 +232,10 @@ set(CRYPTO_SOURCES
../Libraries/LibCrypto/Hash/SHA2.cpp
)
set(C_SOURCES
../Libraries/LibC/ctype.cpp
)
set(SOURCES
${KERNEL_SOURCES}
${AK_SOURCES}
@ -240,6 +243,7 @@ set(SOURCES
${VT_SOURCES}
${KEYBOARD_SOURCES}
${CRYPTO_SOURCES}
${C_SOURCES}
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option -DKERNEL")

View file

@ -35,6 +35,7 @@
#include <LibCore/ArgsParser.h>
#include <LibCore/File.h>
#include <LibCore/ProcessStatisticsReader.h>
#include <ctype.h>
#include <stdio.h>
struct OpenFile {
@ -56,8 +57,8 @@ static bool parse_name(StringView name, OpenFile& file)
return true;
} else {
file.type = component1;
auto component2 = lexer.consume_while([](char c) { return is_printable(c) && !is_whitespace(c) && c != '('; });
lexer.ignore_while(is_whitespace);
auto component2 = lexer.consume_while([](char c) { return isprint(c) && !isspace(c) && c != '('; });
lexer.ignore_while(isspace);
file.name = component2;
if (lexer.tell_remaining() == 0) {

View file

@ -34,6 +34,7 @@
#include <LibCore/File.h>
#include <LibProtocol/Client.h>
#include <LibProtocol/Download.h>
#include <ctype.h>
#include <stdio.h>
// FIXME: Move this somewhere else when it's needed (e.g. in the Browser)
@ -43,7 +44,7 @@ public:
{
GenericLexer lexer(value);
lexer.ignore_while(is_whitespace);
lexer.ignore_while(isspace);
if (lexer.consume_specific("inline")) {
m_kind = Kind::Inline;
@ -55,7 +56,7 @@ public:
if (lexer.consume_specific("attachment")) {
m_kind = Kind::Attachment;
if (lexer.consume_specific(";")) {
lexer.ignore_while(is_whitespace);
lexer.ignore_while(isspace);
if (lexer.consume_specific("filename=")) {
// RFC 2183: "A short (length <= 78 characters)
// parameter value containing only non-`tspecials' characters SHOULD be
@ -77,7 +78,7 @@ public:
if (lexer.consume_specific("form-data")) {
m_kind = Kind::FormData;
while (lexer.consume_specific(";")) {
lexer.ignore_while(is_whitespace);
lexer.ignore_while(isspace);
if (lexer.consume_specific("name=")) {
m_name = lexer.consume_quoted_string();
} else if (lexer.consume_specific("filename=")) {