ladybird/Userland/Libraries/LibCpp/Preprocessor.h
Itamar c3c2fe153b LibCpp: Add "ignore invalid statements" option to Preprocessor
When we run the Preprocessor from the CppComprehensionEngine of
the language server, we don't want the preprocessor to crash if it
encounters an invalid preprocessor statement (for example, an #endif
statement without an accompanying previous #if statement).

To achieve this, this commit adds an "ignore_invalid_statements" flag
to the preprocessor which is set by the CppComprehensionEngine.

Fixes #11064.
2021-12-03 15:38:21 +01:00

99 lines
2.9 KiB
C++

/*
* Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/FlyString.h>
#include <AK/Function.h>
#include <AK/HashMap.h>
#include <AK/Optional.h>
#include <AK/String.h>
#include <AK/StringView.h>
#include <AK/Vector.h>
#include <LibCpp/Token.h>
namespace Cpp {
class Preprocessor {
public:
explicit Preprocessor(const String& filename, StringView program);
Vector<Token> process_and_lex();
Vector<StringView> included_paths() const { return m_included_paths; }
struct Definition {
String key;
Vector<String> parameters;
String value;
FlyString filename;
size_t line { 0 };
size_t column { 0 };
};
using Definitions = HashMap<String, Definition>;
struct Substitution {
Vector<Token> original_tokens;
Definition defined_value;
String processed_value;
};
Definitions const& definitions() const { return m_definitions; }
Vector<Substitution> const& substitutions() const { return m_substitutions; }
void set_ignore_unsupported_keywords(bool ignore) { m_options.ignore_unsupported_keywords = ignore; }
void set_ignore_invalid_statements(bool ignore) { m_options.ignore_invalid_statements = ignore; }
void set_keep_include_statements(bool keep) { m_options.keep_include_statements = keep; }
Function<Definitions(StringView)> definitions_in_header_callback { nullptr };
private:
void handle_preprocessor_statement(StringView);
void handle_include_statement(StringView);
void handle_preprocessor_keyword(StringView keyword, GenericLexer& line_lexer);
String remove_escaped_newlines(StringView value);
size_t do_substitution(Vector<Token> const& tokens, size_t token_index, Definition const&);
Optional<Definition> create_definition(StringView line);
struct MacroCall {
Token name;
struct Argument {
Vector<Token> tokens;
};
Vector<Argument> arguments;
size_t end_token_index { 0 };
};
Optional<MacroCall> parse_macro_call(Vector<Token> const& tokens, size_t token_index);
String evaluate_macro_call(MacroCall const&, Definition const&);
String m_filename;
String m_program;
Vector<Token> m_processed_tokens;
Definitions m_definitions;
Vector<Substitution> m_substitutions;
size_t m_current_line { 0 };
size_t m_current_depth { 0 };
Vector<size_t> m_depths_of_taken_branches;
Vector<size_t> m_depths_of_not_taken_branches;
enum class State {
Normal,
SkipIfBranch,
SkipElseBranch
};
State m_state { State::Normal };
Vector<StringView> m_included_paths;
struct Options {
bool ignore_unsupported_keywords { false };
bool ignore_invalid_statements { false };
bool keep_include_statements { false };
} m_options;
};
}