Skip to content

Commit

Permalink
feat: Document outline support
Browse files Browse the repository at this point in the history
  • Loading branch information
MaliMi97 authored Aug 18, 2021
1 parent 337be2f commit 9f65cd4
Show file tree
Hide file tree
Showing 38 changed files with 2,347 additions and 38 deletions.
83 changes: 82 additions & 1 deletion language_server/src/lsp/feature_language_features.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ void feature_language_features::register_methods(std::map<std::string, method>&
std::bind(&feature_language_features::completion, this, std::placeholders::_1, std::placeholders::_2));
methods.emplace("textDocument/semanticTokens/full",
std::bind(&feature_language_features::semantic_tokens, this, std::placeholders::_1, std::placeholders::_2));
methods.emplace("textDocument/documentSymbol",
std::bind(&feature_language_features::document_symbol, this, std::placeholders::_1, std::placeholders::_2));
}

json feature_language_features::register_capabilities()
Expand Down Expand Up @@ -68,7 +70,8 @@ json feature_language_features::register_capabilities()
"regexp", // self_def_type = 15
"parameter" } }, // ordinary_symbol = 16
{ "tokenModifiers", json::array() } } },
{ "full", true } } } };
{ "full", true } } },
{ "documentSymbolProvider", true } };
}

void feature_language_features::initialize_feature(const json&)
Expand Down Expand Up @@ -244,5 +247,83 @@ void feature_language_features::semantic_tokens(const json& id, const json& para
response_->respond(id, "", { { "data", num_array } });
}

// document symbol item kinds from the LSP specification
enum class lsp_document_symbol_item_kind
{
File = 1,
Module = 2,
Namespace = 3,
Package = 4,
Class = 5,
Method = 6,
Property = 7,
Field = 8,
Constructor = 9,
Enum = 10,
Interface = 11,
Function = 12,
Variable = 13,
Constant = 14,
String = 15,
Number = 16,
Boolean = 17,
Array = 18,
Object = 19,
Key = 20,
Null = 21,
EnumMember = 22,
Struct = 23,
Event = 24,
Operator = 25,
TypeParameter = 26
};


const std::unordered_map<parser_library::document_symbol_kind, lsp_document_symbol_item_kind>
document_symbol_item_kind_mapping { { parser_library::document_symbol_kind::DAT,
lsp_document_symbol_item_kind::Array },
{ parser_library::document_symbol_kind::EQU, lsp_document_symbol_item_kind::Boolean },
{ parser_library::document_symbol_kind::MACH, lsp_document_symbol_item_kind::Constant },
{ parser_library::document_symbol_kind::ASM, lsp_document_symbol_item_kind::Boolean },
{ parser_library::document_symbol_kind::UNKNOWN, lsp_document_symbol_item_kind::Operator },
{ parser_library::document_symbol_kind::VAR, lsp_document_symbol_item_kind::Variable },
{ parser_library::document_symbol_kind::SEQ, lsp_document_symbol_item_kind::String },
{ parser_library::document_symbol_kind::COMMON, lsp_document_symbol_item_kind::Struct },
{ parser_library::document_symbol_kind::DUMMY, lsp_document_symbol_item_kind::Class },
{ parser_library::document_symbol_kind::EXECUTABLE, lsp_document_symbol_item_kind::Object },
{ parser_library::document_symbol_kind::READONLY, lsp_document_symbol_item_kind::Enum },
{ parser_library::document_symbol_kind::EXTERNAL, lsp_document_symbol_item_kind::Enum },
{ parser_library::document_symbol_kind::WEAK_EXTERNAL, lsp_document_symbol_item_kind::Enum },
{ parser_library::document_symbol_kind::MACRO, lsp_document_symbol_item_kind::File } };

json feature_language_features::document_symbol_item_json(hlasm_plugin::parser_library::document_symbol_item symbol)
{
return { { "name", symbol.name() },
{ "kind", document_symbol_item_kind_mapping.at(symbol.kind()) },
{ "range", range_to_json(symbol.symbol_range()) },
{ "selectionRange", range_to_json(symbol.symbol_selection_range()) },
{ "children", document_symbol_list_json(symbol.children()) } };
}

