1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:37:35 +00:00

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
8 changed files with 33 additions and 125 deletions

View file

@ -29,6 +29,7 @@
#include <AK/PrintfImplementation.h> #include <AK/PrintfImplementation.h>
#include <AK/String.h> #include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <ctype.h>
namespace { namespace {
@ -79,7 +80,7 @@ static bool parse_number(GenericLexer& lexer, size_t& value)
bool consumed_at_least_one = false; bool consumed_at_least_one = false;
while (!lexer.is_eof()) { while (!lexer.is_eof()) {
if (lexer.next_is(is_digit)) { if (lexer.next_is(isdigit)) {
value *= 10; value *= 10;
value += lexer.consume() - '0'; value += lexer.consume() - '0';
consumed_at_least_one = true; 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) StringView GenericLexer::consume_quoted_string(char escape_char)
{ {
if (!is_quote(peek())) if (!next_is(is_quote))
return {}; return {};
char quote_char = consume(); char quote_char = consume();
@ -264,75 +264,4 @@ void GenericLexer::ignore_until(const char* stop)
ignore(__builtin_strlen(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); }; return [values](auto c) { return values.contains(c); };
} }
/* constexpr auto is_path_separator = is_any_of("/\\");
* CType adapters: pass them as Conditions to a GenericLexer's methods constexpr auto is_quote = is_any_of("'\"");
* 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);
} }
using AK::GenericLexer; using AK::GenericLexer;
using AK::is_alpha;
using AK::is_alphanum;
using AK::is_any_of; 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_path_separator;
using AK::is_printable;
using AK::is_punctuation;
using AK::is_quote; using AK::is_quote;
using AK::is_uppercase;
using AK::is_whitespace;

View file

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

View file

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

View file

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

View file

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

View file

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