Explorar o código

Reenable GDScript LSP server

George Marques %!s(int64=5) %!d(string=hai) anos
pai
achega
b6a2628c48

+ 2 - 0
modules/gdscript/gdscript_parser.cpp

@@ -149,6 +149,8 @@ T *GDScriptParser::alloc_node() {
 	// TODO: Properly set positions for all nodes.
 	node->start_line = previous.start_line;
 	node->end_line = previous.end_line;
+	node->start_column = previous.start_column;
+	node->end_column = previous.end_column;
 	node->leftmost_column = previous.leftmost_column;
 	node->rightmost_column = previous.rightmost_column;
 

+ 29 - 0
modules/gdscript/gdscript_parser.h

@@ -232,6 +232,7 @@ public:
 
 		Type type = NONE;
 		int start_line = 0, end_line = 0;
+		int start_column = 0, end_column = 0;
 		int leftmost_column = 0, rightmost_column = 0;
 		Node *next = nullptr;
 		List<AnnotationNode *> annotations;
@@ -855,21 +856,49 @@ public:
 				type = CONSTANT;
 				constant = p_constant;
 				name = p_constant->identifier->name;
+
+				start_line = p_constant->start_line;
+				end_line = p_constant->end_line;
+				start_column = p_constant->start_column;
+				end_column = p_constant->end_column;
+				leftmost_column = p_constant->leftmost_column;
+				rightmost_column = p_constant->rightmost_column;
 			}
 			Local(VariableNode *p_variable) {
 				type = VARIABLE;
 				variable = p_variable;
 				name = p_variable->identifier->name;
+
+				start_line = p_variable->start_line;
+				end_line = p_variable->end_line;
+				start_column = p_variable->start_column;
+				end_column = p_variable->end_column;
+				leftmost_column = p_variable->leftmost_column;
+				rightmost_column = p_variable->rightmost_column;
 			}
 			Local(ParameterNode *p_parameter) {
 				type = PARAMETER;
 				parameter = p_parameter;
 				name = p_parameter->identifier->name;
+
+				start_line = p_parameter->start_line;
+				end_line = p_parameter->end_line;
+				start_column = p_parameter->start_column;
+				end_column = p_parameter->end_column;
+				leftmost_column = p_parameter->leftmost_column;
+				rightmost_column = p_parameter->rightmost_column;
 			}
 			Local(IdentifierNode *p_identifier) {
 				type = FOR_VARIABLE;
 				bind = p_identifier;
 				name = p_identifier->name;
+
+				start_line = p_identifier->start_line;
+				end_line = p_identifier->end_line;
+				start_column = p_identifier->start_column;
+				end_column = p_identifier->end_column;
+				leftmost_column = p_identifier->leftmost_column;
+				rightmost_column = p_identifier->rightmost_column;
 			}
 		};
 		Local empty;

+ 318 - 282
modules/gdscript/language_server/gdscript_extend_parser.cpp

@@ -28,12 +28,10 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-// FIXME: Reenable LSP.
-#if 0
-
 #include "gdscript_extend_parser.h"
 
 #include "../gdscript.h"
+#include "../gdscript_analyzer.h"
 #include "core/io/json.h"
 #include "gdscript_language_protocol.h"
 #include "gdscript_workspace.h"
@@ -41,15 +39,17 @@
 void ExtendGDScriptParser::update_diagnostics() {
 	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;
 		diagnostic.severity = lsp::DiagnosticSeverity::Error;
-		diagnostic.message = get_error();
+		diagnostic.message = error.message;
 		diagnostic.source = "gdscript";
 		diagnostic.code = -1;
 		lsp::Range range;
 		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];
 		pos.line = line;
 		pos.character = line_text.length() - line_text.strip_edges(true, false).length();
@@ -70,7 +70,7 @@ void ExtendGDScriptParser::update_diagnostics() {
 		diagnostic.code = warning.code;
 		lsp::Range range;
 		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];
 		pos.line = line;
 		pos.character = line_text.length() - line_text.strip_edges(true, false).length();