json feature_language_features::document_symbol_list_json(
hlasm_plugin::parser_library::document_symbol_list symbol_list)
{
json result = json::array();
for (const auto& symbol : symbol_list)
{
result.push_back(document_symbol_item_json(symbol));
}
return result;
}

void feature_language_features::document_symbol(const json& id, const json& params)
{
auto document_uri = params["textDocument"]["uri"].get<std::string>();

auto symbol_list = ws_mngr_.document_symbol(uri_to_path(document_uri).c_str());

response_->respond(id, "", document_symbol_list_json(symbol_list));
}


} // namespace hlasm_plugin::language_server::lsp
3 changes: 3 additions & 0 deletions language_server/src/lsp/feature_language_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,11 @@ class feature_language_features : public feature
void hover(const json& id, const json& params);
void completion(const json& id, const json& params);
void semantic_tokens(const json& id, const json& params);
void document_symbol(const json& id, const json& params);

static json get_markup_content(std::string_view content);
json document_symbol_item_json(hlasm_plugin::parser_library::document_symbol_item symbol);
json document_symbol_list_json(hlasm_plugin::parser_library::document_symbol_list symbol_list);
};

} // namespace hlasm_plugin::language_server::lsp
Expand Down
1 change: 0 additions & 1 deletion language_server/src/lsp/lsp_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ void server::on_initialize(json id, const json& param)
} },
{ "documentHighlightProvider", false },
{ "renameProvider", false },
{ "documentSymbolProvider", false },
{ "workspaceSymbolProvider", false } } } };

for (auto& f : features_)
Expand Down
21 changes: 21 additions & 0 deletions language_server/test/lsp/feature_language_features_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,27 @@ TEST(language_features, references)
notifs["textDocument/references"]("", params1);
}

TEST(language_features, document_symbol)
{
using namespace ::testing;
parser_library::workspace_manager ws_mngr;
response_provider_mock response_mock;
lsp::feature_language_features f(ws_mngr, response_mock);
std::map<std::string, method> notifs;
f.register_methods(notifs);

std::string file_text = "A EQU 1";
ws_mngr.did_open_file("test", 0, file_text.c_str(), file_text.size());
json params1 = json::parse(R"({"textDocument":{"uri":")" + feature::path_to_uri("test") + "\"}}");

json r = { { "start", { { "line", 0 }, { "character", 0 } } }, { "end", { { "line", 0 }, { "character", 0 } } } };
json response = json::array();
response.push_back(
{ { "name", "A" }, { "kind", 17 }, { "range", r }, { "selectionRange", r }, { "children", json::array() } });
EXPECT_CALL(response_mock, respond(json(""), std::string(""), response));
notifs["textDocument/documentSymbol"]("", params1);
}

TEST(language_features, semantic_tokens)
{
using namespace ::testing;
Expand Down
39 changes: 38 additions & 1 deletion parser_library/include/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ struct variable_store;

namespace lsp {
struct completion_item_s;
}
struct document_symbol_item_s;
} // namespace lsp

struct location;
struct range_uri_s;
Expand Down Expand Up @@ -115,6 +116,42 @@ struct PARSER_LIBRARY_EXPORT completion_item
template class PARSER_LIBRARY_EXPORT sequence<completion_item, const lsp::completion_item_s*>;
using completion_list = sequence<completion_item, const lsp::completion_item_s*>;

enum class PARSER_LIBRARY_EXPORT document_symbol_kind
{
DAT = 0,
EQU = 1,
MACH = 2,
UNKNOWN = 3,
VAR = 4,
SEQ = 5,
COMMON = 6,
DUMMY = 7,
EXECUTABLE = 8,
READONLY = 9,
MACRO = 10,
ASM = 11,
EXTERNAL = 12,
WEAK_EXTERNAL = 13
};

struct PARSER_LIBRARY_EXPORT document_symbol_item;
using document_symbol_list = sequence<document_symbol_item, const lsp::document_symbol_item_s*>;

