From 3445dca01d81cfca7d5233ab7e3fda2798f75dc5 Mon Sep 17 00:00:00 2001 From: George Marques Date: Tue, 19 Jun 2018 02:55:52 -0300 Subject: [PATCH] Add ability to infer variable type from assigned value Syntax: var x : = 42 Infers the type of "x" to be an integer. --- modules/gdscript/gdscript_parser.cpp | 49 ++++++++++++++++++++++++++-- modules/gdscript/gdscript_parser.h | 2 ++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index f4426cd0a1c..8264d87b89c 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -2684,7 +2684,13 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { Node *assigned = NULL; if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { - if (!_parse_type(lv->datatype)) { + if (tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { + lv->datatype = DataType(); +#ifdef DEBUG_ENABLED + lv->datatype.infer_type = true; +#endif + tokenizer->advance(); + } else if (!_parse_type(lv->datatype)) { _set_error("Expected type for variable."); return; } @@ -4414,7 +4420,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { - if (!_parse_type(member.data_type)) { + if (tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { + member.data_type = DataType(); +#ifdef DEBUG_ENABLED + member.data_type.infer_type = true; +#endif + tokenizer->advance(); + } else if (!_parse_type(member.data_type)) { _set_error("Expected type for class variable."); return; } @@ -4606,7 +4618,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { - if (!_parse_type(constant.type)) { + if (tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { + constant.type = DataType(); +#ifdef DEBUG_ENABLED + constant.type.infer_type = true; +#endif + tokenizer->advance(); + } else if (!_parse_type(constant.type)) { _set_error("Expected type for class constant."); return; } @@ -6464,14 +6482,17 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat } if (!valid) { +#ifdef DEBUG_ENABLED if (p_call->arguments[0]->type == Node::TYPE_SELF) { _set_error("Method '" + callee_name + "' is not declared in the current class.", p_call->line); return DataType(); } _mark_line_as_unsafe(p_call->line); +#endif return DataType(); } +#ifdef DEBUG_ENABLED if (current_function && !for_completion && !is_static && p_call->arguments[0]->type == Node::TYPE_SELF && current_function->_static) { if (current_function && current_function->_static && p_call->arguments[0]->type == Node::TYPE_SELF) { _set_error("Can't call non-static function from a static function.", p_call->line); @@ -6483,6 +6504,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat _set_error("Non-static function '" + String(callee_name) + "' can only be called from an instance.", p_call->line); return DataType(); } +#endif } break; } @@ -6967,6 +6989,15 @@ void GDScriptParser::_check_class_level_types(ClassNode *p_class) { v.initial_assignment->arguments[1] = convert_call; } } + + if (v.data_type.infer_type) { + if (!expr_type.has_type) { + _set_error("Assigned value does not have a set type, variable type cannot be inferred.", v.line); + return; + } + v.data_type = expr_type; + v.data_type.is_constant = false; + } } else if (v.data_type.has_type && v.data_type.kind == DataType::BUILTIN) { // Create default value based on the type IdentifierNode *id = alloc_node(); @@ -7249,6 +7280,14 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { lv->assign_op->arguments[1] = convert_call; } } + if (lv->datatype.infer_type) { + if (!assign_type.has_type) { + _set_error("Assigned value does not have a set type, variable type cannot be inferred.", lv->line); + return; + } + lv->datatype = assign_type; + lv->datatype.is_constant = false; + } if (lv->datatype.has_type && !assign_type.has_type) { _mark_line_as_unsafe(lv->line); } @@ -7514,7 +7553,11 @@ Error GDScriptParser::_parse(const String &p_base_path) { current_class = main_class; current_function = NULL; current_block = NULL; +#ifdef DEBUG_ENABLED if (for_completion) check_types = false; +#else + check_types = false; +#endif if (check_types) { // Resolve all class-level stuff before getting into function blocks diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 2650f619f89..48f256b4c6a 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -56,6 +56,7 @@ public: bool has_type; bool is_constant; bool is_meta_type; // Whether the value can be used as a type + bool infer_type; Variant::Type builtin_type; StringName native_type; @@ -93,6 +94,7 @@ public: has_type(false), is_constant(false), is_meta_type(false), + infer_type(false), builtin_type(Variant::NIL), class_type(NULL) {} };