summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorItamar <itamar8910@gmail.com>2021-03-12 17:04:08 +0200
committerAndreas Kling <kling@serenityos.org>2021-03-13 10:17:02 +0100
commit3658c4c567d4076614987a3ab74644df8d487fb0 (patch)
tree405db3786767576d46114b44f98052e2d72a8862
parentf21af0922aee3c5fe028f84846beed973b07926f (diff)
downloadserenity-3658c4c567d4076614987a3ab74644df8d487fb0.zip
LibCpp: Replace defined preprocessor values when parsing
-rw-r--r--Base/home/anon/Source/little/other.cpp1
-rw-r--r--Base/home/anon/Source/little/other.h2
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/ParserAutoComplete.cpp65
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/ParserAutoComplete.h34
-rw-r--r--Userland/Libraries/LibCpp/Parser.cpp45
-rw-r--r--Userland/Libraries/LibCpp/Parser.h18
-rw-r--r--Userland/Libraries/LibCpp/Preprocessor.cpp6
-rw-r--r--Userland/Libraries/LibCpp/Preprocessor.h7
8 files changed, 134 insertions, 44 deletions
diff --git a/Base/home/anon/Source/little/other.cpp b/Base/home/anon/Source/little/other.cpp
index 5ef3a12eb0..a35a49284a 100644
--- a/Base/home/anon/Source/little/other.cpp
+++ b/Base/home/anon/Source/little/other.cpp
@@ -5,6 +5,7 @@ int func()
{
int x = 1;
int y = 2;
+ INT_Z = 3;
StructInHeader mystruct;
printf("x: %d\n", x);
printf("y: %d\n", y);
diff --git a/Base/home/anon/Source/little/other.h b/Base/home/anon/Source/little/other.h
index dbc0f47901..54f64fd686 100644
--- a/Base/home/anon/Source/little/other.h
+++ b/Base/home/anon/Source/little/other.h
@@ -2,6 +2,8 @@ int func();
#define USE_VAR2
+#define INT_Z int z
+
struct StructInHeader {
int var1;
#ifdef USE_VAR2
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/ParserAutoComplete.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/ParserAutoComplete.cpp
index 56107d7d92..bc46722c31 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/ParserAutoComplete.cpp
+++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/ParserAutoComplete.cpp
@@ -64,9 +64,9 @@ OwnPtr<ParserAutoComplete::DocumentData> ParserAutoComplete::create_document_dat
if (!document)
return {};
auto content = document->text();
- auto document_data = make<DocumentData>(document->text(), file);
- auto root = document_data->parser.parse();
- for (auto& path : document_data->preprocessor.included_paths()) {
+ auto document_data = create_document_data(document->text(), file);
+ auto root = document_data->parser().parse();
+ for (auto& path : document_data->preprocessor().included_paths()) {
get_or_create_document_data(document_path_from_include_path(path));
}
#ifdef CPP_LANGUAGE_SERVER_DEBUG
@@ -83,14 +83,6 @@ void ParserAutoComplete::set_document_data(const String& file, OwnPtr<DocumentDa
m_documents.set(filedb().to_absolute_path(file), move(data));
}
-ParserAutoComplete::DocumentData::DocumentData(String&& _text, const String& _filename)
- : filename(_filename)
- , text(move(_text))
- , preprocessor(text.view())
- , parser(preprocessor.process().view(), filename)
-{
-}
-
Vector<GUI::AutocompleteProvider::Entry> ParserAutoComplete::get_suggestions(const String& file, const GUI::TextPosition& autocomplete_position)
{
Cpp::Position position { autocomplete_position.line(), autocomplete_position.column() > 0 ? autocomplete_position.column() - 1 : 0 };
@@ -102,7 +94,7 @@ Vector<GUI::AutocompleteProvider::Entry> ParserAutoComplete::get_suggestions(con
return {};
const auto& document = *document_ptr;
- auto node = document.parser.node_at(position);
+ auto node = document.parser().node_at(position);
if (!node) {
dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", position.line, position.column);
return {};
@@ -110,10 +102,10 @@ Vector<GUI::AutocompleteProvider::Entry> ParserAutoComplete::get_suggestions(con
if (node->is_identifier()) {
if (is_property(*node)) {
- return autocomplete_property(document, (MemberExpression&)(*node->parent()), document.parser.text_of_node(*node));
+ return autocomplete_property(document, (MemberExpression&)(*node->parent()), document.parser().text_of_node(*node));
}
- return autocomplete_name(document, *node, document.parser.text_of_node(*node));
+ return autocomplete_name(document, *node, document.parser().text_of_node(*node));
}
if (is_empty_property(document, *node, position)) {
@@ -122,9 +114,9 @@ Vector<GUI::AutocompleteProvider::Entry> ParserAutoComplete::get_suggestions(con
}
String partial_text = String::empty();
- auto containing_token = document.parser.token_at(position);
+ auto containing_token = document.parser().token_at(position);
if (containing_token.has_value()) {
- partial_text = document.parser.text_of_token(containing_token.value());
+ partial_text = document.parser().text_of_token(containing_token.value());
}
return autocomplete_name(document, *node, partial_text.view());
@@ -204,7 +196,7 @@ bool ParserAutoComplete::is_empty_property(const DocumentData& document, const A
{
if (!node.is_member_expression())
return false;
- auto previous_token = document.parser.token_at(autocomplete_position);
+ auto previous_token = document.parser().token_at(autocomplete_position);
if (!previous_token.has_value())
return false;
return previous_token.value().type() == Token::Type::Dot;
@@ -276,14 +268,14 @@ Vector<ParserAutoComplete::PropertyInfo> ParserAutoComplete::properties_of_type(
NonnullRefPtrVector<Declaration> ParserAutoComplete::get_declarations_in_outer_scope_including_headers(const DocumentData& document) const
{
NonnullRefPtrVector<Declaration> declarations;
- for (auto& include : document.preprocessor.included_paths()) {
+ for (auto& include : document.preprocessor().included_paths()) {
document_path_from_include_path(include);
auto included_document = get_document_data(document_path_from_include_path(include));
if (!included_document)
continue;
declarations.append(get_declarations_in_outer_scope_including_headers(*included_document));
}
- for (auto& decl : document.parser.root_node()->declarations()) {
+ for (auto& decl : document.parser().root_node()->declarations()) {
declarations.append(decl);
}
return declarations;
@@ -336,7 +328,7 @@ Optional<GUI::AutocompleteProvider::ProjectLocation> ParserAutoComplete::find_de
return {};
const auto& document = *document_ptr;
- auto node = document.parser.node_at(Cpp::Position { identifier_position.line(), identifier_position.column() });
+ auto node = document.parser().node_at(Cpp::Position { identifier_position.line(), identifier_position.column() });
if (!node) {
dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", identifier_position.line(), identifier_position.column());
return {};
@@ -350,7 +342,7 @@ Optional<GUI::AutocompleteProvider::ProjectLocation> ParserAutoComplete::find_de
RefPtr<Declaration> ParserAutoComplete::find_declaration_of(const DocumentData& document_data, const ASTNode& node) const
{
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "find_declaration_of: {}", document_data.parser.text_of_node(node));
+ dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "find_declaration_of: {}", document_data.parser().text_of_node(node));
auto declarations = get_available_declarations(document_data, node);
for (auto& decl : declarations) {
if (node.is_identifier() && decl.is_variable_or_parameter_declaration()) {
@@ -379,10 +371,10 @@ RefPtr<Declaration> ParserAutoComplete::find_declaration_of(const DocumentData&
void ParserAutoComplete::update_declared_symbols(const DocumentData& document)
{
Vector<GUI::AutocompleteProvider::Declaration> declarations;
- for (auto& decl : document.parser.root_node()->declarations()) {
- declarations.append({ decl.name(), { document.filename, decl.start().line, decl.start().column }, type_of_declaration(decl) });
+ for (auto& decl : document.parser().root_node()->declarations()) {
+ declarations.append({ decl.name(), { document.filename(), decl.start().line, decl.start().column }, type_of_declaration(decl) });
}
- set_declarations_of_document(document.filename, move(declarations));
+ set_declarations_of_document(document.filename(), move(declarations));
}
GUI::AutocompleteProvider::DeclarationType ParserAutoComplete::type_of_declaration(const Declaration& decl)
@@ -398,4 +390,29 @@ GUI::AutocompleteProvider::DeclarationType ParserAutoComplete::type_of_declarati
return GUI::AutocompleteProvider::DeclarationType::Variable;
}
+OwnPtr<ParserAutoComplete::DocumentData> ParserAutoComplete::create_document_data(String&& text, const String& filename)
+{
+ auto document_data = make<DocumentData>();
+ document_data->m_filename = move(filename);
+ document_data->m_text = move(text);
+ document_data->m_preprocessor = make<Preprocessor>(document_data->text());
+ document_data->preprocessor().process();
+
+ Preprocessor::Definitions all_definitions;
+ for (auto item : document_data->preprocessor().definitions())
+ all_definitions.set(move(item.key), move(item.value));
+
+ for (auto include : document_data->preprocessor().included_paths()) {
+
+ auto included_document = get_or_create_document_data(document_path_from_include_path(include));
+ if (!included_document)
+ continue;
+ for (auto item : included_document->parser().definitions())
+ all_definitions.set(move(item.key), move(item.value));
+ }
+
+ document_data->m_parser = make<Parser>(document_data->preprocessor().processed_text(), filename, move(all_definitions));
+ return document_data;
+}
+
}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/ParserAutoComplete.h b/Userland/DevTools/HackStudio/LanguageServers/Cpp/ParserAutoComplete.h
index 78412f932f..d06a416d9a 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/ParserAutoComplete.h
+++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/ParserAutoComplete.h
@@ -52,11 +52,33 @@ public:
private:
struct DocumentData {
- DocumentData(String&& text, const String& filename);
- String filename;
- String text;
- Preprocessor preprocessor;
- Parser parser;
+ const String& filename() const { return m_filename; }
+ const String& text() const { return m_text; }
+ const Preprocessor& preprocessor() const
+ {
+ VERIFY(m_preprocessor);
+ return *m_preprocessor;
+ }
+ Preprocessor& preprocessor()
+ {
+ VERIFY(m_preprocessor);
+ return *m_preprocessor;
+ }
+ const Parser& parser() const
+ {
+ VERIFY(m_parser);
+ return *m_parser;
+ }
+ Parser& parser()
+ {
+ VERIFY(m_parser);
+ return *m_parser;
+ }
+
+ String m_filename;
+ String m_text;
+ OwnPtr<Preprocessor> m_preprocessor;
+ OwnPtr<Parser> m_parser;
};
Vector<GUI::AutocompleteProvider::Entry> autocomplete_property(const DocumentData&, const MemberExpression&, const StringView partial_text) const;
@@ -85,6 +107,8 @@ private:
void update_declared_symbols(const DocumentData&);
GUI::AutocompleteProvider::DeclarationType type_of_declaration(const Declaration&);
+ OwnPtr<DocumentData> create_document_data(String&& text, const String& filename);
+
HashMap<String, OwnPtr<DocumentData>> m_documents;
};
diff --git a/Userland/Libraries/LibCpp/Parser.cpp b/Userland/Libraries/LibCpp/Parser.cpp
index 6b923d4958..57b212da23 100644
--- a/Userland/Libraries/LibCpp/Parser.cpp
+++ b/Userland/Libraries/LibCpp/Parser.cpp
@@ -37,26 +37,42 @@
namespace Cpp {
-Parser::Parser(const StringView& program, const String& filename)
+Parser::Parser(const StringView& program, const String& filename, Preprocessor::Definitions&& definitions)
: m_program(program)
+ , m_definitions(move(definitions))
, m_lines(m_program.split_view("\n", true))
, m_filename(filename)
{
- Lexer lexer(m_program);
- for (auto& token : lexer.lex()) {
- if (token.m_type == Token::Type::Whitespace)
- continue;
- m_tokens.append(move(token));
- }
+ initialize_program_tokens();
#if CPP_DEBUG
dbgln("Program:");
dbgln("{}", m_program);
dbgln("Tokens:");
for (auto& token : m_tokens) {
- dbgln("{} ({}:{}-{}:{})", token.to_string(), token.start().line, token.start().column, token.end().line, token.end().column);
+ StringView text;
+ if (token.m_start.line != token.m_end.line || token.m_start.column > token.m_end.column)
+ text = {};
+ else
+ text = text_of_token(token);
+ dbgln("{} {}:{}-{}:{} ({})", token.to_string(), token.start().line, token.start().column, token.end().line, token.end().column, text);
}
#endif
}
+void Parser::initialize_program_tokens()
+{
+ Lexer lexer(m_program);
+ for (auto& token : lexer.lex()) {
+ if (token.m_type == Token::Type::Whitespace)
+ continue;
+ if (token.m_type == Token::Type::Identifier) {
+ if (auto defined_value = m_definitions.find(text_of_token(token)); defined_value != m_definitions.end()) {
+ add_tokens_for_preprocessor(token, defined_value->value);
+ continue;
+ }
+ }
+ m_tokens.append(move(token));
+ }
+}
NonnullRefPtr<TranslationUnit> Parser::parse()
{
@@ -1097,5 +1113,18 @@ bool Parser::match_ellipsis()
return false;
return peek().type() == Token::Type::Dot && peek().type() == Token::Type::Dot && peek().type() == Token::Type::Dot;
}
+void Parser::add_tokens_for_preprocessor(Token& replaced_token, Preprocessor::DefinedValue& definition)
+{
+ if (!definition.value.has_value())
+ return;
+ Lexer lexer(definition.value.value());
+ for (auto token : lexer.lex()) {
+ if (token.type() == Token::Type::Whitespace)
+ continue;
+ token.m_start = replaced_token.start();
+ token.m_end = replaced_token.end();
+ m_tokens.append(move(token));
+ }
+}
}
diff --git a/Userland/Libraries/LibCpp/Parser.h b/Userland/Libraries/LibCpp/Parser.h
index 12cf2ffd12..789f0618aa 100644
--- a/Userland/Libraries/LibCpp/Parser.h
+++ b/Userland/Libraries/LibCpp/Parser.h
@@ -27,14 +27,17 @@
#pragma once
#include "AK/NonnullRefPtr.h"
+#include <AK/Noncopyable.h>
#include "AST.h"
+#include "Preprocessor.h"
#include <LibCpp/Lexer.h>
namespace Cpp {
class Parser final {
+ AK_MAKE_NONCOPYABLE(Parser);
public:
- explicit Parser(const StringView& program, const String& filename);
+ explicit Parser(const StringView& program, const String& filename, Preprocessor::Definitions&& = {});
~Parser() = default;
NonnullRefPtr<TranslationUnit> parse();
@@ -48,6 +51,7 @@ public:
StringView text_of_token(const Cpp::Token& token) const;
void print_tokens() const;
Vector<String> errors() const { return m_errors; }
+ const Preprocessor::Definitions& definitions() const {return m_definitions;}
private:
enum class DeclarationType {
@@ -151,7 +155,15 @@ private:
return node;
}
+ bool match_attribute_specification();
+ void consume_attribute_specification();
+ bool match_ellipsis();
+ void initialize_program_tokens();
+ void add_tokens_for_preprocessor(Token& replaced_token, Preprocessor::DefinedValue&);
+ Vector<StringView> parse_type_qualifiers();
+
StringView m_program;
+ Preprocessor::Definitions m_definitions;
Vector<StringView> m_lines;
String m_filename;
Vector<Token> m_tokens;
@@ -160,10 +172,6 @@ private:
RefPtr<TranslationUnit> m_root_node;
NonnullRefPtrVector<ASTNode> m_nodes;
Vector<String> m_errors;
- Vector<StringView> parse_type_qualifiers();
- bool match_attribute_specification();
- void consume_attribute_specification();
- bool match_ellipsis();
};
}
diff --git a/Userland/Libraries/LibCpp/Preprocessor.cpp b/Userland/Libraries/LibCpp/Preprocessor.cpp
index e276017455..5f4f2c29ae 100644
--- a/Userland/Libraries/LibCpp/Preprocessor.cpp
+++ b/Userland/Libraries/LibCpp/Preprocessor.cpp
@@ -182,4 +182,10 @@ void Preprocessor::handle_preprocessor_line(const StringView& line)
VERIFY_NOT_REACHED();
}
+const String& Preprocessor::processed_text()
+{
+ VERIFY(!m_processed_text.is_null());
+ return m_processed_text;
+}
+
};
diff --git a/Userland/Libraries/LibCpp/Preprocessor.h b/Userland/Libraries/LibCpp/Preprocessor.h
index cd402f72bd..e5702b396a 100644
--- a/Userland/Libraries/LibCpp/Preprocessor.h
+++ b/Userland/Libraries/LibCpp/Preprocessor.h
@@ -41,14 +41,17 @@ public:
const String& processed_text();
Vector<StringView> included_paths() const { return m_included_paths; }
-private:
struct DefinedValue {
Optional<StringView> value;
};
+ using Definitions = HashMap<StringView, DefinedValue>;
+
+ const Definitions& definitions() const { return m_definitions; }
+private:
void handle_preprocessor_line(const StringView&);
- HashMap<StringView, DefinedValue> m_definitions;
+ Definitions m_definitions;
const StringView m_program;
StringBuilder m_builder;
Vector<StringView> m_lines;