@@ -85,7 +85,7 @@ void ExtendGDScriptParser::update_diagnostics() {
 void ExtendGDScriptParser::update_symbols() {
 	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)) {
 		parse_class_symbol(gdclass, class_symbol);
 
@@ -109,15 +109,15 @@ void ExtendGDScriptParser::update_symbols() {
 void ExtendGDScriptParser::update_document_links(const String &p_code) {
 	document_links.clear();
 
-	GDScriptTokenizerText tokenizer;
+	GDScriptTokenizer tokenizer;
 	FileAccessRef fs = FileAccess::create(FileAccess::ACCESS_RESOURCES);
-	tokenizer.set_code(p_code);
+	tokenizer.set_source_code(p_code);
 	while (true) {
-		GDScriptTokenizerText::Token token = tokenizer.get_token();
-		if (token == GDScriptTokenizer::TK_EOF || token == GDScriptTokenizer::TK_ERROR) {
+		GDScriptTokenizer::Token token = tokenizer.scan();
+		if (token.type == GDScriptTokenizer::Token::TK_EOF) {
 			break;
-		} else if (token == GDScriptTokenizer::TK_CONSTANT) {
-			const Variant &const_val = tokenizer.get_token_constant();
+		} else if (token.type == GDScriptTokenizer::Token::LITERAL) {
+			const Variant &const_val = token.literal;
 			if (const_val.get_type() == Variant::STRING) {
 				String path = const_val;
 				bool exists = fs->file_exists(path);
@@ -129,15 +129,14 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) {
 					String value = const_val;
 					lsp::DocumentLink link;
 					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.end.line = link.range.start.line;
-					link.range.end.character = LINE_NUMBER_TO_INDEX(tokenizer.get_token_column());
-					link.range.start.character = link.range.end.character - value.length();
+					link.range.start.line = LINE_NUMBER_TO_INDEX(token.start_line);
+					link.range.end.line = LINE_NUMBER_TO_INDEX(token.end_line);
+					link.range.start.character = LINE_NUMBER_TO_INDEX(token.start_column);
+					link.range.end.character = LINE_NUMBER_TO_INDEX(token.end_column);
 					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.script_path = path;
 	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()) {
 		r_symbol.name = path.get_file();
 	}
 	r_symbol.kind = lsp::SymbolKind::Class;
 	r_symbol.deprecated = false;
-	r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_class->line);
-	r_symbol.range.start.character = p_class->column;
+	r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_class->start_line);
+	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.selectionRange.start.line = r_symbol.range.start.line;
 	r_symbol.detail = "class " + r_symbol.name;
 	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);
-
-	for (int i = 0; i < p_class->variables.size(); ++i) {
-		const GDScriptParser::ClassNode::Member &m = p_class->variables[i];
-
-		lsp::DocumentSymbol symbol;
-		symbol.name = m.identifier;
-		symbol.kind = lsp::SymbolKind::Variable;
-		symbol.deprecated = false;
-		const int line = LINE_NUMBER_TO_INDEX(m.line);
-		symbol.range.start.line = line;
-		symbol.range.start.character = lines[line].length() - lines[line].strip_edges(true, false).length();
-		symbol.range.end.line = line;
-		symbol.range.end.character = lines[line].length();
-		symbol.selectionRange.start.line = symbol.range.start.line;
-		if (m._export.type != Variant::NIL) {
-			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);
-	}
+	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->members.size(); i++) {
+		const ClassNode::Member &m = p_class->members[i];
+
+		switch (m.type) {
+			case ClassNode::Member::VARIABLE: {
+				lsp::DocumentSymbol symbol;
+				symbol.name = m.variable->identifier->name;
+				symbol.kind = lsp::SymbolKind::Variable;
+				symbol.deprecated = false;
+				symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.variable->start_line);
+				symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.variable->start_column);
+				symbol.range.end.line = LINE_NUMBER_TO_INDEX(m.variable->end_line);
+				symbol.range.end.character = LINE_NUMBER_TO_INDEX(m.variable->end_column);
+				symbol.selectionRange.start.line = symbol.range.start.line;
+				if (m.variable->exported) {
+					symbol.detail += "@export ";
+				}
+				symbol.detail += "var " + m.variable->identifier->name;
+				if (m.get_datatype().is_hard_type()) {
+					symbol.detail += ": " + m.get_datatype().to_string();
+				}
+				if (m.variable->initializer != nullptr && m.variable->initializer->is_constant) {
+					symbol.detail += " = " + JSON::print(m.variable->initializer->reduced_value);
+				}
 
-	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.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();
+				}
 
-		symbol.detail = "const " + symbol.name;
-		if (c.type.kind != GDScriptParser::DataType::UNRESOLVED) {
-			symbol.detail += ": " + c.type.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;
+				}
 
-		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;
+				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;
 				}
-			} else {
-				value_text = JSON::print(node->value);
-			}
-		} else {
-			value_text = JSON::print(node->value);
-		}
-		if (!value_text.empty()) {
-			symbol.detail += " = " + value_text;
+				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.
 		}
