gdscript_extend_parser.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*************************************************************************/
  2. /* gdscript_extend_parser.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "gdscript_extend_parser.h"
  31. #include "../gdscript.h"
  32. void ExtendGDScriptParser::update_diagnostics() {
  33. diagnostics.clear();
  34. if (has_error()) {
  35. lsp::Diagnostic diagnostic;
  36. diagnostic.severity = lsp::DiagnosticSeverity::Error;
  37. diagnostic.message = get_error();
  38. diagnostic.source = "gdscript";
  39. diagnostic.code = -1;
  40. lsp::Range range;
  41. lsp::Position pos;
  42. int line = get_error_line() - 1;
  43. const String &line_text = get_lines()[line];
  44. pos.line = line;
  45. pos.character = line_text.length() - line_text.strip_edges(true, false).length();
  46. range.start = pos;
  47. range.end = range.start;
  48. range.end.character = line_text.strip_edges(false).length();
  49. diagnostic.range = range;
  50. diagnostics.push_back(diagnostic);
  51. }
  52. const List<GDScriptWarning> &warnings = get_warnings();
  53. for (const List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) {
  54. const GDScriptWarning &warning = E->get();
  55. lsp::Diagnostic diagnostic;
  56. diagnostic.severity = lsp::DiagnosticSeverity::Warning;
  57. diagnostic.message = warning.get_message();
  58. diagnostic.source = "gdscript";
  59. diagnostic.code = warning.code;
  60. lsp::Range range;
  61. lsp::Position pos;
  62. int line = warning.line - 1;
  63. const String &line_text = get_lines()[line];
  64. pos.line = line;
  65. pos.character = line_text.length() - line_text.strip_edges(true, false).length();
  66. range.start = pos;
  67. range.end = pos;
  68. range.end.character = line_text.strip_edges(false).length();
  69. diagnostic.range = range;
  70. diagnostics.push_back(diagnostic);
  71. }
  72. }
  73. void ExtendGDScriptParser::update_symbols() {
  74. const GDScriptParser::Node *head = get_parse_tree();
  75. if (const GDScriptParser::ClassNode *gdclass = dynamic_cast<const GDScriptParser::ClassNode *>(head)) {
  76. parse_class_symbol(gdclass, class_symbol);
  77. }
  78. }
  79. void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p_class, lsp::DocumentSymbol &r_symbol) {
  80. r_symbol.children.clear();
  81. r_symbol.name = p_class->name;
  82. if (r_symbol.name.empty())
  83. r_symbol.name = path.get_file();
  84. r_symbol.kind = lsp::SymbolKind::Class;
  85. r_symbol.detail = p_class->get_datatype().to_string();
  86. r_symbol.deprecated = false;
  87. r_symbol.range.start.line = p_class->line - 1;
  88. r_symbol.range.start.character = p_class->column;
  89. r_symbol.range.end.line = p_class->end_line - 1;
  90. r_symbol.selectionRange.start.line = r_symbol.range.start.line;
  91. for (int i = 0; i < p_class->variables.size(); ++i) {
  92. const GDScriptParser::ClassNode::Member &m = p_class->variables[i];
  93. lsp::DocumentSymbol symbol;
  94. symbol.name = m.identifier;
  95. symbol.kind = lsp::SymbolKind::Variable;
  96. symbol.detail = m.data_type.to_string();
  97. symbol.deprecated = false;
  98. const int line = m.line - 1;
  99. symbol.range.start.line = line;
  100. symbol.range.start.character = lines[line].length() - lines[line].strip_edges(true, false).length();
  101. symbol.range.end.line = line;
  102. symbol.range.end.character = lines[line].length();
  103. symbol.selectionRange.start.line = symbol.range.start.line;
  104. r_symbol.children.push_back(symbol);
  105. }
  106. for (int i = 0; i < p_class->_signals.size(); ++i) {
  107. const GDScriptParser::ClassNode::Signal &signal = p_class->_signals[i];
  108. lsp::DocumentSymbol symbol;
  109. symbol.name = signal.name;
  110. symbol.kind = lsp::SymbolKind::Event;
  111. symbol.deprecated = false;
  112. const int line = signal.line - 1;
  113. symbol.range.start.line = line;
  114. symbol.range.start.character = lines[line].length() - lines[line].strip_edges(true, false).length();
  115. symbol.range.end.line = symbol.range.start.line;
  116. symbol.range.end.character = lines[line].length();
  117. symbol.selectionRange.start.line = symbol.range.start.line;
  118. r_symbol.children.push_back(symbol);
  119. }
  120. for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_class->constant_expressions.front(); E; E = E->next()) {
  121. lsp::DocumentSymbol symbol;
  122. symbol.name = E->key();
  123. symbol.kind = lsp::SymbolKind::Constant;
  124. symbol.deprecated = false;
  125. const int line = E->get().expression->line - 1;
  126. symbol.range.start.line = line;
  127. symbol.range.start.character = E->get().expression->column;
  128. symbol.range.end.line = symbol.range.start.line;
  129. symbol.range.end.character = lines[line].length();
  130. symbol.selectionRange.start.line = symbol.range.start.line;
  131. r_symbol.children.push_back(symbol);
  132. }
  133. for (int i = 0; i < p_class->functions.size(); ++i) {
  134. const GDScriptParser::FunctionNode *func = p_class->functions[i];
  135. lsp::DocumentSymbol symbol;
  136. parse_function_symbol(func, symbol);
  137. r_symbol.children.push_back(symbol);
  138. }
  139. for (int i = 0; i < p_class->static_functions.size(); ++i) {
  140. const GDScriptParser::FunctionNode *func = p_class->static_functions[i];
  141. lsp::DocumentSymbol symbol;
  142. parse_function_symbol(func, symbol);
  143. r_symbol.children.push_back(symbol);
  144. }
  145. for (int i = 0; i < p_class->subclasses.size(); ++i) {
  146. const GDScriptParser::ClassNode *subclass = p_class->subclasses[i];
  147. lsp::DocumentSymbol symbol;
  148. parse_class_symbol(subclass, symbol);
  149. r_symbol.children.push_back(symbol);
  150. }
  151. }
  152. void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionNode *p_func, lsp::DocumentSymbol &r_symbol) {
  153. r_symbol.name = p_func->name;
  154. r_symbol.kind = lsp::SymbolKind::Function;
  155. r_symbol.detail = p_func->get_datatype().to_string();
  156. r_symbol.deprecated = false;
  157. const int line = p_func->line - 1;
  158. r_symbol.range.start.line = line;
  159. r_symbol.range.start.character = p_func->column;
  160. r_symbol.range.end.line = MAX(p_func->body->end_line - 2, p_func->body->line);
  161. r_symbol.range.end.character = lines[r_symbol.range.end.line].length();
  162. r_symbol.selectionRange.start.line = r_symbol.range.start.line;
  163. for (const Map<StringName, LocalVarNode *>::Element *E = p_func->body->variables.front(); E; E = E->next()) {
  164. lsp::DocumentSymbol symbol;
  165. symbol.name = E->key();
  166. symbol.kind = lsp::SymbolKind::Variable;
  167. symbol.range.start.line = E->get()->line - 1;
  168. symbol.range.start.character = E->get()->column;
  169. symbol.range.end.line = symbol.range.start.line;
  170. symbol.range.end.character = lines[symbol.range.end.line].length();
  171. r_symbol.children.push_back(symbol);
  172. }
  173. for (int i = 0; i < p_func->arguments.size(); i++) {
  174. lsp::DocumentSymbol symbol;
  175. symbol.kind = lsp::SymbolKind::Variable;
  176. symbol.name = p_func->arguments[i];
  177. symbol.range.start.line = p_func->body->line - 1;
  178. symbol.range.start.character = p_func->body->column;
  179. symbol.range.end = symbol.range.start;
  180. r_symbol.children.push_back(symbol);
  181. }
  182. }
  183. String ExtendGDScriptParser::get_text_for_completion(const lsp::Position &p_cursor) {
  184. String longthing;
  185. int len = lines.size();
  186. for (int i = 0; i < len; i++) {
  187. if (i == p_cursor.line) {
  188. longthing += lines[i].substr(0, p_cursor.character);
  189. longthing += String::chr(0xFFFF); //not unicode, represents the cursor
  190. longthing += lines[i].substr(p_cursor.character, lines[i].size());
  191. } else {
  192. longthing += lines[i];
  193. }
  194. if (i != len - 1)
  195. longthing += "\n";
  196. }
  197. return longthing;
  198. }
  199. Error ExtendGDScriptParser::parse(const String &p_code, const String &p_path) {
  200. path = p_path;
  201. code = p_code;
  202. lines = p_code.split("\n");
  203. Error err = GDScriptParser::parse(p_code, p_path.get_base_dir(), false, p_path, false, NULL, false);
  204. update_diagnostics();
  205. update_symbols();
  206. return err;
  207. }