struct PARSER_LIBRARY_EXPORT document_symbol_item
{
explicit document_symbol_item(const lsp::document_symbol_item_s& item);
sequence<char> name() const;
document_symbol_kind kind() const;
range symbol_range() const;
range symbol_selection_range() const;
document_symbol_list children() const;

private:
const lsp::document_symbol_item_s& item_;
};

template class PARSER_LIBRARY_EXPORT sequence<document_symbol_item, const lsp::document_symbol_item_s*>;

struct PARSER_LIBRARY_EXPORT position_uri
{
explicit position_uri(const location& item);
Expand Down
1 change: 1 addition & 0 deletions parser_library/include/range.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ struct PARSER_LIBRARY_EXPORT range
, end(start)
{}
bool operator==(const range& r) const { return start == r.start && end == r.end; }
bool operator!=(const range& r) const { return !(*this == r); }
position start;
position end;
};
Expand Down
1 change: 1 addition & 0 deletions parser_library/include/workspace_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class PARSER_LIBRARY_EXPORT workspace_manager
const char* document_uri, position pos, char trigger_char, completion_trigger_kind trigger_kind);

virtual const std::vector<token_info>& semantic_tokens(const char* document_uri);
virtual document_symbol_list document_symbol(const char* document_uri);

virtual void configuration_changed(const lib_config& new_config);

Expand Down
17 changes: 11 additions & 6 deletions parser_library/src/context/hlasm_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ hlasm_context::hlasm_context(std::string file_name, asm_option asm_options, std:
, asm_options_(std::move(asm_options))
, instruction_map_(init_instruction_map())
, SYSNDX_(0)
, ord_ctx(*ids_)
, ord_ctx(*ids_, *this)
{
scope_stack_.emplace_back();
visited_files_.insert(file_name);
Expand Down Expand Up @@ -346,11 +346,14 @@ processing_stack_t hlasm_context::processing_stack() const

for (size_t i = 0; i < source_stack_.size(); ++i)
{
res.emplace_back(source_stack_[i].current_instruction, scope_stack_.front(), file_processing_type::OPENCODE);
res.emplace_back(source_stack_[i].current_instruction,
scope_stack_.front(),
file_processing_type::OPENCODE,
id_storage::empty_id);
for (const auto& member : source_stack_[i].copy_stack)
{
location loc(member.current_statement_position(), member.definition_location->file);
res.emplace_back(std::move(loc), scope_stack_.front(), file_processing_type::COPY);
res.emplace_back(std::move(loc), scope_stack_.front(), file_processing_type::COPY, member.name);
}

if (i == 0) // append macros immediately after ordinary processing
Expand All @@ -361,8 +364,10 @@ processing_stack_t hlasm_context::processing_stack() const

const auto& nest = scope_stack_[j].this_macro->copy_nests[offs];
for (size_t k = 0; k < nest.size(); ++k)
res.emplace_back(
nest[k], scope_stack_[j], k == 0 ? file_processing_type::MACRO : file_processing_type::COPY);
res.emplace_back(nest[k].loc,
scope_stack_[j],
k == 0 ? file_processing_type::MACRO : file_processing_type::COPY,
nest[k].member_name);
}
}
}
Expand All @@ -387,7 +392,7 @@ location hlasm_context::current_statement_location() const
{
const auto& mac_invo = scope_stack_.back().this_macro;

return mac_invo->copy_nests[mac_invo->current_statement].back();
return mac_invo->copy_nests[mac_invo->current_statement].back().loc;
}
}

Expand Down
11 changes: 10 additions & 1 deletion parser_library/src/context/macro.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <string>
#include <unordered_map>
#include <variant>

#include "common_types.h"
#include "copy_member.h"
Expand Down Expand Up @@ -44,10 +45,18 @@ struct macro_arg

class macro_definition;
struct macro_invocation;
struct copy_member;
using macro_invo_ptr = std::shared_ptr<macro_invocation>;
using macro_def_ptr = std::shared_ptr<macro_definition>;
using label_storage = std::unordered_map<id_index, sequence_symbol_ptr>;
using copy_nest_storage = std::vector<std::vector<location>>;

