From db97059e5f2473e46c6562e88c92b327d5c71530 Mon Sep 17 00:00:00 2001 From: rune-scape Date: Sun, 18 Jun 2023 00:59:20 -0700 Subject: [PATCH] added 'is null' operator --- modules/gdscript/gdscript_analyzer.cpp | 17 +++++++++++++++-- modules/gdscript/gdscript_byte_codegen.cpp | 3 +++ modules/gdscript/gdscript_parser.cpp | 15 ++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index ca8d572a60fd..b7993c62cc19 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -4466,7 +4466,16 @@ void GDScriptAnalyzer::reduce_type_test(GDScriptParser::TypeTestNode *p_type_tes p_type_test->is_constant = true; p_type_test->reduced_value = false; - if (!is_type_compatible(test_type, operand_type)) { + if (test_type.kind == GDScriptParser::DataType::BUILTIN && test_type.builtin_type == Variant::NIL) { + const Variant &operand_reduced_value = p_type_test->operand->reduced_value; + if (operand_reduced_value.get_type() == Variant::NIL) { + p_type_test->reduced_value = true; + } else if (operand_reduced_value.get_type() == Variant::OBJECT && operand_reduced_value.is_null()) { + p_type_test->reduced_value = true; + } else { + p_type_test->reduced_value = false; + } + } else if (!is_type_compatible(test_type, operand_type)) { push_error(vformat(R"(Expression is of type "%s" so it can't be of type "%s".)", operand_type.to_string(), test_type.to_string()), p_type_test->operand); } else if (is_type_compatible(test_type, type_from_variant(p_type_test->operand->reduced_value, p_type_test->operand))) { p_type_test->reduced_value = test_type.builtin_type != Variant::OBJECT || !p_type_test->operand->reduced_value.is_null(); @@ -4475,7 +4484,11 @@ void GDScriptAnalyzer::reduce_type_test(GDScriptParser::TypeTestNode *p_type_tes return; } - if (!is_type_compatible(test_type, operand_type) && !is_type_compatible(operand_type, test_type)) { + if (test_type.kind == GDScriptParser::DataType::BUILTIN && test_type.builtin_type == Variant::NIL) { + if (operand_type.kind == GDScriptParser::DataType::ENUM || (operand_type.kind == GDScriptParser::DataType::BUILTIN && operand_type.builtin_type != Variant::NIL && operand_type.builtin_type != Variant::OBJECT)) { + push_error(vformat(R"(Expression is of type "%s" so it can't be null.)", operand_type.to_string()), p_type_test->operand); + } + } else if (!is_type_compatible(test_type, operand_type) && !is_type_compatible(operand_type, test_type)) { if (operand_type.is_hard_type()) { push_error(vformat(R"(Expression is of type "%s" so it can't be of type "%s".)", operand_type.to_string(), test_type.to_string()), p_type_test->operand); } else { diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index d6f21d297a26..8c29764e6886 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -624,6 +624,9 @@ void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const A append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); append(element_type.builtin_type); append(element_type.native_type); + } else if (p_type.builtin_type == Variant::NIL) { + GDScriptCodeGenerator::Address null_value_address(GDScriptCodeGenerator::Address::CONSTANT, add_or_get_constant(Variant()), p_type); + write_binary_operator(p_target, Variant::OP_EQUAL, p_source, null_value_address); } else { append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_BUILTIN); append(p_target); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 410f5ca36b17..76fb305d482b 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3317,7 +3317,20 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_type_test(ExpressionNode * type_test->is_not = true; } - type_test->test_type = parse_type(); + if (check(GDScriptTokenizer::Token::LITERAL) && current.literal == Variant()) { + IdentifierNode *nil_identifier = alloc_node(); + nil_identifier->name = SNAME("Nil"); + complete_extents(nil_identifier); + + TypeNode *type = alloc_node(); + type->type_chain.push_back(nil_identifier); + complete_extents(type); + + type_test->test_type = type; + } else { + type_test->test_type = parse_type(); + } + complete_extents(type_test); if (type_test->test_type == nullptr) {