-
-		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) {
 	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.detail = "func " + p_func->name + "(";
+	r_symbol.detail = "func " + String(p_func->identifier->name) + "(";
 	r_symbol.deprecated = false;
-	const int line = LINE_NUMBER_TO_INDEX(p_func->line);
-	r_symbol.range.start.line = line;
-	r_symbol.range.start.character = p_func->column;
-	r_symbol.range.end.line = MAX(p_func->body->end_line - 2, r_symbol.range.start.line);
-	r_symbol.range.end.character = lines[r_symbol.range.end.line].length();
+	r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_func->start_line);
+	r_symbol.range.start.character = LINE_NUMBER_TO_INDEX(p_func->start_column);
+	r_symbol.range.end.line = LINE_NUMBER_TO_INDEX(p_func->start_line);
+	r_symbol.range.end.character = LINE_NUMBER_TO_INDEX(p_func->end_column);
 	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.script_path = path;
 
-	String arguments;
-	for (int i = 0; i < p_func->arguments.size(); i++) {
+	String parameters;
+	for (int i = 0; i < p_func->parameters.size(); i++) {
+		const ParameterNode *parameter = p_func->parameters[i];
 		lsp::DocumentSymbol symbol;
 		symbol.kind = lsp::SymbolKind::Variable;
-		symbol.name = p_func->arguments[i];
-		symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_func->body->line);
-		symbol.range.start.character = p_func->body->column;
-		symbol.range.end = symbol.range.start;
+		symbol.name = parameter->identifier->name;
+		symbol.range.start.line = LINE_NUMBER_TO_INDEX(parameter->start_line);
+		symbol.range.start.character = LINE_NUMBER_TO_INDEX(parameter->start_line);
+		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.script_path = path;
 		r_symbol.children.push_back(symbol);
 		if (i > 0) {
-			arguments += ", ";
+			parameters += ", ";
 		}
-		arguments += String(p_func->arguments[i]);
-		if (p_func->argument_types[i].kind != GDScriptParser::DataType::UNRESOLVED) {
-			arguments += ": " + p_func->argument_types[i].to_string();
+		parameters += String(parameter->identifier->name);
+		if (parameter->get_datatype().is_hard_type()) {
+			parameters += ": " + parameter->get_datatype().to_string();
 		}
-		int default_value_idx = i - (p_func->arguments.size() - p_func->default_values.size());
-		if (default_value_idx >= 0) {
-			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) {
-				String value = JSON::print(const_node->value);
-				arguments += " = " + value;
-			}
+		if (parameter->default_value != nullptr) {
+			String value = JSON::print(parameter->default_value->reduced_value);
+			parameters += " = " + value;
 		}
 	}
-	r_symbol.detail += arguments + ")";
-	if (p_func->return_type.kind != GDScriptParser::DataType::UNRESOLVED) {
-		r_symbol.detail += " -> " + p_func->return_type.to_string();
+	r_symbol.detail += parameters + ")";
+	if (p_func->get_datatype().is_hard_type()) {
+		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;
-		const GDScriptParser::LocalVarNode *var = E->value();
-		symbol.name = E->key();
-		symbol.kind = lsp::SymbolKind::Variable;
-		symbol.range.start.line = LINE_NUMBER_TO_INDEX(E->get()->line);
-		symbol.range.start.character = E->get()->column;
-		symbol.range.end.line = symbol.range.start.line;
-		symbol.range.end.character = lines[symbol.range.end.line].length();
+		symbol.name = local.name;
+		symbol.kind = local.type == SuiteNode::Local::CONSTANT ? lsp::SymbolKind::Constant : lsp::SymbolKind::Variable;
+		symbol.range.start.line = LINE_NUMBER_TO_INDEX(local.start_line);
+		symbol.range.start.character = LINE_NUMBER_TO_INDEX(local.start_column);
+		symbol.range.end.line = LINE_NUMBER_TO_INDEX(local.end_line);
+		symbol.range.end.character = LINE_NUMBER_TO_INDEX(local.end_column);
 		symbol.uri = uri;
 		symbol.script_path = path;
-		symbol.detail = "var " + symbol.name;
-		if (var->datatype.kind != GDScriptParser::DataType::UNRESOLVED) {
-			symbol.detail += ": " + var->datatype.to_string();
+		symbol.detail = SuiteNode::Local::CONSTANT ? "const " : "var ";
+		symbol.detail += symbol.name;
+		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);
 	}
 }
@@ -627,34 +645,24 @@ const Array &ExtendGDScriptParser::get_member_completions() {
 Dictionary ExtendGDScriptParser::dump_function_api(const GDScriptParser::FunctionNode *p_func) const {
 	Dictionary func;
 	ERR_FAIL_NULL_V(p_func, func);
-	func["name"] = p_func->name;
-	func["return_type"] = p_func->return_type.to_string();
+	func["name"] = p_func->identifier->name;
+	func["return_type"] = p_func->get_datatype().to_string();
 	func["rpc_mode"] = p_func->rpc_mode;
-	Array arguments;
-	for (int i = 0; i < p_func->arguments.size(); i++) {
+	Array parameters;
+	for (int i = 0; i < p_func->parameters.size(); i++) {
 		Dictionary arg;
-		arg["name"] = p_func->arguments[i];
-		arg["type"] = p_func->argument_types[i].to_string();
-		int default_value_idx = i - (p_func->arguments.size() - p_func->default_values.size());
-		if (default_value_idx >= 0) {
-			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;
-			}
+		arg["name"] = p_func->parameters[i]->identifier->name;
+		arg["type"] = p_func->parameters[i]->get_datatype().to_string();
+		if (p_func->parameters[i]->default_value != nullptr) {
+			arg["default_value"] = p_func->parameters[i]->default_value->reduced_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["description"] = symbol->documentation;
 	}
-	func["arguments"] = arguments;
+	func["arguments"] = parameters;
 	return func;
 }
 
@@ -663,91 +671,117 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
 
 	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;
 	Array extends_class;
-	for (int i = 0; i < p_class->extends_class.size(); i++) {
-		extends_class.append(String(p_class->extends_class[i]));
+	for (int i = 0; i < p_class->extends.size(); i++) {
+		extends_class.append(String(p_class->extends[i]));
 	}
 	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);
 
-	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["description"] = symbol->documentation;
 	}
 
-	Array subclasses;
-	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 nested_classes;
 	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;
-	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;
-	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;
+	Array methods;
+	Array static_functions;
+
+	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.
 		}
-		signals.push_back(api);
 	}
-	class_api["signals"] = signals;
 
-	Array methods;
-	for (int i = 0; i < p_class->functions.size(); ++i) {
-		methods.append(dump_function_api(p_class->functions[i]));
-	}
+	class_api["sub_classes"] = nested_classes;
+	class_api["constants"] = constants;
+	class_api["members"] = members;
+	class_api["signals"] = signals;
 	class_api["methods"] = methods;
-
-	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]));
-	}
 	class_api["static_functions"] = static_functions;
 
 	return class_api;
