| 1 | /**************************************************************************/ |
| 2 | /* gdscript_compiler.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 GDSCRIPT_COMPILER_H |
| 32 | #define GDSCRIPT_COMPILER_H |
| 33 | |
| 34 | #include "gdscript.h" |
| 35 | #include "gdscript_codegen.h" |
| 36 | #include "gdscript_function.h" |
| 37 | #include "gdscript_parser.h" |
| 38 | |
| 39 | #include "core/templates/hash_set.h" |
| 40 | |
| 41 | class GDScriptCompiler { |
| 42 | const GDScriptParser *parser = nullptr; |
| 43 | HashSet<GDScript *> parsed_classes; |
| 44 | HashSet<GDScript *> parsing_classes; |
| 45 | GDScript *main_script = nullptr; |
| 46 | |
| 47 | struct CodeGen { |
| 48 | GDScript *script = nullptr; |
| 49 | const GDScriptParser::ClassNode *class_node = nullptr; |
| 50 | const GDScriptParser::FunctionNode *function_node = nullptr; |
| 51 | StringName function_name; |
| 52 | GDScriptCodeGenerator *generator = nullptr; |
| 53 | HashMap<StringName, GDScriptCodeGenerator::Address> parameters; |
| 54 | HashMap<StringName, GDScriptCodeGenerator::Address> locals; |
| 55 | List<HashMap<StringName, GDScriptCodeGenerator::Address>> locals_stack; |
| 56 | bool is_static = false; |
| 57 | |
| 58 | GDScriptCodeGenerator::Address add_local(const StringName &p_name, const GDScriptDataType &p_type) { |
| 59 | uint32_t addr = generator->add_local(p_name, p_type); |
| 60 | locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::LOCAL_VARIABLE, addr, p_type); |
| 61 | return locals[p_name]; |
| 62 | } |
| 63 | |
| 64 | GDScriptCodeGenerator::Address add_local_constant(const StringName &p_name, const Variant &p_value) { |
| 65 | uint32_t addr = generator->add_local_constant(p_name, p_value); |
| 66 | locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CONSTANT, addr); |
| 67 | return locals[p_name]; |
| 68 | } |
| 69 | |
| 70 | GDScriptCodeGenerator::Address add_temporary(const GDScriptDataType &p_type = GDScriptDataType()) { |
| 71 | uint32_t addr = generator->add_temporary(p_type); |
| 72 | return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::TEMPORARY, addr, p_type); |
| 73 | } |
| 74 | |
| 75 | GDScriptCodeGenerator::Address add_constant(const Variant &p_constant) { |
| 76 | GDScriptDataType type; |
| 77 | type.has_type = true; |
| 78 | type.kind = GDScriptDataType::BUILTIN; |
| 79 | type.builtin_type = p_constant.get_type(); |
| 80 | if (type.builtin_type == Variant::OBJECT) { |
| 81 | Object *obj = p_constant; |
| 82 | if (obj) { |
| 83 | type.kind = GDScriptDataType::NATIVE; |
| 84 | type.native_type = obj->get_class_name(); |
| 85 | |
| 86 | Ref<Script> scr = obj->get_script(); |
| 87 | if (scr.is_valid()) { |
| 88 | type.script_type = scr.ptr(); |
| 89 | Ref<GDScript> gdscript = scr; |
| 90 | if (gdscript.is_valid()) { |
| 91 | type.kind = GDScriptDataType::GDSCRIPT; |
| 92 | } else { |
| 93 | type.kind = GDScriptDataType::SCRIPT; |
| 94 | } |
| 95 | } |
| 96 | } else { |
| 97 | type.builtin_type = Variant::NIL; |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | uint32_t addr = generator->add_or_get_constant(p_constant); |
| 102 | return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CONSTANT, addr, type); |
| 103 | } |
| 104 | |
| 105 | void start_block() { |
| 106 | HashMap<StringName, GDScriptCodeGenerator::Address> old_locals = locals; |
| 107 | locals_stack.push_back(old_locals); |
| 108 | generator->start_block(); |
| 109 | } |
| 110 | |
| 111 | void end_block() { |
| 112 | locals = locals_stack.back()->get(); |
| 113 | locals_stack.pop_back(); |
| 114 | generator->end_block(); |
| 115 | } |
| 116 | }; |
| 117 | |
| 118 | bool _is_class_member_property(CodeGen &codegen, const StringName &p_name); |
| 119 | bool _is_class_member_property(GDScript *owner, const StringName &p_name); |
| 120 | bool _is_local_or_parameter(CodeGen &codegen, const StringName &p_name); |
| 121 | |
| 122 | void _set_error(const String &p_error, const GDScriptParser::Node *p_node); |
| 123 | |
| 124 | Error _create_binary_operator(CodeGen &codegen, const GDScriptParser::BinaryOpNode *on, Variant::Operator op, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address()); |
| 125 | Error _create_binary_operator(CodeGen &codegen, const GDScriptParser::ExpressionNode *p_left_operand, const GDScriptParser::ExpressionNode *p_right_operand, Variant::Operator op, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address()); |
| 126 | |
| 127 | GDScriptDataType _gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner, bool p_handle_metatype = true); |
| 128 | |
| 129 | GDScriptCodeGenerator::Address _parse_assign_right_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::AssignmentNode *p_assignmentint, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address()); |
| 130 | GDScriptCodeGenerator::Address _parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root = false, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address()); |
| 131 | GDScriptCodeGenerator::Address _parse_match_pattern(CodeGen &codegen, Error &r_error, const GDScriptParser::PatternNode *p_pattern, const GDScriptCodeGenerator::Address &p_value_addr, const GDScriptCodeGenerator::Address &p_type_addr, const GDScriptCodeGenerator::Address &p_previous_test, bool p_is_first, bool p_is_nested); |
| 132 | List<GDScriptCodeGenerator::Address> _add_locals_in_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block); |
| 133 | void _clear_addresses(CodeGen &codegen, const List<GDScriptCodeGenerator::Address> &p_addresses); |
| 134 | Error _parse_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block, bool p_add_locals = true, bool p_reset_locals = true); |
| 135 | GDScriptFunction *_parse_function(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false, bool p_for_lambda = false); |
| 136 | GDScriptFunction *_make_static_initializer(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class); |
| 137 | Error _parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter); |
| 138 | Error _prepare_compilation(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); |
| 139 | Error _compile_class(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); |
| 140 | int err_line = 0; |
| 141 | int err_column = 0; |
| 142 | StringName source; |
| 143 | String error; |
| 144 | GDScriptParser::ExpressionNode *awaited_node = nullptr; |
| 145 | bool has_static_data = false; |
| 146 | |
| 147 | public: |
| 148 | static void convert_to_initializer_type(Variant &p_variant, const GDScriptParser::VariableNode *p_node); |
| 149 | static void make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); |
| 150 | Error compile(const GDScriptParser *p_parser, GDScript *p_script, bool p_keep_state = false); |
| 151 | |
| 152 | String get_error() const; |
| 153 | int get_error_line() const; |
| 154 | int get_error_column() const; |
| 155 | |
| 156 | GDScriptCompiler(); |
| 157 | }; |
| 158 | |
| 159 | #endif // GDSCRIPT_COMPILER_H |
| 160 | |