mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-24 02:12:09 -05:00
5c4890411b
SQL was standardized before there was consensus on sane language syntax constructs had evolved. The language is mostly case-insensitive, with unquoted text converted to upper case. Identifiers can include lower case characters and other 'special' characters by enclosing the identifier with double quotes. A double quote is escaped by doubling it. Likewise, a single quote in a literal string is escaped by doubling it. All this means that the strategy used in the lexer, where a token's value is a StringView 'window' on the source string, does not work, because the value needs to be massaged before being handed to the parser. Therefore a token now has a String containing its value. Given the limited lifetime of a token, this is acceptable overhead. Not doing this means that for example quote removal and double quote escaping would need to be done in the parser or in AST node construction, which would spread lexing basically all over the place. Which would be suboptimal. There was some impact on the sql utility and SyntaxHighlighter component which was addressed by storing the token's end position together with the start position in order to properly highlight it. Finally, reviewing the tests for parsing numeric literals revealed an inconsistency in which tokens we accept or reject: `1a` is accepted but `1e` is rejected. Related to this is the fate of `0x`. Added a FIXME reminding us to address this.
61 lines
1.6 KiB
C++
61 lines
1.6 KiB
C++
/*
|
|
* Copyright (c) 2021, Tim Flynn <trflynn89@pm.me>
|
|
* Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "Token.h"
|
|
#include <AK/HashMap.h>
|
|
#include <AK/String.h>
|
|
#include <AK/StringView.h>
|
|
|
|
namespace SQL::AST {
|
|
|
|
class Lexer {
|
|
public:
|
|
explicit Lexer(StringView source);
|
|
|
|
Token next();
|
|
|
|
private:
|
|
void consume(StringBuilder* = nullptr);
|
|
|
|
bool consume_whitespace_and_comments();
|
|
bool consume_numeric_literal(StringBuilder&);
|
|
bool consume_string_literal(StringBuilder&);
|
|
bool consume_quoted_identifier(StringBuilder&);
|
|
bool consume_blob_literal(StringBuilder&);
|
|
bool consume_exponent(StringBuilder&);
|
|
bool consume_hexadecimal_number(StringBuilder&);
|
|
|
|
bool match(char a, char b) const;
|
|
bool is_identifier_start() const;
|
|
bool is_identifier_middle() const;
|
|
bool is_numeric_literal_start() const;
|
|
bool is_string_literal_start() const;
|
|
bool is_string_literal_end() const;
|
|
bool is_quoted_identifier_start() const;
|
|
bool is_quoted_identifier_end() const;
|
|
bool is_blob_literal_start() const;
|
|
bool is_line_comment_start() const;
|
|
bool is_block_comment_start() const;
|
|
bool is_block_comment_end() const;
|
|
bool is_line_break() const;
|
|
bool is_eof() const;
|
|
|
|
static HashMap<String, TokenType> s_keywords;
|
|
static HashMap<char, TokenType> s_one_char_tokens;
|
|
static HashMap<String, TokenType> s_two_char_tokens;
|
|
|
|
StringView m_source;
|
|
size_t m_line_number { 1 };
|
|
size_t m_line_column { 0 };
|
|
char m_current_char { 0 };
|
|
bool m_eof { false };
|
|
size_t m_position { 0 };
|
|
};
|
|
|
|
}
|