@@ -755,7 +789,7 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
 
 Dictionary ExtendGDScriptParser::generate_api() const {
 	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)) {
 		api = dump_class_api(gdclass);
 	}
@@ -766,11 +800,13 @@ Error ExtendGDScriptParser::parse(const String &p_code, const String &p_path) {
 	path = p_path;
 	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_symbols();
 	update_document_links(p_code);
 	return err;
 }
-
-#endif

+ 0 - 5
modules/gdscript/language_server/gdscript_extend_parser.h

@@ -31,9 +31,6 @@
 #ifndef GDSCRIPT_EXTEND_PARSER_H
 #define GDSCRIPT_EXTEND_PARSER_H
 
-// FIXME: Reenable LSP.
-#if 0
-
 #include "../gdscript_parser.h"
 #include "core/variant.h"
 #include "lsp.hpp"
@@ -103,5 +100,3 @@ public:
 };
 
 #endif
-
-#endif

+ 0 - 5
modules/gdscript/language_server/gdscript_language_protocol.cpp

@@ -28,9 +28,6 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-// FIXME: Reenable LSP.
-#if 0
-
 #include "gdscript_language_protocol.h"
 
 #include "core/io/json.h"
@@ -306,5 +303,3 @@ GDScriptLanguageProtocol::GDScriptLanguageProtocol() {
 	set_scope("workspace", workspace.ptr());
 	workspace->root = ProjectSettings::get_singleton()->get_resource_path();
 }
