|
|
@ -28,12 +28,10 @@
|
|
|
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
|
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
|
|
/*************************************************************************/
|
|
|
|
/*************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
// FIXME: Reenable LSP.
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "gdscript_extend_parser.h"
|
|
|
|
#include "gdscript_extend_parser.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "../gdscript.h"
|
|
|
|
#include "../gdscript.h"
|
|
|
|
|
|
|
|
#include "../gdscript_analyzer.h"
|
|
|
|
#include "core/io/json.h"
|
|
|
|
#include "core/io/json.h"
|
|
|
|
#include "gdscript_language_protocol.h"
|
|
|
|
#include "gdscript_language_protocol.h"
|
|
|
|
#include "gdscript_workspace.h"
|
|
|
|
#include "gdscript_workspace.h"
|
|
|
@ -41,15 +39,17 @@
|
|
|
|
void ExtendGDScriptParser::update_diagnostics() {
|
|
|
|
void ExtendGDScriptParser::update_diagnostics() {
|
|
|
|
diagnostics.clear();
|
|
|
|
diagnostics.clear();
|
|
|
|
|
|
|
|
|
|
|
|
if (has_error()) {
|
|
|
|
const List<ParserError> &errors = get_errors();
|
|
|
|
|
|
|
|
for (const List<ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) {
|
|
|
|
|
|
|
|
const ParserError &error = E->get();
|
|
|
|
lsp::Diagnostic diagnostic;
|
|
|
|
lsp::Diagnostic diagnostic;
|
|
|
|
diagnostic.severity = lsp::DiagnosticSeverity::Error;
|
|
|
|
diagnostic.severity = lsp::DiagnosticSeverity::Error;
|
|
|
|
diagnostic.message = get_error();
|
|
|
|
diagnostic.message = error.message;
|
|
|
|
diagnostic.source = "gdscript";
|
|
|
|
diagnostic.source = "gdscript";
|
|
|
|
diagnostic.code = -1;
|
|
|
|
diagnostic.code = -1;
|
|
|
|
lsp::Range range;
|
|
|
|
lsp::Range range;
|
|
|
|
lsp::Position pos;
|
|
|
|
lsp::Position pos;
|
|
|
|
int line = LINE_NUMBER_TO_INDEX(get_error_line());
|
|
|
|
int line = LINE_NUMBER_TO_INDEX(error.line);
|
|
|
|
const String &line_text = get_lines()[line];
|
|
|
|
const String &line_text = get_lines()[line];
|
|
|
|
pos.line = line;
|
|
|
|
pos.line = line;
|
|
|
|
pos.character = line_text.length() - line_text.strip_edges(true, false).length();
|
|
|
|
pos.character = line_text.length() - line_text.strip_edges(true, false).length();
|
|
|
@ -70,7 +70,7 @@ void ExtendGDScriptParser::update_diagnostics() {
|
|
|
|
diagnostic.code = warning.code;
|
|
|
|
diagnostic.code = warning.code;
|
|
|
|
lsp::Range range;
|
|
|
|
lsp::Range range;
|
|
|
|
lsp::Position pos;
|
|
|
|
lsp::Position pos;
|
|
|
|
int line = LINE_NUMBER_TO_INDEX(warning.line);
|
|
|
|
int line = LINE_NUMBER_TO_INDEX(warning.start_line);
|
|
|
|
const String &line_text = get_lines()[line];
|
|
|
|
const String &line_text = get_lines()[line];
|
|
|
|
pos.line = line;
|
|
|
|
pos.line = line;
|
|
|
|
pos.character = line_text.length() - line_text.strip_edges(true, false).length();
|
|
|
|
pos.character = line_text.length() - line_text.strip_edges(true, false).length();
|
|
|
@ -85,7 +85,7 @@ void ExtendGDScriptParser::update_diagnostics() {
|
|
|
|
void ExtendGDScriptParser::update_symbols() {
|
|
|
|
void ExtendGDScriptParser::update_symbols() {
|
|
|
|
members.clear();
|
|
|
|
members.clear();
|
|
|
|
|
|
|
|
|
|
|
|
const GDScriptParser::Node *head = get_parse_tree();
|
|
|
|
const GDScriptParser::Node *head = get_tree();
|
|
|
|
if (const GDScriptParser::ClassNode *gdclass = dynamic_cast<const GDScriptParser::ClassNode *>(head)) {
|
|
|
|
if (const GDScriptParser::ClassNode *gdclass = dynamic_cast<const GDScriptParser::ClassNode *>(head)) {
|
|
|
|
parse_class_symbol(gdclass, class_symbol);
|
|
|
|
parse_class_symbol(gdclass, class_symbol);
|
|
|
|
|
|
|
|
|
|
|
@ -109,15 +109,15 @@ void ExtendGDScriptParser::update_symbols() {
|
|
|
|
void ExtendGDScriptParser::update_document_links(const String &p_code) {
|
|
|
|
void ExtendGDScriptParser::update_document_links(const String &p_code) {
|
|
|
|
document_links.clear();
|
|
|
|
document_links.clear();
|
|
|
|
|
|
|
|
|
|
|
|
GDScriptTokenizerText tokenizer;
|
|
|
|
GDScriptTokenizer tokenizer;
|
|
|
|
FileAccessRef fs = FileAccess::create(FileAccess::ACCESS_RESOURCES);
|
|
|
|
FileAccessRef fs = FileAccess::create(FileAccess::ACCESS_RESOURCES);
|
|
|
|
tokenizer.set_code(p_code);
|
|
|
|
tokenizer.set_source_code(p_code);
|
|
|
|
while (true) {
|
|
|
|
while (true) {
|
|
|
|
GDScriptTokenizerText::Token token = tokenizer.get_token();
|
|
|
|
GDScriptTokenizer::Token token = tokenizer.scan();
|
|
|
|
if (token == GDScriptTokenizer::TK_EOF || token == GDScriptTokenizer::TK_ERROR) {
|
|
|
|
if (token.type == GDScriptTokenizer::Token::TK_EOF) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
} else if (token == GDScriptTokenizer::TK_CONSTANT) {
|
|
|
|
} else if (token.type == GDScriptTokenizer::Token::LITERAL) {
|
|
|
|
const Variant &const_val = tokenizer.get_token_constant();
|
|
|
|
const Variant &const_val = token.literal;
|
|
|
|
if (const_val.get_type() == Variant::STRING) {
|
|
|
|
if (const_val.get_type() == Variant::STRING) {
|
|
|
|
String path = const_val;
|
|
|
|
String path = const_val;
|
|
|
|
bool exists = fs->file_exists(path);
|
|
|
|
bool exists = fs->file_exists(path);
|
|
|
@ -129,15 +129,14 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) {
|
|
|
|
String value = const_val;
|
|
|
|
String value = const_val;
|
|
|
|
lsp::DocumentLink link;
|
|
|
|
lsp::DocumentLink link;
|
|
|
|
link.target = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_uri(path);
|
|
|
|
link.target = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_uri(path);
|
|
|
|
link.range.start.line = LINE_NUMBER_TO_INDEX(tokenizer.get_token_line());
|
|
|
|
link.range.start.line = LINE_NUMBER_TO_INDEX(token.start_line);
|
|
|
|
link.range.end.line = link.range.start.line;
|
|
|
|
link.range.end.line = LINE_NUMBER_TO_INDEX(token.end_line);
|
|
|
|
link.range.end.character = LINE_NUMBER_TO_INDEX(tokenizer.get_token_column());
|
|
|
|
link.range.start.character = LINE_NUMBER_TO_INDEX(token.start_column);
|
|
|
|
link.range.start.character = link.range.end.character - value.length();
|
|
|
|
link.range.end.character = LINE_NUMBER_TO_INDEX(token.end_column);
|
|
|
|
document_links.push_back(link);
|
|
|
|
document_links.push_back(link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tokenizer.advance();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -147,219 +146,238 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
|
|
|
|
r_symbol.uri = uri;
|
|
|
|
r_symbol.uri = uri;
|
|
|
|
r_symbol.script_path = path;
|
|
|
|
r_symbol.script_path = path;
|
|
|
|
r_symbol.children.clear();
|
|
|
|
r_symbol.children.clear();
|
|
|
|
r_symbol.name = p_class->name;
|
|
|
|
r_symbol.name = p_class->identifier != nullptr ? String(p_class->identifier->name) : String();
|
|
|
|
if (r_symbol.name.empty()) {
|
|
|
|
if (r_symbol.name.empty()) {
|
|
|
|
r_symbol.name = path.get_file();
|
|
|
|
r_symbol.name = path.get_file();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r_symbol.kind = lsp::SymbolKind::Class;
|
|
|
|
r_symbol.kind = lsp::SymbolKind::Class;
|
|
|
|
r_symbol.deprecated = false;
|
|
|
|
r_symbol.deprecated = false;
|
|
|
|
r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_class->line);
|
|
|
|
r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_class->start_line);
|
|
|
|
r_symbol.range.start.character = p_class->column;
|
|
|
|
r_symbol.range.start.character = LINE_NUMBER_TO_INDEX(p_class->start_column);
|
|
|
|
r_symbol.range.end.line = LINE_NUMBER_TO_INDEX(p_class->end_line);
|
|
|
|
r_symbol.range.end.line = LINE_NUMBER_TO_INDEX(p_class->end_line);
|
|
|
|
r_symbol.selectionRange.start.line = r_symbol.range.start.line;
|
|
|
|
r_symbol.selectionRange.start.line = r_symbol.range.start.line;
|
|
|
|
r_symbol.detail = "class " + r_symbol.name;
|
|
|
|
r_symbol.detail = "class " + r_symbol.name;
|
|
|
|
bool is_root_class = &r_symbol == &class_symbol;
|
|
|
|
bool is_root_class = &r_symbol == &class_symbol;
|
|
|
|
r_symbol.documentation = parse_documentation(is_root_class ? 0 : LINE_NUMBER_TO_INDEX(p_class->line), is_root_class);
|
|
|
|
r_symbol.documentation = parse_documentation(is_root_class ? 0 : LINE_NUMBER_TO_INDEX(p_class->start_line), is_root_class);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < p_class->variables.size(); ++i) {
|
|
|
|
for (int i = 0; i < p_class->members.size(); i++) {
|
|
|
|
const GDScriptParser::ClassNode::Member &m = p_class->variables[i];
|
|
|
|
const ClassNode::Member &m = p_class->members[i];
|
|
|
|
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
switch (m.type) {
|
|
|
|
symbol.name = m.identifier;
|
|
|
|
case ClassNode::Member::VARIABLE: {
|
|
|
|
symbol.kind = lsp::SymbolKind::Variable;
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
symbol.deprecated = false;
|
|
|
|
symbol.name = m.variable->identifier->name;
|
|
|
|
const int line = LINE_NUMBER_TO_INDEX(m.line);
|
|
|
|
symbol.kind = lsp::SymbolKind::Variable;
|
|
|
|
symbol.range.start.line = line;
|
|
|
|
symbol.deprecated = false;
|
|
|
|
symbol.range.start.character = lines[line].length() - lines[line].strip_edges(true, false).length();
|
|
|
|
symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.variable->start_line);
|
|
|
|
symbol.range.end.line = line;
|
|
|
|
symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.variable->start_column);
|
|
|
|
symbol.range.end.character = lines[line].length();
|
|
|
|
symbol.range.end.line = LINE_NUMBER_TO_INDEX(m.variable->end_line);
|
|
|
|
symbol.selectionRange.start.line = symbol.range.start.line;
|
|
|
|
symbol.range.end.character = LINE_NUMBER_TO_INDEX(m.variable->end_column);
|
|
|
|
if (m._export.type != Variant::NIL) {
|
|
|
|
symbol.selectionRange.start.line = symbol.range.start.line;
|
|
|
|
symbol.detail += "export ";
|
|
|
|
if (m.variable->exported) {
|
|
|
|
}
|
|
|
|
symbol.detail += "@export ";
|
|
|
|
symbol.detail += "var " + m.identifier;
|
|
|
|
|
|
|
|
if (m.data_type.kind != GDScriptParser::DataType::UNRESOLVED) {
|
|
|
|
|
|
|
|
symbol.detail += ": " + m.data_type.to_string();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m.default_value.get_type() != Variant::NIL) {
|
|
|
|
|
|
|
|
symbol.detail += " = " + JSON::print(m.default_value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
symbol.documentation = parse_documentation(line);
|
|
|
|
|
|
|
|
symbol.uri = uri;
|
|
|
|
|
|
|
|
symbol.script_path = path;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < p_class->_signals.size(); ++i) {
|
|
|
|
|
|
|
|
const GDScriptParser::ClassNode::Signal &signal = p_class->_signals[i];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
|
|
|
|
symbol.name = signal.name;
|
|
|
|
|
|
|
|
symbol.kind = lsp::SymbolKind::Event;
|
|
|
|
|
|
|
|
symbol.deprecated = false;
|
|
|
|
|
|
|
|
const int line = LINE_NUMBER_TO_INDEX(signal.line);
|
|
|
|
|
|
|
|
symbol.range.start.line = line;
|
|
|
|
|
|
|
|
symbol.range.start.character = lines[line].length() - lines[line].strip_edges(true, false).length();
|
|
|
|
|
|
|
|
symbol.range.end.line = symbol.range.start.line;
|
|
|
|
|
|
|
|
symbol.range.end.character = lines[line].length();
|
|
|
|
|
|
|
|
symbol.selectionRange.start.line = symbol.range.start.line;
|
|
|
|
|
|
|
|
symbol.documentation = parse_documentation(line);
|
|
|
|
|
|
|
|
symbol.uri = uri;
|
|
|
|
|
|
|
|
symbol.script_path = path;
|
|
|
|
|
|
|
|
symbol.detail = "signal " + signal.name + "(";
|
|
|
|
|
|
|
|
for (int j = 0; j < signal.arguments.size(); j++) {
|
|
|
|
|
|
|
|
if (j > 0) {
|
|
|
|
|
|
|
|
symbol.detail += ", ";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
symbol.detail += signal.arguments[j];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
symbol.detail += ")";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_class->constant_expressions.front(); E; E = E->next()) {
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
|
|
|
|
const GDScriptParser::ClassNode::Constant &c = E->value();
|
|
|
|
|
|
|
|
const GDScriptParser::ConstantNode *node = dynamic_cast<const GDScriptParser::ConstantNode *>(c.expression);
|
|
|
|
|
|
|
|
ERR_FAIL_COND(!node);
|
|
|
|
|
|
|
|
symbol.name = E->key();
|
|
|
|
|
|
|
|
symbol.kind = lsp::SymbolKind::Constant;
|
|
|
|
|
|
|
|
symbol.deprecated = false;
|
|
|
|
|
|
|
|
const int line = LINE_NUMBER_TO_INDEX(E->get().expression->line);
|
|
|
|
|
|
|
|
symbol.range.start.line = line;
|
|
|
|
|
|
|
|
symbol.range.start.character = E->get().expression->column;
|
|
|
|
|
|
|
|
symbol.range.end.line = symbol.range.start.line;
|
|
|
|
|
|
|
|
symbol.range.end.character = lines[line].length();
|
|
|
|
|
|
|
|
symbol.selectionRange.start.line = symbol.range.start.line;
|
|
|
|
|
|
|
|
symbol.documentation = parse_documentation(line);
|
|
|
|
|
|
|
|
symbol.uri = uri;
|
|
|
|
|
|
|
|
symbol.script_path = path;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
symbol.detail = "const " + symbol.name;
|
|
|
|
|
|
|
|
if (c.type.kind != GDScriptParser::DataType::UNRESOLVED) {
|
|
|
|
|
|
|
|
symbol.detail += ": " + c.type.to_string();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String value_text;
|
|
|
|
|
|
|
|
if (node->value.get_type() == Variant::OBJECT) {
|
|
|
|
|
|
|
|
RES res = node->value;
|
|
|
|
|
|
|
|
if (res.is_valid() && !res->get_path().empty()) {
|
|
|
|
|
|
|
|
value_text = "preload(\"" + res->get_path() + "\")";
|
|
|
|
|
|
|
|
if (symbol.documentation.empty()) {
|
|
|
|
|
|
|
|
if (Map<String, ExtendGDScriptParser *>::Element *S = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(res->get_path())) {
|
|
|
|
|
|
|
|
symbol.documentation = S->get()->class_symbol.documentation;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
symbol.detail += "var " + m.variable->identifier->name;
|
|
|
|
value_text = JSON::print(node->value);
|
|
|
|
if (m.get_datatype().is_hard_type()) {
|
|
|
|
}
|
|
|
|
symbol.detail += ": " + m.get_datatype().to_string();
|
|
|
|
} else {
|
|
|
|
}
|
|
|
|
value_text = JSON::print(node->value);
|
|
|
|
if (m.variable->initializer != nullptr && m.variable->initializer->is_constant) {
|
|
|
|
|
|
|
|
symbol.detail += " = " + JSON::print(m.variable->initializer->reduced_value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.variable->start_line));
|
|
|
|
|
|
|
|
symbol.uri = uri;
|
|
|
|
|
|
|
|
symbol.script_path = path;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::CONSTANT: {
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
symbol.name = m.constant->identifier->name;
|
|
|
|
|
|
|
|
symbol.kind = lsp::SymbolKind::Constant;
|
|
|
|
|
|
|
|
symbol.deprecated = false;
|
|
|
|
|
|
|
|
symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.constant->start_line);
|
|
|
|
|
|
|
|
symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.constant->start_column);
|
|
|
|
|
|
|
|
symbol.range.end.line = LINE_NUMBER_TO_INDEX(m.constant->end_line);
|
|
|
|
|
|
|
|
symbol.range.end.character = LINE_NUMBER_TO_INDEX(m.constant->start_column);
|
|
|
|
|
|
|
|
symbol.selectionRange.start.line = LINE_NUMBER_TO_INDEX(m.constant->start_line);
|
|
|
|
|
|
|
|
symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.constant->start_line));
|
|
|
|
|
|
|
|
symbol.uri = uri;
|
|
|
|
|
|
|
|
symbol.script_path = path;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
symbol.detail = "const " + symbol.name;
|
|
|
|
|
|
|
|
if (m.constant->get_datatype().is_hard_type()) {
|
|
|
|
|
|
|
|
symbol.detail += ": " + m.constant->get_datatype().to_string();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Variant &default_value = m.constant->initializer->reduced_value;
|
|
|
|
|
|
|
|
String value_text;
|
|
|
|
|
|
|
|
if (default_value.get_type() == Variant::OBJECT) {
|
|
|
|
|
|
|
|
RES res = default_value;
|
|
|
|
|
|
|
|
if (res.is_valid() && !res->get_path().empty()) {
|
|
|
|
|
|
|
|
value_text = "preload(\"" + res->get_path() + "\")";
|
|
|
|
|
|
|
|
if (symbol.documentation.empty()) {
|
|
|
|
|
|
|
|
if (Map<String, ExtendGDScriptParser *>::Element *S = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(res->get_path())) {
|
|
|
|
|
|
|
|
symbol.documentation = S->get()->class_symbol.documentation;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
value_text = JSON::print(default_value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
value_text = JSON::print(default_value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!value_text.empty()) {
|
|
|
|
|
|
|
|
symbol.detail += " = " + value_text;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::ENUM_VALUE: {
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
symbol.name = m.constant->identifier->name;
|
|
|
|
|
|
|
|
symbol.kind = lsp::SymbolKind::EnumMember;
|
|
|
|
|
|
|
|
symbol.deprecated = false;
|
|
|
|
|
|
|
|
symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.enum_value.line);
|
|
|
|
|
|
|
|
symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.enum_value.leftmost_column);
|
|
|
|
|
|
|
|
symbol.range.end.line = LINE_NUMBER_TO_INDEX(m.enum_value.line);
|
|
|
|
|
|
|
|
symbol.range.end.character = LINE_NUMBER_TO_INDEX(m.enum_value.rightmost_column);
|
|
|
|
|
|
|
|
symbol.selectionRange.start.line = LINE_NUMBER_TO_INDEX(m.enum_value.line);
|
|
|
|
|
|
|
|
symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.enum_value.line));
|
|
|
|
|
|
|
|
symbol.uri = uri;
|
|
|
|
|
|
|
|
symbol.script_path = path;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
symbol.detail = symbol.name + " = " + itos(m.enum_value.value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::SIGNAL: {
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
|
|
|
|
symbol.name = m.signal->identifier->name;
|
|
|
|
|
|
|
|
symbol.kind = lsp::SymbolKind::Event;
|
|
|
|
|
|
|
|
symbol.deprecated = false;
|
|
|
|
|
|
|
|
symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.signal->start_line);
|
|
|
|
|
|
|
|
symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.signal->start_column);
|
|
|
|
|
|
|
|
symbol.range.end.line = LINE_NUMBER_TO_INDEX(m.signal->end_line);
|
|
|
|
|
|
|
|
symbol.range.end.character = LINE_NUMBER_TO_INDEX(m.signal->end_column);
|
|
|
|
|
|
|
|
symbol.selectionRange.start.line = symbol.range.start.line;
|
|
|
|
|
|
|
|
symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.signal->start_line));
|
|
|
|
|
|
|
|
symbol.uri = uri;
|
|
|
|
|
|
|
|
symbol.script_path = path;
|
|
|
|
|
|
|
|
symbol.detail = "signal " + String(m.signal->identifier->name) + "(";
|
|
|
|
|
|
|
|
for (int j = 0; j < m.signal->parameters.size(); j++) {
|
|
|
|
|
|
|
|
if (j > 0) {
|
|
|
|
|
|
|
|
symbol.detail += ", ";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
symbol.detail += m.signal->parameters[i]->identifier->name;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
symbol.detail += ")";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::ENUM: {
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
|
|
|
|
symbol.kind = lsp::SymbolKind::Enum;
|
|
|
|
|
|
|
|
symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.m_enum->start_line);
|
|
|
|
|
|
|
|
symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.m_enum->start_column);
|
|
|
|
|
|
|
|
symbol.range.end.line = LINE_NUMBER_TO_INDEX(m.m_enum->end_line);
|
|
|
|
|
|
|
|
symbol.range.end.character = LINE_NUMBER_TO_INDEX(m.m_enum->end_column);
|
|
|
|
|
|
|
|
symbol.selectionRange.start.line = symbol.range.start.line;
|
|
|
|
|
|
|
|
symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.m_enum->start_line));
|
|
|
|
|
|
|
|
symbol.uri = uri;
|
|
|
|
|
|
|
|
symbol.script_path = path;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
symbol.detail = "enum " + String(m.m_enum->identifier->name) + "{";
|
|
|
|
|
|
|
|
for (int i = 0; i < m.m_enum->values.size(); i++) {
|
|
|
|
|
|
|
|
if (i > 0) {
|
|
|
|
|
|
|
|
symbol.detail += ", ";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
symbol.detail += String(m.m_enum->values[i].identifier->name) + " = " + itos(m.m_enum->values[i].value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
symbol.detail += "}";
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::FUNCTION: {
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
|
|
|
|
parse_function_symbol(m.function, symbol);
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::CLASS: {
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
|
|
|
|
parse_class_symbol(m.m_class, symbol);
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::UNDEFINED:
|
|
|
|
|
|
|
|
break; // Unreachable.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!value_text.empty()) {
|
|
|
|
|
|
|
|
symbol.detail += " = " + value_text;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < p_class->functions.size(); ++i) {
|
|
|
|
|
|
|
|
const GDScriptParser::FunctionNode *func = p_class->functions[i];
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
|
|
|
|
parse_function_symbol(func, symbol);
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < p_class->static_functions.size(); ++i) {
|
|
|
|
|
|
|
|
const GDScriptParser::FunctionNode *func = p_class->static_functions[i];
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
|
|
|
|
parse_function_symbol(func, symbol);
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < p_class->subclasses.size(); ++i) {
|
|
|
|
|
|
|
|
const GDScriptParser::ClassNode *subclass = p_class->subclasses[i];
|
|
|
|
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
|
|
|
|
parse_class_symbol(subclass, symbol);
|
|
|
|
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionNode *p_func, lsp::DocumentSymbol &r_symbol) {
|
|
|
|
void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionNode *p_func, lsp::DocumentSymbol &r_symbol) {
|
|
|
|
const String uri = get_uri();
|
|
|
|
const String uri = get_uri();
|
|
|
|
|
|
|
|
|
|
|
|
r_symbol.name = p_func->name;
|
|
|
|
r_symbol.name = p_func->identifier->name;
|
|
|
|
r_symbol.kind = lsp::SymbolKind::Function;
|
|
|
|
r_symbol.kind = lsp::SymbolKind::Function;
|
|
|
|
r_symbol.detail = "func " + p_func->name + "(";
|
|
|
|
r_symbol.detail = "func " + String(p_func->identifier->name) + "(";
|
|
|
|
r_symbol.deprecated = false;
|
|
|
|
r_symbol.deprecated = false;
|
|
|
|
const int line = LINE_NUMBER_TO_INDEX(p_func->line);
|
|
|
|
r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_func->start_line);
|
|
|
|
r_symbol.range.start.line = line;
|
|
|
|
r_symbol.range.start.character = LINE_NUMBER_TO_INDEX(p_func->start_column);
|
|
|
|
r_symbol.range.start.character = p_func->column;
|
|
|
|
r_symbol.range.end.line = LINE_NUMBER_TO_INDEX(p_func->start_line);
|
|
|
|
r_symbol.range.end.line = MAX(p_func->body->end_line - 2, r_symbol.range.start.line);
|
|
|
|
r_symbol.range.end.character = LINE_NUMBER_TO_INDEX(p_func->end_column);
|
|
|
|
r_symbol.range.end.character = lines[r_symbol.range.end.line].length();
|
|
|
|
|
|
|
|
r_symbol.selectionRange.start.line = r_symbol.range.start.line;
|
|
|
|
r_symbol.selectionRange.start.line = r_symbol.range.start.line;
|
|
|
|
r_symbol.documentation = parse_documentation(line);
|
|
|
|
r_symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(p_func->start_line));
|
|
|
|
r_symbol.uri = uri;
|
|
|
|
r_symbol.uri = uri;
|
|
|
|
r_symbol.script_path = path;
|
|
|
|
r_symbol.script_path = path;
|
|
|
|
|
|
|
|
|
|
|
|
String arguments;
|
|
|
|
String parameters;
|
|
|
|
for (int i = 0; i < p_func->arguments.size(); i++) {
|
|
|
|
for (int i = 0; i < p_func->parameters.size(); i++) {
|
|
|
|
|
|
|
|
const ParameterNode *parameter = p_func->parameters[i];
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
symbol.kind = lsp::SymbolKind::Variable;
|
|
|
|
symbol.kind = lsp::SymbolKind::Variable;
|
|
|
|
symbol.name = p_func->arguments[i];
|
|
|
|
symbol.name = parameter->identifier->name;
|
|
|
|
symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_func->body->line);
|
|
|
|
symbol.range.start.line = LINE_NUMBER_TO_INDEX(parameter->start_line);
|
|
|
|
symbol.range.start.character = p_func->body->column;
|
|
|
|
symbol.range.start.character = LINE_NUMBER_TO_INDEX(parameter->start_line);
|
|
|
|
symbol.range.end = symbol.range.start;
|
|
|
|
symbol.range.end.line = LINE_NUMBER_TO_INDEX(parameter->end_line);
|
|
|
|
|
|
|
|
symbol.range.end.character = LINE_NUMBER_TO_INDEX(parameter->end_column);
|
|
|
|
symbol.uri = uri;
|
|
|
|
symbol.uri = uri;
|
|
|
|
symbol.script_path = path;
|
|
|
|
symbol.script_path = path;
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
if (i > 0) {
|
|
|
|
if (i > 0) {
|
|
|
|
arguments += ", ";
|
|
|
|
parameters += ", ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
arguments += String(p_func->arguments[i]);
|
|
|
|
parameters += String(parameter->identifier->name);
|
|
|
|
if (p_func->argument_types[i].kind != GDScriptParser::DataType::UNRESOLVED) {
|
|
|
|
if (parameter->get_datatype().is_hard_type()) {
|
|
|
|
arguments += ": " + p_func->argument_types[i].to_string();
|
|
|
|
parameters += ": " + parameter->get_datatype().to_string();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int default_value_idx = i - (p_func->arguments.size() - p_func->default_values.size());
|
|
|
|
if (parameter->default_value != nullptr) {
|
|
|
|
if (default_value_idx >= 0) {
|
|
|
|
String value = JSON::print(parameter->default_value->reduced_value);
|
|
|
|
const GDScriptParser::ConstantNode *const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(p_func->default_values[default_value_idx]);
|
|
|
|
parameters += " = " + value;
|
|
|
|
if (const_node == nullptr) {
|
|
|
|
|
|
|
|
const GDScriptParser::OperatorNode *operator_node = dynamic_cast<const GDScriptParser::OperatorNode *>(p_func->default_values[default_value_idx]);
|
|
|
|
|
|
|
|
if (operator_node) {
|
|
|
|
|
|
|
|
const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(operator_node->next);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (const_node) {
|
|
|
|
|
|
|
|
String value = JSON::print(const_node->value);
|
|
|
|
|
|
|
|
arguments += " = " + value;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r_symbol.detail += arguments + ")";
|
|
|
|
r_symbol.detail += parameters + ")";
|
|
|
|
if (p_func->return_type.kind != GDScriptParser::DataType::UNRESOLVED) {
|
|
|
|
if (p_func->get_datatype().is_hard_type()) {
|
|
|
|
r_symbol.detail += " -> " + p_func->return_type.to_string();
|
|
|
|
r_symbol.detail += " -> " + p_func->get_datatype().to_string();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const Map<StringName, LocalVarNode *>::Element *E = p_func->body->variables.front(); E; E = E->next()) {
|
|
|
|
for (int i = 0; i < p_func->body->locals.size(); i++) {
|
|
|
|
|
|
|
|
const SuiteNode::Local &local = p_func->body->locals[i];
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
lsp::DocumentSymbol symbol;
|
|
|
|
const GDScriptParser::LocalVarNode *var = E->value();
|
|
|
|
symbol.name = local.name;
|
|
|
|
symbol.name = E->key();
|
|
|
|
symbol.kind = local.type == SuiteNode::Local::CONSTANT ? lsp::SymbolKind::Constant : lsp::SymbolKind::Variable;
|
|
|
|
symbol.kind = lsp::SymbolKind::Variable;
|
|
|
|
symbol.range.start.line = LINE_NUMBER_TO_INDEX(local.start_line);
|
|
|
|
symbol.range.start.line = LINE_NUMBER_TO_INDEX(E->get()->line);
|
|
|
|
symbol.range.start.character = LINE_NUMBER_TO_INDEX(local.start_column);
|
|
|
|
symbol.range.start.character = E->get()->column;
|
|
|
|
symbol.range.end.line = LINE_NUMBER_TO_INDEX(local.end_line);
|
|
|
|
symbol.range.end.line = symbol.range.start.line;
|
|
|
|
symbol.range.end.character = LINE_NUMBER_TO_INDEX(local.end_column);
|
|
|
|
symbol.range.end.character = lines[symbol.range.end.line].length();
|
|
|
|
|
|
|
|
symbol.uri = uri;
|
|
|
|
symbol.uri = uri;
|
|
|
|
symbol.script_path = path;
|
|
|
|
symbol.script_path = path;
|
|
|
|
symbol.detail = "var " + symbol.name;
|
|
|
|
symbol.detail = SuiteNode::Local::CONSTANT ? "const " : "var ";
|
|
|
|
if (var->datatype.kind != GDScriptParser::DataType::UNRESOLVED) {
|
|
|
|
symbol.detail += symbol.name;
|
|
|
|
symbol.detail += ": " + var->datatype.to_string();
|
|
|
|
if (local.get_datatype().is_hard_type()) {
|
|
|
|
|
|
|
|
symbol.detail += ": " + local.get_datatype().to_string();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
symbol.documentation = parse_documentation(line);
|
|
|
|
symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(local.start_line));
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
r_symbol.children.push_back(symbol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -627,34 +645,24 @@ const Array &ExtendGDScriptParser::get_member_completions() {
|
|
|
|
Dictionary ExtendGDScriptParser::dump_function_api(const GDScriptParser::FunctionNode *p_func) const {
|
|
|
|
Dictionary ExtendGDScriptParser::dump_function_api(const GDScriptParser::FunctionNode *p_func) const {
|
|
|
|
Dictionary func;
|
|
|
|
Dictionary func;
|
|
|
|
ERR_FAIL_NULL_V(p_func, func);
|
|
|
|
ERR_FAIL_NULL_V(p_func, func);
|
|
|
|
func["name"] = p_func->name;
|
|
|
|
func["name"] = p_func->identifier->name;
|
|
|
|
func["return_type"] = p_func->return_type.to_string();
|
|
|
|
func["return_type"] = p_func->get_datatype().to_string();
|
|
|
|
func["rpc_mode"] = p_func->rpc_mode;
|
|
|
|
func["rpc_mode"] = p_func->rpc_mode;
|
|
|
|
Array arguments;
|
|
|
|
Array parameters;
|
|
|
|
for (int i = 0; i < p_func->arguments.size(); i++) {
|
|
|
|
for (int i = 0; i < p_func->parameters.size(); i++) {
|
|
|
|
Dictionary arg;
|
|
|
|
Dictionary arg;
|
|
|
|
arg["name"] = p_func->arguments[i];
|
|
|
|
arg["name"] = p_func->parameters[i]->identifier->name;
|
|
|
|
arg["type"] = p_func->argument_types[i].to_string();
|
|
|
|
arg["type"] = p_func->parameters[i]->get_datatype().to_string();
|
|
|
|
int default_value_idx = i - (p_func->arguments.size() - p_func->default_values.size());
|
|
|
|
if (p_func->parameters[i]->default_value != nullptr) {
|
|
|
|
if (default_value_idx >= 0) {
|
|
|
|
arg["default_value"] = p_func->parameters[i]->default_value->reduced_value;
|
|
|
|
const GDScriptParser::ConstantNode *const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(p_func->default_values[default_value_idx]);
|
|
|
|
|
|
|
|
if (const_node == nullptr) {
|
|
|
|
|
|
|
|
const GDScriptParser::OperatorNode *operator_node = dynamic_cast<const GDScriptParser::OperatorNode *>(p_func->default_values[default_value_idx]);
|
|
|
|
|
|
|
|
if (operator_node) {
|
|
|
|
|
|
|
|
const_node = dynamic_cast<const GDScriptParser::ConstantNode *>(operator_node->next);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const_node) {
|
|
|
|
|
|
|
|
arg["default_value"] = const_node->value;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
arguments.push_back(arg);
|
|
|
|
parameters.push_back(arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(p_func->line))) {
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(p_func->start_line))) {
|
|
|
|
func["signature"] = symbol->detail;
|
|
|
|
func["signature"] = symbol->detail;
|
|
|
|
func["description"] = symbol->documentation;
|
|
|
|
func["description"] = symbol->documentation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func["arguments"] = arguments;
|
|
|
|
func["arguments"] = parameters;
|
|
|
|
return func;
|
|
|
|
return func;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -663,91 +671,117 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
|
|
|
|
|
|
|
|
|
|
|
|
ERR_FAIL_NULL_V(p_class, class_api);
|
|
|
|
ERR_FAIL_NULL_V(p_class, class_api);
|
|
|
|
|
|
|
|
|
|
|
|
class_api["name"] = String(p_class->name);
|
|
|
|
class_api["name"] = p_class->identifier != nullptr ? String(p_class->identifier->name) : String();
|
|
|
|
class_api["path"] = path;
|
|
|
|
class_api["path"] = path;
|
|
|
|
Array extends_class;
|
|
|
|
Array extends_class;
|
|
|
|
for (int i = 0; i < p_class->extends_class.size(); i++) {
|
|
|
|
for (int i = 0; i < p_class->extends.size(); i++) {
|
|
|
|
extends_class.append(String(p_class->extends_class[i]));
|
|
|
|
extends_class.append(String(p_class->extends[i]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class_api["extends_class"] = extends_class;
|
|
|
|
class_api["extends_class"] = extends_class;
|
|
|
|
class_api["extends_file"] = String(p_class->extends_file);
|
|
|
|
class_api["extends_file"] = String(p_class->extends_path);
|
|
|
|
class_api["icon"] = String(p_class->icon_path);
|
|
|
|
class_api["icon"] = String(p_class->icon_path);
|
|
|
|
|
|
|
|
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(p_class->line))) {
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(p_class->start_line))) {
|
|
|
|
class_api["signature"] = symbol->detail;
|
|
|
|
class_api["signature"] = symbol->detail;
|
|
|
|
class_api["description"] = symbol->documentation;
|
|
|
|
class_api["description"] = symbol->documentation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Array subclasses;
|
|
|
|
Array nested_classes;
|
|
|
|
for (int i = 0; i < p_class->subclasses.size(); i++) {
|
|
|
|
|
|
|
|
subclasses.push_back(dump_class_api(p_class->subclasses[i]));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
class_api["sub_classes"] = subclasses;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Array constants;
|
|
|
|
Array constants;
|
|
|
|
for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_class->constant_expressions.front(); E; E = E->next()) {
|
|
|
|
|
|
|
|
const GDScriptParser::ClassNode::Constant &c = E->value();
|
|
|
|
|
|
|
|
const GDScriptParser::ConstantNode *node = dynamic_cast<const GDScriptParser::ConstantNode *>(c.expression);
|
|
|
|
|
|
|
|
ERR_FAIL_COND_V(!node, class_api);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Dictionary api;
|
|
|
|
|
|
|
|
api["name"] = E->key();
|
|
|
|
|
|
|
|
api["value"] = node->value;
|
|
|
|
|
|
|
|
api["data_type"] = node->datatype.to_string();
|
|
|
|
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(node->line))) {
|
|
|
|
|
|
|
|
api["signature"] = symbol->detail;
|
|
|
|
|
|
|
|
api["description"] = symbol->documentation;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
constants.push_back(api);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
class_api["constants"] = constants;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Array members;
|
|
|
|
Array members;
|
|
|
|
for (int i = 0; i < p_class->variables.size(); ++i) {
|
|
|
|
|
|
|
|
const GDScriptParser::ClassNode::Member &m = p_class->variables[i];
|
|
|
|
|
|
|
|
Dictionary api;
|
|
|
|
|
|
|
|
api["name"] = m.identifier;
|
|
|
|
|
|
|
|
api["data_type"] = m.data_type.to_string();
|
|
|
|
|
|
|
|
api["default_value"] = m.default_value;
|
|
|
|
|
|
|
|
api["setter"] = String(m.setter);
|
|
|
|
|
|
|
|
api["getter"] = String(m.getter);
|
|
|
|
|
|
|
|
api["export"] = m._export.type != Variant::NIL;
|
|
|
|
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(m.line))) {
|
|
|
|
|
|
|
|
api["signature"] = symbol->detail;
|
|
|
|
|
|
|
|
api["description"] = symbol->documentation;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
members.push_back(api);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
class_api["members"] = members;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Array signals;
|
|
|
|
Array signals;
|
|
|
|
for (int i = 0; i < p_class->_signals.size(); ++i) {
|
|
|
|
|
|
|
|
const GDScriptParser::ClassNode::Signal &signal = p_class->_signals[i];
|
|
|
|
|
|
|
|
Dictionary api;
|
|
|
|
|
|
|
|
api["name"] = signal.name;
|
|
|
|
|
|
|
|
Array args;
|
|
|
|
|
|
|
|
for (int j = 0; j < signal.arguments.size(); j++) {
|
|
|
|
|
|
|
|
args.append(signal.arguments[j]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
api["arguments"] = args;
|
|
|
|
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(signal.line))) {
|
|
|
|
|
|
|
|
api["signature"] = symbol->detail;
|
|
|
|
|
|
|
|
api["description"] = symbol->documentation;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
signals.push_back(api);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
class_api["signals"] = signals;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Array methods;
|
|
|
|
Array methods;
|
|
|
|
for (int i = 0; i < p_class->functions.size(); ++i) {
|
|
|
|
|
|
|
|
methods.append(dump_function_api(p_class->functions[i]));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
class_api["methods"] = methods;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Array static_functions;
|
|
|
|
Array static_functions;
|
|
|
|
for (int i = 0; i < p_class->static_functions.size(); ++i) {
|
|
|
|
|
|
|
|
static_functions.append(dump_function_api(p_class->static_functions[i]));
|
|
|
|
for (int i = 0; i < p_class->members.size(); i++) {
|
|
|
|
|
|
|
|
const ClassNode::Member &m = p_class->members[i];
|
|
|
|
|
|
|
|
switch (m.type) {
|
|
|
|
|
|
|
|
case ClassNode::Member::CLASS:
|
|
|
|
|
|
|
|
nested_classes.push_back(dump_class_api(m.m_class));
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ClassNode::Member::CONSTANT: {
|
|
|
|
|
|
|
|
Dictionary api;
|
|
|
|
|
|
|
|
api["name"] = m.constant->identifier->name;
|
|
|
|
|
|
|
|
api["value"] = m.constant->initializer->reduced_value;
|
|
|
|
|
|
|
|
api["data_type"] = m.constant->get_datatype().to_string();
|
|
|
|
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(m.constant->start_line))) {
|
|
|
|
|
|
|
|
api["signature"] = symbol->detail;
|
|
|
|
|
|
|
|
api["description"] = symbol->documentation;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
constants.push_back(api);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::ENUM_VALUE: {
|
|
|
|
|
|
|
|
Dictionary api;
|
|
|
|
|
|
|
|
api["name"] = m.enum_value.identifier->name;
|
|
|
|
|
|
|
|
api["value"] = m.enum_value.value;
|
|
|
|
|
|
|
|
api["data_type"] = m.get_datatype().to_string();
|
|
|
|
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(m.enum_value.line))) {
|
|
|
|
|
|
|
|
api["signature"] = symbol->detail;
|
|
|
|
|
|
|
|
api["description"] = symbol->documentation;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
constants.push_back(api);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::ENUM: {
|
|
|
|
|
|
|
|
Dictionary enum_dict;
|
|
|
|
|
|
|
|
for (int j = 0; j < m.m_enum->values.size(); i++) {
|
|
|
|
|
|
|
|
enum_dict[m.m_enum->values[i].identifier->name] = m.m_enum->values[i].value;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Dictionary api;
|
|
|
|
|
|
|
|
api["name"] = m.m_enum->identifier->name;
|
|
|
|
|
|
|
|
api["value"] = enum_dict;
|
|
|
|
|
|
|
|
api["data_type"] = m.get_datatype().to_string();
|
|
|
|
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(m.m_enum->start_line))) {
|
|
|
|
|
|
|
|
api["signature"] = symbol->detail;
|
|
|
|
|
|
|
|
api["description"] = symbol->documentation;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
constants.push_back(api);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::VARIABLE: {
|
|
|
|
|
|
|
|
Dictionary api;
|
|
|
|
|
|
|
|
api["name"] = m.variable->identifier->name;
|
|
|
|
|
|
|
|
api["data_type"] = m.variable->get_datatype().to_string();
|
|
|
|
|
|
|
|
api["default_value"] = m.variable->initializer != nullptr ? m.variable->initializer->reduced_value : Variant();
|
|
|
|
|
|
|
|
api["setter"] = m.variable->setter ? ("@" + String(m.variable->identifier->name) + "_setter") : (m.variable->setter_pointer != nullptr ? String(m.variable->setter_pointer->name) : String());
|
|
|
|
|
|
|
|
api["getter"] = m.variable->getter ? ("@" + String(m.variable->identifier->name) + "_getter") : (m.variable->getter_pointer != nullptr ? String(m.variable->getter_pointer->name) : String());
|
|
|
|
|
|
|
|
api["export"] = m.variable->exported;
|
|
|
|
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(m.variable->start_line))) {
|
|
|
|
|
|
|
|
api["signature"] = symbol->detail;
|
|
|
|
|
|
|
|
api["description"] = symbol->documentation;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
members.push_back(api);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::SIGNAL: {
|
|
|
|
|
|
|
|
Dictionary api;
|
|
|
|
|
|
|
|
api["name"] = m.signal->identifier->name;
|
|
|
|
|
|
|
|
Array pars;
|
|
|
|
|
|
|
|
for (int j = 0; j < m.signal->parameters.size(); j++) {
|
|
|
|
|
|
|
|
pars.append(String(m.signal->parameters[i]->identifier->name));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
api["arguments"] = pars;
|
|
|
|
|
|
|
|
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(m.signal->start_line))) {
|
|
|
|
|
|
|
|
api["signature"] = symbol->detail;
|
|
|
|
|
|
|
|
api["description"] = symbol->documentation;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
signals.push_back(api);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::FUNCTION: {
|
|
|
|
|
|
|
|
if (m.function->is_static) {
|
|
|
|
|
|
|
|
static_functions.append(dump_function_api(m.function));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
methods.append(dump_function_api(m.function));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ClassNode::Member::UNDEFINED:
|
|
|
|
|
|
|
|
break; // Unreachable.
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class_api["sub_classes"] = nested_classes;
|
|
|
|
|
|
|
|
class_api["constants"] = constants;
|
|
|
|
|
|
|
|
class_api["members"] = members;
|
|
|
|
|
|
|
|
class_api["signals"] = signals;
|
|
|
|
|
|
|
|
class_api["methods"] = methods;
|
|
|
|
class_api["static_functions"] = static_functions;
|
|
|
|
class_api["static_functions"] = static_functions;
|
|
|
|
|
|
|
|
|
|
|
|
return class_api;
|
|
|
|
return class_api;
|
|
|
@ -755,7 +789,7 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
|
|
|
|
|
|
|
|
|
|
|
|
Dictionary ExtendGDScriptParser::generate_api() const {
|
|
|
|
Dictionary ExtendGDScriptParser::generate_api() const {
|
|
|
|
Dictionary api;
|
|
|
|
Dictionary api;
|
|
|
|
const GDScriptParser::Node *head = get_parse_tree();
|
|
|
|
const GDScriptParser::Node *head = get_tree();
|
|
|
|
if (const GDScriptParser::ClassNode *gdclass = dynamic_cast<const GDScriptParser::ClassNode *>(head)) {
|
|
|
|
if (const GDScriptParser::ClassNode *gdclass = dynamic_cast<const GDScriptParser::ClassNode *>(head)) {
|
|
|
|
api = dump_class_api(gdclass);
|
|
|
|
api = dump_class_api(gdclass);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -766,11 +800,13 @@ Error ExtendGDScriptParser::parse(const String &p_code, const String &p_path) {
|
|
|
|
path = p_path;
|
|
|
|
path = p_path;
|
|
|
|
lines = p_code.split("\n");
|
|
|
|
lines = p_code.split("\n");
|
|
|
|
|
|
|
|
|
|
|
|
Error err = GDScriptParser::parse(p_code, p_path.get_base_dir(), false, p_path, false, nullptr, false);
|
|
|
|
Error err = GDScriptParser::parse(p_code, p_path, false);
|
|
|
|
|
|
|
|
if (err == OK) {
|
|
|
|
|
|
|
|
GDScriptAnalyzer analyzer(this);
|
|
|
|
|
|
|
|
err = analyzer.analyze();
|
|
|
|
|
|
|
|
}
|
|
|
|
update_diagnostics();
|
|
|
|
update_diagnostics();
|
|
|
|
update_symbols();
|
|
|
|
update_symbols();
|
|
|
|
update_document_links(p_code);
|
|
|
|
update_document_links(p_code);
|
|
|
|
return err;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|