2022-07-18 18:26:57 -04:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <optional>
|
|
|
|
#include <string>
|
2024-03-30 19:49:07 -04:00
|
|
|
#include <tuple>
|
2022-07-18 18:26:57 -04:00
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
#include "common/util/FileUtil.h"
|
|
|
|
|
|
|
|
#include "decompiler/util/DecompilerTypeSystem.h"
|
2023-05-21 17:24:23 -04:00
|
|
|
#include "goalc/compiler/Compiler.h"
|
|
|
|
#include "goalc/compiler/docs/DocTypes.h"
|
2022-07-18 18:26:57 -04:00
|
|
|
#include "lsp/protocol/common_types.h"
|
|
|
|
#include "lsp/protocol/document_diagnostics.h"
|
|
|
|
#include "lsp/protocol/document_symbols.h"
|
2023-05-21 17:24:23 -04:00
|
|
|
#include "lsp/state/lsp_requester.h"
|
|
|
|
|
2024-03-30 19:49:07 -04:00
|
|
|
#include "third-party/tree-sitter/tree-sitter/lib/src/tree.h"
|
|
|
|
|
|
|
|
// TODO -
|
|
|
|
// https://sourcegraph.com/github.com/ensisoft/detonator@36f626caf957d0734865a8f5641be6170d997f45/-/blob/editor/app/lua-tools.cpp?L116:15-116:30
|
|
|
|
|
|
|
|
struct TreeSitterTreeDeleter {
|
|
|
|
void operator()(TSTree* ptr) const { ts_tree_delete(ptr); }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct OpenGOALFormResult {
|
|
|
|
std::vector<std::string> tokens;
|
|
|
|
std::pair<int, int> start_point;
|
|
|
|
std::pair<int, int> end_point;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct OGGlobalIndex {
|
|
|
|
std::unordered_map<std::string, Docs::SymbolDocumentation> global_symbols = {};
|
|
|
|
std::unordered_map<std::string, Docs::FileDocumentation> per_file_symbols = {};
|
|
|
|
};
|
|
|
|
|
2023-05-21 17:24:23 -04:00
|
|
|
class WorkspaceOGFile {
|
|
|
|
public:
|
|
|
|
WorkspaceOGFile(){};
|
2024-03-30 19:49:07 -04:00
|
|
|
WorkspaceOGFile(const LSPSpec::DocumentUri& uri,
|
|
|
|
const std::string& content,
|
|
|
|
const GameVersion& game_version);
|
|
|
|
LSPSpec::DocumentUri m_uri;
|
2023-05-28 13:22:00 -04:00
|
|
|
std::string m_content;
|
2024-03-30 19:49:07 -04:00
|
|
|
int m_line_count = 0;
|
|
|
|
std::string m_line_ending;
|
|
|
|
GameVersion m_game_version;
|
2023-05-21 17:24:23 -04:00
|
|
|
std::vector<LSPSpec::DocumentSymbol> m_symbols;
|
|
|
|
std::vector<LSPSpec::Diagnostic> m_diagnostics;
|
|
|
|
|
2024-03-30 19:49:07 -04:00
|
|
|
void parse_content(const std::string& new_content);
|
2024-04-01 18:56:55 -04:00
|
|
|
void update_symbols(const std::vector<symbol_info::SymbolInfo*>& symbol_infos);
|
2023-05-21 17:24:23 -04:00
|
|
|
std::optional<std::string> get_symbol_at_position(const LSPSpec::Position position) const;
|
2024-03-30 19:49:07 -04:00
|
|
|
std::vector<OpenGOALFormResult> search_for_forms_that_begin_with(
|
|
|
|
std::vector<std::string> prefix) const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
int32_t version;
|
|
|
|
std::shared_ptr<TSTree> m_ast;
|
2023-05-21 17:24:23 -04:00
|
|
|
};
|
2022-07-18 18:26:57 -04:00
|
|
|
|
|
|
|
class WorkspaceIRFile {
|
|
|
|
public:
|
|
|
|
WorkspaceIRFile(){};
|
|
|
|
WorkspaceIRFile(const std::string& content);
|
|
|
|
// TODO - make private
|
|
|
|
int32_t version;
|
|
|
|
std::vector<std::string> m_lines;
|
|
|
|
std::vector<LSPSpec::DocumentSymbol> m_symbols;
|
|
|
|
std::vector<LSPSpec::Diagnostic> m_diagnostics;
|
|
|
|
GameVersion m_game_version;
|
|
|
|
LSPSpec::DocumentUri m_all_types_uri = "";
|
|
|
|
fs::path m_all_types_file_path;
|
|
|
|
|
2023-05-21 17:24:23 -04:00
|
|
|
std::optional<std::string> get_mips_instruction_at_position(
|
|
|
|
const LSPSpec::Position position) const;
|
|
|
|
std::optional<std::string> get_symbol_at_position(const LSPSpec::Position position) const;
|
2022-07-18 18:26:57 -04:00
|
|
|
|
|
|
|
private:
|
|
|
|
void find_all_types_path(const std::string& line);
|
|
|
|
void find_function_symbol(const uint32_t line_num_zero_based, const std::string& line);
|
2023-05-21 17:24:23 -04:00
|
|
|
/// Make any relevant diagnostics on the IR line.
|
2022-07-18 18:26:57 -04:00
|
|
|
/// It's assumed each line in an IR can have atmost one diagnostic, and they are contained to just
|
|
|
|
/// that line!
|
2024-01-21 01:05:41 -05:00
|
|
|
void identify_diagnostics(const uint32_t line_num_zero_based,
|
|
|
|
const std::string& line,
|
|
|
|
const bool in_opengoal_block);
|
2022-07-18 18:26:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
class WorkspaceAllTypesFile {
|
|
|
|
public:
|
[goalc] Cleaned up speedups (#3066)
Started at 349,880,038 allocations and 42s
- Switched to making `Symbol` in GOOS be a "fixed type", just a wrapper
around a `const char*` pointing to the string in the symbol table. This
is a step toward making a lot of things better, but by itself not a huge
improvement. Some things may be worse due to more temp `std::string`
allocations, but one day all these can be removed. On linux it saved
allocations (347,685,429), and saved a second or two (41 s).
- cache `#t` and `#f` in interpreter, better lookup for special
forms/builtins (hashtable of pointers instead of strings, vector for the
small special form list). Dropped time to 38s.
- special-case in quasiquote when splicing is the last thing in a list.
Allocation dropped to 340,603,082
- custom hash table for environment lookups (lexical vars). Dropped to
36s and 314,637,194
- less allocation in `read_list` 311,613,616. Time about the same.
- `let` and `let*` in Interpreter.cpp 191,988,083, time down to 28s.
2023-10-07 10:48:17 -04:00
|
|
|
WorkspaceAllTypesFile()
|
|
|
|
: m_dts(std::make_unique<decompiler::DecompilerTypeSystem>(GameVersion::Jak1)){};
|
2022-07-18 18:26:57 -04:00
|
|
|
WorkspaceAllTypesFile(const LSPSpec::DocumentUri& uri,
|
|
|
|
const GameVersion version,
|
|
|
|
const fs::path file_path)
|
[goalc] Cleaned up speedups (#3066)
Started at 349,880,038 allocations and 42s
- Switched to making `Symbol` in GOOS be a "fixed type", just a wrapper
around a `const char*` pointing to the string in the symbol table. This
is a step toward making a lot of things better, but by itself not a huge
improvement. Some things may be worse due to more temp `std::string`
allocations, but one day all these can be removed. On linux it saved
allocations (347,685,429), and saved a second or two (41 s).
- cache `#t` and `#f` in interpreter, better lookup for special
forms/builtins (hashtable of pointers instead of strings, vector for the
small special form list). Dropped time to 38s.
- special-case in quasiquote when splicing is the last thing in a list.
Allocation dropped to 340,603,082
- custom hash table for environment lookups (lexical vars). Dropped to
36s and 314,637,194
- less allocation in `read_list` 311,613,616. Time about the same.
- `let` and `let*` in Interpreter.cpp 191,988,083, time down to 28s.
2023-10-07 10:48:17 -04:00
|
|
|
: m_game_version(version),
|
|
|
|
m_uri(uri),
|
|
|
|
m_dts(std::make_unique<decompiler::DecompilerTypeSystem>(m_game_version)),
|
|
|
|
m_file_path(file_path){};
|
2022-07-18 18:26:57 -04:00
|
|
|
|
|
|
|
GameVersion m_game_version;
|
|
|
|
LSPSpec::DocumentUri m_uri;
|
[goalc] Cleaned up speedups (#3066)
Started at 349,880,038 allocations and 42s
- Switched to making `Symbol` in GOOS be a "fixed type", just a wrapper
around a `const char*` pointing to the string in the symbol table. This
is a step toward making a lot of things better, but by itself not a huge
improvement. Some things may be worse due to more temp `std::string`
allocations, but one day all these can be removed. On linux it saved
allocations (347,685,429), and saved a second or two (41 s).
- cache `#t` and `#f` in interpreter, better lookup for special
forms/builtins (hashtable of pointers instead of strings, vector for the
small special form list). Dropped time to 38s.
- special-case in quasiquote when splicing is the last thing in a list.
Allocation dropped to 340,603,082
- custom hash table for environment lookups (lexical vars). Dropped to
36s and 314,637,194
- less allocation in `read_list` 311,613,616. Time about the same.
- `let` and `let*` in Interpreter.cpp 191,988,083, time down to 28s.
2023-10-07 10:48:17 -04:00
|
|
|
std::unique_ptr<decompiler::DecompilerTypeSystem> m_dts;
|
2022-07-18 18:26:57 -04:00
|
|
|
fs::path m_file_path;
|
|
|
|
|
|
|
|
void parse_type_system();
|
|
|
|
void update_type_system();
|
|
|
|
};
|
|
|
|
|
|
|
|
class Workspace {
|
|
|
|
public:
|
2023-05-21 17:24:23 -04:00
|
|
|
enum class FileType { OpenGOAL, OpenGOALIR, Unsupported };
|
2022-07-18 18:26:57 -04:00
|
|
|
Workspace();
|
|
|
|
virtual ~Workspace();
|
|
|
|
|
|
|
|
bool is_initialized();
|
|
|
|
void set_initialized(bool new_value);
|
|
|
|
|
2023-05-21 17:24:23 -04:00
|
|
|
// Even though when a file is initially opened it has the language id
|
|
|
|
// many subsequent requests only provide a uri to the file
|
|
|
|
// and it's a lot faster to check the end of a string, then multiple tracked file maps
|
|
|
|
FileType determine_filetype_from_languageid(const std::string& language_id);
|
|
|
|
FileType determine_filetype_from_uri(const LSPSpec::DocumentUri& file_uri);
|
2024-03-30 19:49:07 -04:00
|
|
|
std::optional<GameVersion> determine_game_version_from_uri(const LSPSpec::DocumentUri& uri);
|
2023-05-21 17:24:23 -04:00
|
|
|
|
2022-07-18 18:26:57 -04:00
|
|
|
void start_tracking_file(const LSPSpec::DocumentUri& file_uri,
|
|
|
|
const std::string& language_id,
|
|
|
|
const std::string& content);
|
|
|
|
void update_tracked_file(const LSPSpec::DocumentUri& file_uri, const std::string& content);
|
2024-03-30 19:49:07 -04:00
|
|
|
void tracked_file_will_save(const LSPSpec::DocumentUri& file_uri);
|
|
|
|
void update_global_index(const GameVersion game_version);
|
2022-07-18 18:26:57 -04:00
|
|
|
void stop_tracking_file(const LSPSpec::DocumentUri& file_uri);
|
2024-03-30 19:49:07 -04:00
|
|
|
std::optional<std::reference_wrapper<WorkspaceOGFile>> get_tracked_og_file(
|
|
|
|
const LSPSpec::URI& file_uri);
|
|
|
|
std::optional<std::reference_wrapper<WorkspaceIRFile>> get_tracked_ir_file(
|
|
|
|
const LSPSpec::URI& file_uri);
|
2022-09-16 20:28:44 -04:00
|
|
|
std::optional<DefinitionMetadata> get_definition_info_from_all_types(
|
2022-07-18 18:26:57 -04:00
|
|
|
const std::string& symbol_name,
|
2022-09-16 20:28:44 -04:00
|
|
|
const LSPSpec::DocumentUri& all_types_uri);
|
2024-04-01 18:56:55 -04:00
|
|
|
std::vector<symbol_info::SymbolInfo*> get_symbols_starting_with(const GameVersion game_version,
|
|
|
|
const std::string& symbol_prefix);
|
|
|
|
std::optional<symbol_info::SymbolInfo*> get_global_symbol_info(const WorkspaceOGFile& file,
|
|
|
|
const std::string& symbol_name);
|
2024-03-30 19:49:07 -04:00
|
|
|
std::optional<std::pair<TypeSpec, Type*>> get_symbol_typeinfo(const WorkspaceOGFile& file,
|
|
|
|
const std::string& symbol_name);
|
|
|
|
std::optional<symbol_info::DefinitionLocation> get_symbol_def_location(
|
|
|
|
const WorkspaceOGFile& file,
|
2024-04-01 18:56:55 -04:00
|
|
|
const symbol_info::SymbolInfo* symbol_info);
|
2024-03-30 19:49:07 -04:00
|
|
|
std::vector<std::tuple<std::string, std::string, Docs::DefinitionLocation>>
|
|
|
|
get_symbols_parent_type_path(const std::string& symbol_name, const GameVersion game_version);
|
|
|
|
std::vector<std::tuple<std::string, std::string, Docs::DefinitionLocation>> get_types_subtypes(
|
|
|
|
const std::string& symbol_name,
|
|
|
|
const GameVersion game_version);
|
|
|
|
std::unordered_map<std::string, s64> get_enum_entries(const std::string& enum_name,
|
|
|
|
const GameVersion game_version);
|
2022-07-18 18:26:57 -04:00
|
|
|
|
|
|
|
private:
|
2023-05-21 17:24:23 -04:00
|
|
|
LSPRequester m_requester;
|
2022-07-18 18:26:57 -04:00
|
|
|
bool m_initialized = false;
|
2023-05-21 17:24:23 -04:00
|
|
|
std::unordered_map<LSPSpec::DocumentUri, WorkspaceOGFile> m_tracked_og_files = {};
|
2022-07-18 18:26:57 -04:00
|
|
|
std::unordered_map<LSPSpec::DocumentUri, WorkspaceIRFile> m_tracked_ir_files = {};
|
[goalc] Cleaned up speedups (#3066)
Started at 349,880,038 allocations and 42s
- Switched to making `Symbol` in GOOS be a "fixed type", just a wrapper
around a `const char*` pointing to the string in the symbol table. This
is a step toward making a lot of things better, but by itself not a huge
improvement. Some things may be worse due to more temp `std::string`
allocations, but one day all these can be removed. On linux it saved
allocations (347,685,429), and saved a second or two (41 s).
- cache `#t` and `#f` in interpreter, better lookup for special
forms/builtins (hashtable of pointers instead of strings, vector for the
small special form list). Dropped time to 38s.
- special-case in quasiquote when splicing is the last thing in a list.
Allocation dropped to 340,603,082
- custom hash table for environment lookups (lexical vars). Dropped to
36s and 314,637,194
- less allocation in `read_list` 311,613,616. Time about the same.
- `let` and `let*` in Interpreter.cpp 191,988,083, time down to 28s.
2023-10-07 10:48:17 -04:00
|
|
|
std::unordered_map<LSPSpec::DocumentUri, std::unique_ptr<WorkspaceAllTypesFile>>
|
|
|
|
m_tracked_all_types_files = {};
|
2023-05-21 17:24:23 -04:00
|
|
|
|
|
|
|
// TODO:
|
|
|
|
// OpenGOAL is still incredibly tightly coupled to the jak projects as a language
|
|
|
|
//
|
|
|
|
// In the future, information like GameVersion should just be within the project file
|
|
|
|
// and then we can track projects instead of games
|
|
|
|
//
|
|
|
|
// Until that decoupling happens, things like this will remain fairly clunky.
|
2024-03-30 19:49:07 -04:00
|
|
|
// TODO - change this to a shared_ptr so it can more easily be passed around functions
|
2023-05-21 17:24:23 -04:00
|
|
|
std::unordered_map<GameVersion, std::unique_ptr<Compiler>> m_compiler_instances;
|
2024-03-30 19:49:07 -04:00
|
|
|
std::unordered_map<GameVersion, OGGlobalIndex> m_global_indicies;
|
2022-07-18 18:26:57 -04:00
|
|
|
};
|