struct copy_nest_item
{
location loc;
id_index member_name;
};

using copy_nest_storage = std::vector<std::vector<copy_nest_item>>;

// class representing macro definition
// contains info about keyword, positional parameters of HLASM macro as well as list of statements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <stdexcept>

#include "alignment.h"
#include "context/hlasm_context.h"

namespace hlasm_plugin::parser_library::context {

Expand All @@ -30,16 +31,20 @@ void ordinary_assembly_context::create_private_section()

const std::vector<std::unique_ptr<section>>& ordinary_assembly_context::sections() const { return sections_; }

ordinary_assembly_context::ordinary_assembly_context(id_storage& storage)
const std::unordered_map<id_index, symbol>& ordinary_assembly_context::symbols() const { return symbols_; }

ordinary_assembly_context::ordinary_assembly_context(id_storage& storage, const hlasm_context& hlasm_ctx)
: curr_section_(nullptr)
, ids(storage)
, hlasm_ctx_(hlasm_ctx)
, symbol_dependencies(*this)
{}

bool ordinary_assembly_context::create_symbol(
id_index name, symbol_value value, symbol_attributes attributes, location symbol_location)
{
auto res = symbols_.try_emplace(name, name, value, attributes, std::move(symbol_location));
auto res =
symbols_.try_emplace(name, name, value, attributes, std::move(symbol_location), hlasm_ctx_.processing_stack());

if (!res.second)
throw std::runtime_error("symbol name in use");
Expand Down Expand Up @@ -78,6 +83,18 @@ symbol* ordinary_assembly_context::get_symbol(id_index name)
return tmp == symbols_.end() ? nullptr : &tmp->second;
}

section* ordinary_assembly_context::get_section(id_index name)
{
for (auto& tmp : sections_)
{
if (tmp->name == name)
{
return &(*tmp);
}
}
return nullptr;
}

const section* ordinary_assembly_context::current_section() const { return curr_section_; }

void ordinary_assembly_context::set_section(id_index name, section_kind kind, location symbol_location)
Expand All @@ -97,11 +114,17 @@ void ordinary_assembly_context::set_section(id_index name, section_kind kind, lo
curr_section_ = sections_.back().get();

auto tmp_addr = curr_section_->current_location_counter().current_address();
symbols_.try_emplace(name, name, tmp_addr, symbol_attributes::make_section_attrs(), std::move(symbol_location));
symbols_.try_emplace(name,
name,
tmp_addr,
symbol_attributes::make_section_attrs(),
std::move(symbol_location),
hlasm_ctx_.processing_stack());
}
}

void ordinary_assembly_context::create_external_section(id_index name, section_kind kind, location symbol_location)
void ordinary_assembly_context::create_external_section(
id_index name, section_kind kind, location symbol_location, processing_stack_t processing_stack)
{
const auto attrs = [kind]() {
switch (kind)
Expand All @@ -122,7 +145,8 @@ void ordinary_assembly_context::create_external_section(id_index name, section_k
->current_location_counter()
.current_address(),
attrs,
std::move(symbol_location))
std::move(symbol_location),
processing_stack)
.second)
throw std::invalid_argument("symbol already defined");
}
Expand All @@ -149,8 +173,12 @@ void ordinary_assembly_context::set_location_counter(id_index name, location sym
{
auto tmp_addr = curr_section_->current_location_counter().current_address();

auto sym_tmp = symbols_.try_emplace(
name, name, tmp_addr, symbol_attributes::make_section_attrs(), std::move(symbol_location));
auto sym_tmp = symbols_.try_emplace(name,
name,
tmp_addr,
symbol_attributes::make_section_attrs(),
std::move(symbol_location),
hlasm_ctx_.processing_stack());
if (!sym_tmp.second)
throw std::invalid_argument("symbol already defined");
}
Expand Down
Loading

0 comments on commit 9f65cd4

Please sign in to comment.