Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GDScript: Allow Strings and StringNames match each other in a match statement #78389

Merged
merged 1 commit into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 55 additions & 22 deletions modules/gdscript/gdscript_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1272,37 +1272,40 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
}

// Get literal type into constant map.
GDScriptCodeGenerator::Address literal_type_addr = codegen.add_constant((int)p_pattern->literal->value.get_type());
Variant::Type literal_type = p_pattern->literal->value.get_type();
GDScriptCodeGenerator::Address literal_type_addr = codegen.add_constant(literal_type);

// Equality is always a boolean.
GDScriptDataType equality_type;
equality_type.has_type = true;
equality_type.kind = GDScriptDataType::BUILTIN;
equality_type.builtin_type = Variant::BOOL;

GDScriptCodeGenerator::Address type_string_addr = codegen.add_constant(Variant::STRING);
GDScriptCodeGenerator::Address type_string_name_addr = codegen.add_constant(Variant::STRING_NAME);

// Check type equality.
GDScriptCodeGenerator::Address type_equality_addr = codegen.add_temporary(equality_type);
codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_EQUAL, p_type_addr, literal_type_addr);

// Check if StringName <-> String comparison is possible.
GDScriptCodeGenerator::Address type_comp_addr_1 = codegen.add_temporary(equality_type);
GDScriptCodeGenerator::Address type_comp_addr_2 = codegen.add_temporary(equality_type);
if (literal_type == Variant::STRING) {
GDScriptCodeGenerator::Address type_stringname_addr = codegen.add_constant(Variant::STRING_NAME);

// Check StringName <-> String type equality.
GDScriptCodeGenerator::Address tmp_comp_addr = codegen.add_temporary(equality_type);

codegen.generator->write_binary_operator(tmp_comp_addr, Variant::OP_EQUAL, p_type_addr, type_stringname_addr);
codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_OR, type_equality_addr, tmp_comp_addr);

codegen.generator->pop_temporary(); // Remove tmp_comp_addr from stack.
} else if (literal_type == Variant::STRING_NAME) {
GDScriptCodeGenerator::Address type_string_addr = codegen.add_constant(Variant::STRING);

codegen.generator->write_binary_operator(type_comp_addr_1, Variant::OP_EQUAL, p_type_addr, type_string_addr);
codegen.generator->write_binary_operator(type_comp_addr_2, Variant::OP_EQUAL, literal_type_addr, type_string_name_addr);
codegen.generator->write_binary_operator(type_comp_addr_1, Variant::OP_AND, type_comp_addr_1, type_comp_addr_2);
codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_OR, type_equality_addr, type_comp_addr_1);
// Check String <-> StringName type equality.
GDScriptCodeGenerator::Address tmp_comp_addr = codegen.add_temporary(equality_type);

codegen.generator->write_binary_operator(type_comp_addr_1, Variant::OP_EQUAL, p_type_addr, type_string_name_addr);
codegen.generator->write_binary_operator(type_comp_addr_2, Variant::OP_EQUAL, literal_type_addr, type_string_addr);
codegen.generator->write_binary_operator(type_comp_addr_1, Variant::OP_AND, type_comp_addr_1, type_comp_addr_2);
codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_OR, type_equality_addr, type_comp_addr_1);
codegen.generator->write_binary_operator(tmp_comp_addr, Variant::OP_EQUAL, p_type_addr, type_string_addr);
codegen.generator->write_binary_operator(type_equality_addr, Variant::OP_OR, type_equality_addr, tmp_comp_addr);

codegen.generator->pop_temporary(); // Remove type_comp_addr_2 from stack.
codegen.generator->pop_temporary(); // Remove type_comp_addr_1 from stack.
codegen.generator->pop_temporary(); // Remove tmp_comp_addr from stack.
}

codegen.generator->write_and_left_operand(type_equality_addr);

Expand Down Expand Up @@ -1349,9 +1352,22 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
} else if (!p_is_first) {
codegen.generator->write_or_left_operand(p_previous_test);
}

GDScriptCodeGenerator::Address type_string_addr = codegen.add_constant(Variant::STRING);
GDScriptCodeGenerator::Address type_stringname_addr = codegen.add_constant(Variant::STRING_NAME);