-
-#endif

+ 0 - 5
modules/gdscript/language_server/gdscript_language_protocol.h

@@ -31,9 +31,6 @@
 #ifndef GDSCRIPT_PROTOCAL_SERVER_H
 #define GDSCRIPT_PROTOCAL_SERVER_H
 
-// FIXME: Reenable LSP.
-#if 0
-
 #include "core/io/stream_peer.h"
 #include "core/io/stream_peer_tcp.h"
 #include "core/io/tcp_server.h"
@@ -112,5 +109,3 @@ public:
 };
 
 #endif
-
-#endif

+ 0 - 5
modules/gdscript/language_server/gdscript_language_server.cpp

@@ -28,9 +28,6 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-// FIXME: Reenable LSP.
-#if 0
-
 #include "gdscript_language_server.h"
 
 #include "core/os/file_access.h"
@@ -117,5 +114,3 @@ void register_lsp_types() {
 	ClassDB::register_class<GDScriptTextDocument>();
 	ClassDB::register_class<GDScriptWorkspace>();
 }
-
-#endif

+ 0 - 5
modules/gdscript/language_server/gdscript_language_server.h

@@ -31,9 +31,6 @@
 #ifndef GDSCRIPT_LANGUAGE_SERVER_H
 #define GDSCRIPT_LANGUAGE_SERVER_H
 
-// FIXME: Reenable LSP.
-#if 0
-
 #include "../gdscript_parser.h"
 #include "editor/editor_plugin.h"
 #include "gdscript_language_protocol.h"
@@ -63,6 +60,4 @@ public:
 
 void register_lsp_types();
 
-#endif
-
 #endif // GDSCRIPT_LANGUAGE_SERVER_H

+ 0 - 5
modules/gdscript/language_server/gdscript_text_document.cpp

@@ -38,9 +38,6 @@
 #include "gdscript_language_protocol.h"
 #include "servers/display_server.h"
 
-// FIXME: Reenable LSP.
-#if 0
-
 void GDScriptTextDocument::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen);
 	ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange);
@@ -440,5 +437,3 @@ Array GDScriptTextDocument::find_symbols(const lsp::TextDocumentPositionParams &
 	}
 	return arr;
 }
