diff options
Diffstat (limited to 'modules/gdscript')
-rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 286 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 208 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.h | 22 |
4 files changed, 489 insertions, 29 deletions
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index def2bed714..8c83f712ad 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -273,8 +273,22 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: // TRY MEMBER VARIABLES! //static function if (codegen.script->member_indices.has(identifier)) { - int idx = codegen.script->member_indices[identifier].index; - return idx | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS); //argument (stack root) + if (codegen.script->member_indices[identifier].getter != StringName() && codegen.script->member_indices[identifier].getter != codegen.function_name) { + // Perform getter. + codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_RETURN); + codegen.opcodes.push_back(0); // Argument count. + codegen.opcodes.push_back(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); // Base (self). + codegen.opcodes.push_back(codegen.get_name_map_pos(codegen.script->member_indices[identifier].getter)); // Method name. + // Destination. + int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); + codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode + codegen.alloc_stack(p_stack_level); + return dst_addr; + } else { + // No getter or inside getter: direct member access. + int idx = codegen.script->member_indices[identifier].index; + return idx | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS); //argument (stack root) + } } } @@ -779,12 +793,12 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: if (p_index_addr != 0) { index = p_index_addr; } else if (subscript->is_attribute) { - if (subscript->base->type == GDScriptParser::Node::SELF && codegen.script && codegen.function_node && !codegen.function_node->is_static) { + if (subscript->base->type == GDScriptParser::Node::SELF && codegen.script) { GDScriptParser::IdentifierNode *identifier = subscript->attribute; const Map<StringName, GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(identifier->name); #ifdef DEBUG_ENABLED - if (MI && MI->get().getter == codegen.function_node->identifier->name) { + if (MI && MI->get().getter == codegen.function_name) { String n = identifier->name; _set_error("Must use '" + n + "' instead of 'self." + n + "' in getter.", identifier); return -1; @@ -1095,9 +1109,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: const GDScriptParser::SubscriptNode *subscript = static_cast<GDScriptParser::SubscriptNode *>(assignment->assignee); #ifdef DEBUG_ENABLED if (subscript->is_attribute) { - if (subscript->base->type == GDScriptParser::Node::SELF && codegen.script && codegen.function_node && !codegen.function_node->is_static) { + if (subscript->base->type == GDScriptParser::Node::SELF && codegen.script) { const Map<StringName, GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(subscript->attribute->name); - if (MI && MI->get().setter == codegen.function_node->identifier->name) { + if (MI && MI->get().setter == codegen.function_name) { String n = subscript->attribute->name; _set_error("Must use '" + n + "' instead of 'self." + n + "' in setter.", subscript); return -1; @@ -1263,15 +1277,43 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: //REGULAR ASSIGNMENT MODE!! int slevel = p_stack_level; - - int dst_address_a = _parse_expression(codegen, assignment->assignee, slevel); - if (dst_address_a < 0) { - return -1; + int dst_address_a = -1; + + bool has_setter = false; + bool is_in_setter = false; + StringName setter_function; + if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER) { + StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name; + if (!codegen.stack_identifiers.has(var_name) && codegen.script->member_indices.has(var_name)) { + setter_function = codegen.script->member_indices[var_name].setter; + if (setter_function != StringName()) { + has_setter = true; + is_in_setter = setter_function == codegen.function_name; + dst_address_a = codegen.script->member_indices[var_name].index; + } + } } - if (dst_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); + if (has_setter) { + if (is_in_setter) { + // Use direct member access. + dst_address_a |= GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS; + } else { + // Store stack slot for the temp value. + dst_address_a = slevel++; + codegen.alloc_stack(slevel); + dst_address_a |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS; + } + } else { + dst_address_a = _parse_expression(codegen, assignment->assignee, slevel); + if (dst_address_a < 0) { + return -1; + } + + if (dst_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) { + slevel++; + codegen.alloc_stack(slevel); + } } int src_address_b = _parse_assign_right_expression(codegen, assignment, slevel); @@ -1330,6 +1372,18 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(dst_address_a); // argument 1 codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) } + + if (has_setter && !is_in_setter) { + // Call setter. + codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL); + codegen.opcodes.push_back(1); // Argument count. + codegen.opcodes.push_back(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); // Base (self). + codegen.opcodes.push_back(codegen.get_name_map_pos(setter_function)); // Method name. + codegen.opcodes.push_back(dst_address_a); // Argument. + codegen.opcodes.push_back(dst_address_a); // Result address (won't be used here). + codegen.alloc_call(1); + } + return dst_address_a; //if anything, returns wathever was assigned or correct stack position } } break; @@ -2157,13 +2211,14 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser } defarg_addr.invert(); } + func_name = p_func->identifier->name; + codegen.function_name = func_name; Error err = _parse_block(codegen, p_func->body, stack_level); if (err) { return err; } - func_name = p_func->identifier->name; } else { if (p_for_ready) { func_name = "_ready"; @@ -2172,6 +2227,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser } } + codegen.function_name = func_name; codegen.opcodes.push_back(GDScriptFunction::OPCODE_END); /* @@ -2327,6 +2383,150 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser return OK; } +Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter) { + Vector<int> bytecode; + CodeGen codegen; + + codegen.class_node = p_class; + codegen.script = p_script; + codegen.function_node = nullptr; + codegen.stack_max = 0; + codegen.current_line = 0; + codegen.call_max = 0; + codegen.debug_stack = EngineDebugger::is_active(); + Vector<StringName> argnames; + + int stack_level = 0; + + if (p_is_setter) { + codegen.add_stack_identifier(p_variable->setter_parameter->name, stack_level++); + argnames.push_back(p_variable->setter_parameter->name); + } + + codegen.alloc_stack(stack_level); + + StringName func_name; + + if (p_is_setter) { + func_name = "@" + p_variable->identifier->name + "_setter"; + } else { + func_name = "@" + p_variable->identifier->name + "_getter"; + } + codegen.function_name = func_name; + + Error err = _parse_block(codegen, p_is_setter ? p_variable->setter : p_variable->getter, stack_level); + if (err != OK) { + return err; + } + + codegen.opcodes.push_back(GDScriptFunction::OPCODE_END); + + p_script->member_functions[func_name] = memnew(GDScriptFunction); + GDScriptFunction *gdfunc = p_script->member_functions[func_name]; + + gdfunc->_static = false; + gdfunc->rpc_mode = p_variable->rpc_mode; + gdfunc->argument_types.resize(p_is_setter ? 1 : 0); + gdfunc->return_type = GDScriptDataType(); // TODO +#ifdef TOOLS_ENABLED + gdfunc->arg_names = argnames; +#endif + + // TODO: Unify this with function compiler. + //constants + if (codegen.constant_map.size()) { + gdfunc->_constant_count = codegen.constant_map.size(); + gdfunc->constants.resize(codegen.constant_map.size()); + gdfunc->_constants_ptr = gdfunc->constants.ptrw(); + const Variant *K = nullptr; + while ((K = codegen.constant_map.next(K))) { + int idx = codegen.constant_map[*K]; + gdfunc->constants.write[idx] = *K; + } + } else { + gdfunc->_constants_ptr = nullptr; + gdfunc->_constant_count = 0; + } + //global names + if (codegen.name_map.size()) { + gdfunc->global_names.resize(codegen.name_map.size()); + gdfunc->_global_names_ptr = &gdfunc->global_names[0]; + for (Map<StringName, int>::Element *E = codegen.name_map.front(); E; E = E->next()) { + gdfunc->global_names.write[E->get()] = E->key(); + } + gdfunc->_global_names_count = gdfunc->global_names.size(); + + } else { + gdfunc->_global_names_ptr = nullptr; + gdfunc->_global_names_count = 0; + } + +#ifdef TOOLS_ENABLED + // Named globals + if (codegen.named_globals.size()) { + gdfunc->named_globals.resize(codegen.named_globals.size()); + gdfunc->_named_globals_ptr = gdfunc->named_globals.ptr(); + for (int i = 0; i < codegen.named_globals.size(); i++) { + gdfunc->named_globals.write[i] = codegen.named_globals[i]; + } + gdfunc->_named_globals_count = gdfunc->named_globals.size(); + } +#endif + + gdfunc->code = codegen.opcodes; + gdfunc->_code_ptr = &gdfunc->code[0]; + gdfunc->_code_size = codegen.opcodes.size(); + gdfunc->_default_arg_count = 0; + gdfunc->_default_arg_ptr = nullptr; + gdfunc->_argument_count = argnames.size(); + gdfunc->_stack_size = codegen.stack_max; + gdfunc->_call_size = codegen.call_max; + gdfunc->name = func_name; +#ifdef DEBUG_ENABLED + if (EngineDebugger::is_active()) { + String signature; + //path + if (p_script->get_path() != String()) { + signature += p_script->get_path(); + } + //loc + signature += "::" + itos(p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line); + + //function and class + + if (p_class->identifier) { + signature += "::" + String(p_class->identifier->name) + "." + String(func_name); + } else { + signature += "::" + String(func_name); + } + + gdfunc->profile.signature = signature; + } +#endif + gdfunc->_script = p_script; + gdfunc->source = source; + +#ifdef DEBUG_ENABLED + + { + gdfunc->func_cname = (String(source) + " - " + String(func_name)).utf8(); + gdfunc->_func_cname = gdfunc->func_cname.get_data(); + } + +#endif + gdfunc->_initial_line = p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line; +#ifdef TOOLS_ENABLED + + p_script->member_lines[func_name] = gdfunc->_initial_line; +#endif + + if (codegen.debug_stack) { + gdfunc->stack_debug = codegen.stack_debug; + } + + return OK; +} + Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { parsing_classes.insert(p_script); @@ -2407,9 +2607,26 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar GDScript::MemberInfo minfo; minfo.index = p_script->member_indices.size(); - // FIXME: Getter and setter. - // minfo.setter = p_class->variables[i].setter; - // minfo.getter = p_class->variables[i].getter; + switch (variable->property) { + case GDScriptParser::VariableNode::PROP_NONE: + break; // Nothing to do. + case GDScriptParser::VariableNode::PROP_SETGET: + if (variable->setter_pointer != nullptr) { + minfo.setter = variable->setter_pointer->name; + } + if (variable->getter_pointer != nullptr) { + minfo.getter = variable->getter_pointer->name; + } + break; + case GDScriptParser::VariableNode::PROP_INLINE: + if (variable->setter != nullptr) { + minfo.setter = "@" + variable->identifier->name + "_setter"; + } + if (variable->getter != nullptr) { + minfo.getter = "@" + variable->identifier->name + "_getter"; + } + break; + } minfo.rpc_mode = variable->rpc_mode; // FIXME: Types. // minfo.data_type = _gdtype_from_datatype(p_class->variables[i].data_type); @@ -2565,16 +2782,31 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa for (int i = 0; i < p_class->members.size(); i++) { const GDScriptParser::ClassNode::Member &member = p_class->members[i]; - if (member.type != member.FUNCTION) { - continue; - } - const GDScriptParser::FunctionNode *function = member.function; - if (!has_ready && function->identifier->name == "_ready") { - has_ready = true; - } - Error err = _parse_function(p_script, p_class, function); - if (err) { - return err; + if (member.type == member.FUNCTION) { + const GDScriptParser::FunctionNode *function = member.function; + if (!has_ready && function->identifier->name == "_ready") { + has_ready = true; + } + Error err = _parse_function(p_script, p_class, function); + if (err) { + return err; + } + } else if (member.type == member.VARIABLE) { + const GDScriptParser::VariableNode *variable = member.variable; + if (variable->property == GDScriptParser::VariableNode::PROP_INLINE) { + if (variable->setter != nullptr) { + Error err = _parse_setter_getter(p_script, p_class, variable, true); + if (err) { + return err; + } + } + if (variable->getter != nullptr) { + Error err = _parse_setter_getter(p_script, p_class, variable, false); + if (err) { + return err; + } + } + } } } diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 674982659f..490768ea96 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -45,6 +45,7 @@ class GDScriptCompiler { GDScript *script; const GDScriptParser::ClassNode *class_node; const GDScriptParser::FunctionNode *function_node; + StringName function_name; bool debug_stack; List<Map<StringName, int>> stack_id_stack; @@ -153,6 +154,7 @@ class GDScriptCompiler { Error _parse_match_pattern(CodeGen &codegen, const GDScriptParser::PatternNode *p_pattern, int p_stack_level, int p_value_addr, int p_type_addr, int &r_bound_variables, Vector<int> &r_patch_addresses, Vector<int> &r_block_patch_address); Error _parse_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1); Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false); + Error _parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter); Error _parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); void _make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 2d82cd2d5e..8d07099fc3 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -184,6 +184,11 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_ clear(); tokenizer.set_source_code(p_source_code); current = tokenizer.scan(); + // Avoid error as the first token. + while (current.type == GDScriptTokenizer::Token::ERROR) { + push_error(current.literal); + current = tokenizer.scan(); + } push_multiline(false); // Keep one for the whole parsing. parse_program(); @@ -555,6 +560,10 @@ void GDScriptParser::parse_class_body() { } GDScriptParser::VariableNode *GDScriptParser::parse_variable() { + return parse_variable(true); +} + +GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_property) { if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected variable name after "var".)")) { return nullptr; } @@ -563,10 +572,26 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable() { variable->identifier = parse_identifier(); if (match(GDScriptTokenizer::Token::COLON)) { - if (check((GDScriptTokenizer::Token::EQUAL))) { + if (check(GDScriptTokenizer::Token::NEWLINE)) { + if (p_allow_property) { + advance(); + + return parse_property(variable, true); + } else { + push_error(R"(Expected type after ":")"); + return nullptr; + } + } else if (check((GDScriptTokenizer::Token::EQUAL))) { // Infer type. variable->infer_datatype = true; } else { + if (p_allow_property && check(GDScriptTokenizer::Token::IDENTIFIER)) { + // Check if get or set. + if (current.get_identifier() == "get" || current.get_identifier() == "set") { + return parse_property(variable, false); + } + } + // Parse type. variable->datatype_specifier = parse_type(); } @@ -577,6 +602,14 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable() { variable->initializer = parse_expression(false); } + if (p_allow_property && match(GDScriptTokenizer::Token::COLON)) { + if (match(GDScriptTokenizer::Token::NEWLINE)) { + return parse_property(variable, true); + } else { + return parse_property(variable, false); + } + } + end_statement("variable declaration"); variable->export_info.name = variable->identifier->name; @@ -584,6 +617,125 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable() { return variable; } +GDScriptParser::VariableNode *GDScriptParser::parse_property(VariableNode *p_variable, bool p_need_indent) { + if (p_need_indent) { + if (!consume(GDScriptTokenizer::Token::INDENT, R"(Expected indented block for property after ":".)")) { + return nullptr; + } + } + + if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected "get" or "set" for property declaration.)")) { + return nullptr; + } + + VariableNode *property = p_variable; + + IdentifierNode *function = parse_identifier(); + + if (check(GDScriptTokenizer::Token::EQUAL)) { + p_variable->property = VariableNode::PROP_SETGET; + } else { + p_variable->property = VariableNode::PROP_INLINE; + if (!p_need_indent) { + push_error("Property with inline code must go to an indented block."); + } + } + + bool getter_used = false; + bool setter_used = false; + + // Run with a loop because order doesn't matter. + for (int i = 0; i < 2; i++) { + if (function->name == "set") { + if (setter_used) { + push_error(R"(Properties can only have one setter.)"); + } else { + parse_property_setter(property); + setter_used = true; + } + } else if (function->name == "get") { + if (getter_used) { + push_error(R"(Properties can only have one getter.)"); + } else { + parse_property_getter(property); + getter_used = true; + } + } else { + // TODO: Update message to only have the missing one if it's the case. + push_error(R"(Expected "get" or "set" for property declaration.)"); + } + + if (i == 0 && p_variable->property == VariableNode::PROP_SETGET) { + if (match(GDScriptTokenizer::Token::COMMA)) { + // Consume potential newline. + if (match(GDScriptTokenizer::Token::NEWLINE)) { + if (!p_need_indent) { + push_error(R"(Inline setter/getter setting cannot span across multiple lines (use "\\"" if needed).)"); + } + } + } else { + break; + } + } + + if (!match(GDScriptTokenizer::Token::IDENTIFIER)) { + break; + } + function = parse_identifier(); + } + + if (p_variable->property == VariableNode::PROP_SETGET) { + end_statement("property declaration"); + } + + if (p_need_indent) { + consume(GDScriptTokenizer::Token::DEDENT, R"(Expected end of indented block for property.)"); + } + return property; +} + +void GDScriptParser::parse_property_setter(VariableNode *p_variable) { + switch (p_variable->property) { + case VariableNode::PROP_INLINE: + consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected "(" after "set".)"); + if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected parameter name after "(".)")) { + p_variable->setter_parameter = parse_identifier(); + } + consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after parameter name.)*"); + consume(GDScriptTokenizer::Token::COLON, R"*(Expected ":" after ")".)*"); + + p_variable->setter = parse_suite("setter definition"); + break; + + case VariableNode::PROP_SETGET: + consume(GDScriptTokenizer::Token::EQUAL, R"(Expected "=" after "set")"); + if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected setter function name after "=".)")) { + p_variable->setter_pointer = parse_identifier(); + } + break; + case VariableNode::PROP_NONE: + break; // Unreachable. + } +} + +void GDScriptParser::parse_property_getter(VariableNode *p_variable) { + switch (p_variable->property) { + case VariableNode::PROP_INLINE: + consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "get".)"); + + p_variable->getter = parse_suite("getter definition"); + break; + case VariableNode::PROP_SETGET: + consume(GDScriptTokenizer::Token::EQUAL, R"(Expected "=" after "get")"); + if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected getter function name after "=".)")) { + p_variable->getter_pointer = parse_identifier(); + } + break; + case VariableNode::PROP_NONE: + break; // Unreachable. + } +} + GDScriptParser::ConstantNode *GDScriptParser::parse_constant() { if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected constant name after "const".)")) { return nullptr; @@ -1021,6 +1173,9 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { default: { // Expression statement. ExpressionNode *expression = parse_expression(true); // Allow assignment here. + if (expression == nullptr) { + push_error(vformat(R"(Expected statement, found "%s" instead.)", previous.get_name())); + } end_statement("expression"); result = expression; break; @@ -1402,7 +1557,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_identifier(ExpressionNode ERR_FAIL_V_MSG(nullptr, "Parser bug: parsing literal node without literal token."); } IdentifierNode *identifier = alloc_node<IdentifierNode>(); - identifier->name = previous.literal; + identifier->name = previous.get_identifier(); return identifier; } @@ -3016,6 +3171,15 @@ void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) { push_text("Variable "); print_identifier(p_variable->identifier); + push_text(" : "); + if (p_variable->datatype_specifier != nullptr) { + print_type(p_variable->datatype_specifier); + } else if (p_variable->infer_datatype) { + push_text("<inferred type>"); + } else { + push_text("Variant"); + } + increase_indent(); push_line(); @@ -3025,6 +3189,46 @@ void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) { } else { print_expression(p_variable->initializer); } + push_line(); + + if (p_variable->property != VariableNode::PROP_NONE) { + if (p_variable->getter != nullptr) { + push_text("Get"); + if (p_variable->property == VariableNode::PROP_INLINE) { + push_line(":"); + increase_indent(); + print_suite(p_variable->getter); + decrease_indent(); + } else { + push_line(" ="); + increase_indent(); + print_identifier(p_variable->getter_pointer); + push_line(); + decrease_indent(); + } + } + if (p_variable->setter != nullptr) { + push_text("Set ("); + if (p_variable->property == VariableNode::PROP_INLINE) { + if (p_variable->setter_parameter != nullptr) { + print_identifier(p_variable->setter_parameter); + } else { + push_text("<missing>"); + } + push_line("):"); + increase_indent(); + print_suite(p_variable->setter); + decrease_indent(); + } else { + push_line(" ="); + increase_indent(); + print_identifier(p_variable->setter_pointer); + push_line(); + decrease_indent(); + } + } + } + decrease_indent(); push_line(); } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 09cb17f010..0d775915cf 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -777,10 +777,28 @@ public: }; struct VariableNode : public Node { + enum PropertyStyle { + PROP_NONE, + PROP_INLINE, + PROP_SETGET, + }; + IdentifierNode *identifier = nullptr; ExpressionNode *initializer = nullptr; TypeNode *datatype_specifier = nullptr; bool infer_datatype = false; + + PropertyStyle property = PROP_NONE; + union { + SuiteNode *setter = nullptr; + IdentifierNode *setter_pointer; + }; + IdentifierNode *setter_parameter = nullptr; + union { + SuiteNode *getter = nullptr; + IdentifierNode *getter_pointer; + }; + bool exported = false; bool onready = false; PropertyInfo export_info; @@ -923,6 +941,10 @@ private: // Statements. Node *parse_statement(); VariableNode *parse_variable(); + VariableNode *parse_variable(bool p_allow_property); + VariableNode *parse_property(VariableNode *p_variable, bool p_need_indent); + void parse_property_getter(VariableNode *p_variable); + void parse_property_setter(VariableNode *p_variable); ConstantNode *parse_constant(); AssertNode *parse_assert(); BreakNode *parse_break(); |