// Equality is always a boolean.
GDScriptDataType equality_type;
equality_type.has_type = true;
equality_type.kind = GDScriptDataType::BUILTIN;
equality_type.builtin_type = Variant::BOOL;

// Create the result temps first since it's the last to go away.
GDScriptCodeGenerator::Address result_addr = codegen.add_temporary();
GDScriptCodeGenerator::Address equality_test_addr = codegen.add_temporary();
GDScriptCodeGenerator::Address result_addr = codegen.add_temporary(equality_type);
GDScriptCodeGenerator::Address equality_test_addr = codegen.add_temporary(equality_type);
GDScriptCodeGenerator::Address stringy_comp_addr = codegen.add_temporary(equality_type);
GDScriptCodeGenerator::Address stringy_comp_addr_2 = codegen.add_temporary(equality_type);
GDScriptCodeGenerator::Address expr_type_addr = codegen.add_temporary();

// Evaluate expression.
GDScriptCodeGenerator::Address expr_addr;
Expand All @@ -1363,10 +1379,27 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
// Evaluate expression type.
Vector<GDScriptCodeGenerator::Address> typeof_args;
typeof_args.push_back(expr_addr);
codegen.generator->write_call_utility(result_addr, "typeof", typeof_args);
codegen.generator->write_call_utility(expr_type_addr, "typeof", typeof_args);

// Check type equality.
codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, result_addr);
codegen.generator->write_binary_operator(result_addr, Variant::OP_EQUAL, p_type_addr, expr_type_addr);

// Check for String <-> StringName comparison.
codegen.generator->write_binary_operator(stringy_comp_addr, Variant::OP_EQUAL, p_type_addr, type_string_addr);
codegen.generator->write_binary_operator(stringy_comp_addr_2, Variant::OP_EQUAL, expr_type_addr, type_stringname_addr);
codegen.generator->write_binary_operator(stringy_comp_addr, Variant::OP_AND, stringy_comp_addr, stringy_comp_addr_2);
codegen.generator->write_binary_operator(result_addr, Variant::OP_OR, result_addr, stringy_comp_addr);

// Check for StringName <-> String comparison.
codegen.generator->write_binary_operator(stringy_comp_addr, Variant::OP_EQUAL, p_type_addr, type_stringname_addr);
codegen.generator->write_binary_operator(stringy_comp_addr_2, Variant::OP_EQUAL, expr_type_addr, type_string_addr);
codegen.generator->write_binary_operator(stringy_comp_addr, Variant::OP_AND, stringy_comp_addr, stringy_comp_addr_2);
codegen.generator->write_binary_operator(result_addr, Variant::OP_OR, result_addr, stringy_comp_addr);

codegen.generator->pop_temporary(); // Remove expr_type_addr from stack.
codegen.generator->pop_temporary(); // Remove stringy_comp_addr_2 from stack.
codegen.generator->pop_temporary(); // Remove stringy_comp_addr from stack.

codegen.generator->write_and_left_operand(result_addr);

// Check value equality.
Expand All @@ -1380,7 +1413,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &c
if (expr_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
codegen.generator->pop_temporary(); // Remove type equality temporary.
codegen.generator->pop_temporary(); // Remove equality_test_addr from stack.

// If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
if (p_is_nested) {
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# https://github.com/godotengine/godot/issues/64171
# https://github.com/godotengine/godot/issues/60145

var s = "abc"
var sn = &"abc"

func test():
print("Compare ==: ", "abc" == &"abc")
Expand All @@ -9,3 +13,27 @@ func test():
print("Concat: ", "abc" + &"def")
print("Concat: ", &"abc" + "def")
print("Concat: ", &"abc" + &"def")

match "abc":
&"abc":
print("String matched StringName literal")
_:
print("no Match")

match &"abc":
"abc":
print("StringName matched String literal")
_:
print("no Match")

match "abc":
sn:
print("String matched StringName")
_:
print("no match")

match &"abc":
s:
print("StringName matched String")
_:
print("no match")
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ Compare !=: false
Concat: abcdef
Concat: abcdef
Concat: abcdef
String matched StringName literal
StringName matched String literal
String matched StringName
StringName matched String