-
-#endif

+ 0 - 5
modules/gdscript/language_server/gdscript_text_document.h

@@ -31,9 +31,6 @@
 #ifndef GDSCRIPT_TEXT_DOCUMENT_H
 #define GDSCRIPT_TEXT_DOCUMENT_H
 
-// FIXME: Reenable LSP.
-#if 0
-
 #include "core/os/file_access.h"
 #include "core/reference.h"
 #include "lsp.hpp"
@@ -79,5 +76,3 @@ public:
 };
 
 #endif
-
-#endif

+ 1 - 6
modules/gdscript/language_server/gdscript_workspace.cpp

@@ -28,9 +28,6 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-// FIXME: Reenable LSP.
-#if 0
-
 #include "gdscript_workspace.h"
 
 #include "../gdscript.h"
@@ -121,7 +118,7 @@ void GDScriptWorkspace::reload_all_workspace_scripts() {
 			Map<String, ExtendGDScriptParser *>::Element *S = parse_results.find(path);
 			String err_msg = "Failed parse script " + path;
 			if (S) {
-				err_msg += "\n" + S->get()->get_error();
+				err_msg += "\n" + S->get()->get_errors()[0].message;
 			}
 			ERR_CONTINUE_MSG(err != OK, err_msg);
 		}
@@ -621,5 +618,3 @@ GDScriptWorkspace::~GDScriptWorkspace() {
 		remove_cache_parser(E->get());
 	}
 }
-
-#endif

+ 0 - 5
modules/gdscript/language_server/gdscript_workspace.h

@@ -31,9 +31,6 @@
 #ifndef GDSCRIPT_WORKSPACE_H
 #define GDSCRIPT_WORKSPACE_H
 
-// FIXME: Reenable LSP.
-#if 0
-
 #include "../gdscript_parser.h"
 #include "core/variant.h"
 #include "editor/editor_file_system.h"
@@ -98,5 +95,3 @@ public:
 };
 
 #endif
-
-#endif

+ 0 - 5
modules/gdscript/language_server/lsp.hpp

@@ -31,9 +31,6 @@
 #ifndef GODOT_LSP_H
 #define GODOT_LSP_H
 
-// FIXME: Reenable LSP.
-#if 0
-
 #include "core/class_db.h"
 #include "core/list.h"
 #include "editor/doc_data.h"
@@ -1788,5 +1785,3 @@ static String marked_documentation(const String &p_bbcode) {
 } // namespace lsp
 
 #endif
-
-#endif

+ 0 - 6
modules/gdscript/register_types.cpp

@@ -52,13 +52,10 @@ GDScriptCache *gdscript_cache = nullptr;
 #include "editor/gdscript_highlighter.h"
 #include "editor/gdscript_translation_parser_plugin.h"
 
-// FIXME: Reenable LSP.
-#if 0
 #ifndef GDSCRIPT_NO_LSP
 #include "core/engine.h"
 #include "language_server/gdscript_language_server.h"
 #endif // !GDSCRIPT_NO_LSP
-#endif
 
 Ref<GDScriptEditorTranslationParserPlugin> gdscript_translation_parser_plugin;
 
@@ -97,15 +94,12 @@ static void _editor_init() {
 	ScriptEditor::get_singleton()->register_syntax_highlighter(gdscript_syntax_highlighter);
 #endif
 
-// FIXME: Reenable LSP.
-#if 0
 #ifndef GDSCRIPT_NO_LSP
 	register_lsp_types();
 	GDScriptLanguageServer *lsp_plugin = memnew(GDScriptLanguageServer);
 	EditorNode::get_singleton()->add_editor_plugin(lsp_plugin);
 	Engine::get_singleton()->add_singleton(Engine::Singleton("GDScriptLanguageProtocol", GDScriptLanguageProtocol::get_singleton()));
 #endif // !GDSCRIPT_NO_LSP
-#endif
 }
 
 #endif // TOOLS_ENABLED