1 | /**************************************************************************/ |
2 | /* script_language.h */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
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 | |
31 | #ifndef SCRIPT_LANGUAGE_H |
32 | #define SCRIPT_LANGUAGE_H |
33 | |
34 | #include "core/doc_data.h" |
35 | #include "core/io/resource.h" |
36 | #include "core/object/script_instance.h" |
37 | #include "core/templates/pair.h" |
38 | #include "core/templates/rb_map.h" |
39 | #include "core/templates/safe_refcount.h" |
40 | #include "core/variant/typed_array.h" |
41 | |
42 | class ScriptLanguage; |
43 | template <typename T> |
44 | class TypedArray; |
45 | |
46 | typedef void (*ScriptEditRequestFunction)(const String &p_path); |
47 | |
48 | class ScriptServer { |
49 | enum { |
50 | MAX_LANGUAGES = 16 |
51 | }; |
52 | |
53 | static ScriptLanguage *_languages[MAX_LANGUAGES]; |
54 | static int _language_count; |
55 | static bool scripting_enabled; |
56 | static bool reload_scripts_on_save; |
57 | static SafeFlag languages_finished; // Used until GH-76581 is fixed properly. |
58 | |
59 | struct GlobalScriptClass { |
60 | StringName language; |
61 | String path; |
62 | StringName base; |
63 | }; |
64 | |
65 | static HashMap<StringName, GlobalScriptClass> global_classes; |
66 | static HashMap<StringName, Vector<StringName>> inheriters_cache; |
67 | static bool inheriters_cache_dirty; |
68 | |
69 | public: |
70 | static ScriptEditRequestFunction edit_request_func; |
71 | |
72 | static void set_scripting_enabled(bool p_enabled); |
73 | static bool is_scripting_enabled(); |
74 | _FORCE_INLINE_ static int get_language_count() { return _language_count; } |
75 | static ScriptLanguage *get_language(int p_idx); |
76 | static Error register_language(ScriptLanguage *p_language); |
77 | static Error unregister_language(const ScriptLanguage *p_language); |
78 | |
79 | static void set_reload_scripts_on_save(bool p_enable); |
80 | static bool is_reload_scripts_on_save_enabled(); |
81 | |
82 | static void thread_enter(); |
83 | static void thread_exit(); |
84 | |
85 | static void global_classes_clear(); |
86 | static void add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path); |
87 | static void remove_global_class(const StringName &p_class); |
88 | static void remove_global_class_by_path(const String &p_path); |
89 | static bool is_global_class(const StringName &p_class); |
90 | static StringName get_global_class_language(const StringName &p_class); |
91 | static String get_global_class_path(const String &p_class); |
92 | static StringName get_global_class_base(const String &p_class); |
93 | static StringName get_global_class_native_base(const String &p_class); |
94 | static void get_global_class_list(List<StringName> *r_global_classes); |
95 | static void get_inheriters_list(const StringName &p_base_type, List<StringName> *r_classes); |
96 | static void save_global_classes(); |
97 | static String get_global_class_cache_file_path(); |
98 | |
99 | static void init_languages(); |
100 | static void finish_languages(); |
101 | |
102 | static bool are_languages_finished() { return languages_finished.is_set(); } |
103 | }; |
104 | |
105 | class PlaceHolderScriptInstance; |
106 | |
107 | class Script : public Resource { |
108 | GDCLASS(Script, Resource); |
109 | OBJ_SAVE_TYPE(Script); |
110 | |
111 | protected: |
112 | virtual bool editor_can_reload_from_file() override { return false; } // this is handled by editor better |
113 | void _notification(int p_what); |
114 | static void _bind_methods(); |
115 | |
116 | friend class PlaceHolderScriptInstance; |
117 | virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {} |
118 | |
119 | Variant _get_property_default_value(const StringName &p_property); |
120 | TypedArray<Dictionary> _get_script_property_list(); |
121 | TypedArray<Dictionary> _get_script_method_list(); |
122 | TypedArray<Dictionary> _get_script_signal_list(); |
123 | Dictionary _get_script_constant_map(); |
124 | |
125 | public: |
126 | virtual bool can_instantiate() const = 0; |
127 | |
128 | virtual Ref<Script> get_base_script() const = 0; //for script inheritance |
129 | virtual StringName get_global_name() const = 0; |
130 | virtual bool inherits_script(const Ref<Script> &p_script) const = 0; |
131 | |
132 | virtual StringName get_instance_base_type() const = 0; // this may not work in all scripts, will return empty if so |
133 | virtual ScriptInstance *instance_create(Object *p_this) = 0; |
134 | virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this) { return nullptr; } |
135 | virtual bool instance_has(const Object *p_this) const = 0; |
136 | |
137 | virtual bool has_source_code() const = 0; |
138 | virtual String get_source_code() const = 0; |
139 | virtual void set_source_code(const String &p_code) = 0; |
140 | virtual Error reload(bool p_keep_state = false) = 0; |
141 | |
142 | #ifdef TOOLS_ENABLED |
143 | virtual Vector<DocData::ClassDoc> get_documentation() const = 0; |
144 | virtual String get_class_icon_path() const = 0; |
145 | virtual PropertyInfo get_class_category() const; |
146 | #endif // TOOLS_ENABLED |
147 | |
148 | virtual bool has_method(const StringName &p_method) const = 0; |
149 | virtual MethodInfo get_method_info(const StringName &p_method) const = 0; |
150 | |
151 | virtual bool is_tool() const = 0; |
152 | virtual bool is_valid() const = 0; |
153 | |
154 | virtual ScriptLanguage *get_language() const = 0; |
155 | |
156 | virtual bool has_script_signal(const StringName &p_signal) const = 0; |
157 | virtual void get_script_signal_list(List<MethodInfo> *r_signals) const = 0; |
158 | |
159 | virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const = 0; |
160 | |
161 | virtual void update_exports() {} //editor tool |
162 | virtual void get_script_method_list(List<MethodInfo> *p_list) const = 0; |
163 | virtual void get_script_property_list(List<PropertyInfo> *p_list) const = 0; |
164 | |
165 | virtual int get_member_line(const StringName &p_member) const { return -1; } |
166 | |
167 | virtual void get_constants(HashMap<StringName, Variant> *p_constants) {} |
168 | virtual void get_members(HashSet<StringName> *p_constants) {} |
169 | |
170 | virtual bool is_placeholder_fallback_enabled() const { return false; } |
171 | |
172 | virtual const Variant get_rpc_config() const = 0; |
173 | |
174 | Script() {} |
175 | }; |
176 | |
177 | class ScriptCodeCompletionCache { |
178 | static ScriptCodeCompletionCache *singleton; |
179 | |
180 | public: |
181 | static ScriptCodeCompletionCache *get_singleton() { return singleton; } |
182 | |
183 | ScriptCodeCompletionCache(); |
184 | |
185 | virtual ~ScriptCodeCompletionCache() {} |
186 | }; |
187 | |
188 | class ScriptLanguage : public Object { |
189 | GDCLASS(ScriptLanguage, Object) |
190 | public: |
191 | virtual String get_name() const = 0; |
192 | |
193 | /* LANGUAGE FUNCTIONS */ |
194 | virtual void init() = 0; |
195 | virtual String get_type() const = 0; |
196 | virtual String get_extension() const = 0; |
197 | virtual void finish() = 0; |
198 | |
199 | /* EDITOR FUNCTIONS */ |
200 | struct Warning { |
201 | int start_line = -1, end_line = -1; |
202 | int leftmost_column = -1, rightmost_column = -1; |
203 | int code; |
204 | String string_code; |
205 | String message; |
206 | }; |
207 | |
208 | struct ScriptError { |
209 | String path; |
210 | int line = -1; |
211 | int column = -1; |
212 | String message; |
213 | }; |
214 | |
215 | enum TemplateLocation { |
216 | TEMPLATE_BUILT_IN, |
217 | TEMPLATE_EDITOR, |
218 | TEMPLATE_PROJECT |
219 | }; |
220 | |
221 | struct ScriptTemplate { |
222 | String inherit = "Object" ; |
223 | String name; |
224 | String description; |
225 | String content; |
226 | int id = 0; |
227 | TemplateLocation origin = TemplateLocation::TEMPLATE_BUILT_IN; |
228 | |
229 | String get_hash() const { |
230 | return itos(origin) + inherit + name; |
231 | } |
232 | }; |
233 | |
234 | void get_core_type_words(List<String> *p_core_type_words) const; |
235 | virtual void get_reserved_words(List<String> *p_words) const = 0; |
236 | virtual bool is_control_flow_keyword(String p_string) const = 0; |
237 | virtual void (List<String> *p_delimiters) const = 0; |
238 | virtual void get_string_delimiters(List<String> *p_delimiters) const = 0; |
239 | virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const { return Ref<Script>(); } |
240 | virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) { return Vector<ScriptTemplate>(); } |
241 | virtual bool is_using_templates() { return false; } |
242 | virtual bool validate(const String &p_script, const String &p_path = "" , List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const = 0; |
243 | virtual String validate_path(const String &p_path) const { return "" ; } |
244 | virtual Script *create_script() const = 0; |
245 | virtual bool has_named_classes() const = 0; |
246 | virtual bool supports_builtin_mode() const = 0; |
247 | virtual bool supports_documentation() const { return false; } |
248 | virtual bool can_inherit_from_file() const { return false; } |
249 | virtual int find_function(const String &p_function, const String &p_code) const = 0; |
250 | virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const = 0; |
251 | virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; } |
252 | virtual bool overrides_external_editor() { return false; } |
253 | |
254 | // Keep enums in sync with: |
255 | // scene/gui/code_edit.h - CodeEdit::CodeCompletionKind |
256 | enum CodeCompletionKind { |
257 | CODE_COMPLETION_KIND_CLASS, |
258 | CODE_COMPLETION_KIND_FUNCTION, |
259 | CODE_COMPLETION_KIND_SIGNAL, |
260 | CODE_COMPLETION_KIND_VARIABLE, |
261 | CODE_COMPLETION_KIND_MEMBER, |
262 | CODE_COMPLETION_KIND_ENUM, |
263 | CODE_COMPLETION_KIND_CONSTANT, |
264 | CODE_COMPLETION_KIND_NODE_PATH, |
265 | CODE_COMPLETION_KIND_FILE_PATH, |
266 | CODE_COMPLETION_KIND_PLAIN_TEXT, |
267 | CODE_COMPLETION_KIND_MAX |
268 | }; |
269 | |
270 | // scene/gui/code_edit.h - CodeEdit::CodeCompletionLocation |
271 | enum CodeCompletionLocation { |
272 | LOCATION_LOCAL = 0, |
273 | LOCATION_PARENT_MASK = 1 << 8, |
274 | LOCATION_OTHER_USER_CODE = 1 << 9, |
275 | LOCATION_OTHER = 1 << 10, |
276 | }; |
277 | |
278 | struct CodeCompletionOption { |
279 | CodeCompletionKind kind = CODE_COMPLETION_KIND_PLAIN_TEXT; |
280 | String display; |
281 | String insert_text; |
282 | Color font_color; |
283 | Ref<Resource> icon; |
284 | Variant default_value; |
285 | Vector<Pair<int, int>> matches; |
286 | Vector<Pair<int, int>> last_matches = { { -1, -1 } }; // This value correspond to an impossible match |
287 | int location = LOCATION_OTHER; |
288 | String theme_color_name; |
289 | |
290 | CodeCompletionOption() {} |
291 | |
292 | CodeCompletionOption(const String &p_text, CodeCompletionKind p_kind, int p_location = LOCATION_OTHER, const String &p_theme_color_name = "" ) { |
293 | display = p_text; |
294 | insert_text = p_text; |
295 | kind = p_kind; |
296 | location = p_location; |
297 | theme_color_name = p_theme_color_name; |
298 | } |
299 | |
300 | TypedArray<int> get_option_characteristics(const String &p_base); |
301 | void clear_characteristics(); |
302 | TypedArray<int> get_option_cached_characteristics() const; |
303 | |
304 | private: |
305 | TypedArray<int> charac; |
306 | }; |
307 | |
308 | virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<CodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; } |
309 | |
310 | enum LookupResultType { |
311 | LOOKUP_RESULT_SCRIPT_LOCATION, |
312 | LOOKUP_RESULT_CLASS, |
313 | LOOKUP_RESULT_CLASS_CONSTANT, |
314 | LOOKUP_RESULT_CLASS_PROPERTY, |
315 | LOOKUP_RESULT_CLASS_METHOD, |
316 | LOOKUP_RESULT_CLASS_SIGNAL, |
317 | LOOKUP_RESULT_CLASS_ENUM, |
318 | LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE, |
319 | LOOKUP_RESULT_CLASS_ANNOTATION, |
320 | LOOKUP_RESULT_MAX |
321 | }; |
322 | |
323 | struct LookupResult { |
324 | LookupResultType type; |
325 | Ref<Script> script; |
326 | String class_name; |
327 | String class_member; |
328 | String class_path; |
329 | int location; |
330 | }; |
331 | |
332 | virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { return ERR_UNAVAILABLE; } |
333 | |
334 | virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const = 0; |
335 | virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) = 0; |
336 | virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value) {} |
337 | virtual void remove_named_global_constant(const StringName &p_name) {} |
338 | |
339 | /* MULTITHREAD FUNCTIONS */ |
340 | |
341 | //some VMs need to be notified of thread creation/exiting to allocate a stack |
342 | virtual void thread_enter() {} |
343 | virtual void thread_exit() {} |
344 | |
345 | /* DEBUGGER FUNCTIONS */ |
346 | struct StackInfo { |
347 | String file; |
348 | String func; |
349 | int line; |
350 | }; |
351 | |
352 | virtual String debug_get_error() const = 0; |
353 | virtual int debug_get_stack_level_count() const = 0; |
354 | virtual int debug_get_stack_level_line(int p_level) const = 0; |
355 | virtual String debug_get_stack_level_function(int p_level) const = 0; |
356 | virtual String debug_get_stack_level_source(int p_level) const = 0; |
357 | virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0; |
358 | virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0; |
359 | virtual ScriptInstance *debug_get_stack_level_instance(int p_level) { return nullptr; } |
360 | virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0; |
361 | virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) = 0; |
362 | |
363 | virtual Vector<StackInfo> debug_get_current_stack_info() { return Vector<StackInfo>(); } |
364 | |
365 | virtual void reload_all_scripts() = 0; |
366 | virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) = 0; |
367 | /* LOADER FUNCTIONS */ |
368 | |
369 | virtual void get_recognized_extensions(List<String> *p_extensions) const = 0; |
370 | virtual void get_public_functions(List<MethodInfo> *p_functions) const = 0; |
371 | virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const = 0; |
372 | virtual void get_public_annotations(List<MethodInfo> *p_annotations) const = 0; |
373 | |
374 | struct ProfilingInfo { |
375 | StringName signature; |
376 | uint64_t call_count; |
377 | uint64_t total_time; |
378 | uint64_t self_time; |
379 | }; |
380 | |
381 | virtual void profiling_start() = 0; |
382 | virtual void profiling_stop() = 0; |
383 | |
384 | virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) = 0; |
385 | virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) = 0; |
386 | |
387 | virtual void frame(); |
388 | |
389 | virtual bool handles_global_class_type(const String &p_type) const { return false; } |
390 | virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const { return String(); } |
391 | |
392 | virtual ~ScriptLanguage() {} |
393 | }; |
394 | |
395 | extern uint8_t script_encryption_key[32]; |
396 | |
397 | class PlaceHolderScriptInstance : public ScriptInstance { |
398 | Object *owner = nullptr; |
399 | List<PropertyInfo> properties; |
400 | HashMap<StringName, Variant> values; |
401 | HashMap<StringName, Variant> constants; |
402 | ScriptLanguage *language = nullptr; |
403 | Ref<Script> script; |
404 | |
405 | public: |
406 | virtual bool set(const StringName &p_name, const Variant &p_value) override; |
407 | virtual bool get(const StringName &p_name, Variant &r_ret) const override; |
408 | virtual void get_property_list(List<PropertyInfo> *p_properties) const override; |
409 | virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const override; |
410 | virtual void validate_property(PropertyInfo &p_property) const override {} |
411 | |
412 | virtual bool property_can_revert(const StringName &p_name) const override { return false; }; |
413 | virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const override { return false; }; |
414 | |
415 | virtual void get_method_list(List<MethodInfo> *p_list) const override; |
416 | virtual bool has_method(const StringName &p_method) const override; |
417 | |
418 | virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override { |
419 | r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; |
420 | return Variant(); |
421 | } |
422 | virtual void notification(int p_notification, bool p_reversed = false) override {} |
423 | |
424 | virtual Ref<Script> get_script() const override { return script; } |
425 | |
426 | virtual ScriptLanguage *get_language() override { return language; } |
427 | |
428 | Object *get_owner() override { return owner; } |
429 | |
430 | void update(const List<PropertyInfo> &p_properties, const HashMap<StringName, Variant> &p_values); //likely changed in editor |
431 | |
432 | virtual bool is_placeholder() const override { return true; } |
433 | |
434 | virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr) override; |
435 | virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = nullptr) override; |
436 | |
437 | virtual const Variant get_rpc_config() const override { return Variant(); } |
438 | |
439 | PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner); |
440 | ~PlaceHolderScriptInstance(); |
441 | }; |
442 | |
443 | #endif // SCRIPT_LANGUAGE_H |
444 | |