| 590 | } |
| 591 | |
| 592 | void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) { |
| 593 | bool valid = HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand); |
| 594 | |
| 595 | // Avoid validated evaluator for modulo and division when operands are int or integer vector, since there's no check for division by zero. |
| 596 | if (valid && (p_operator == Variant::OP_DIVIDE || p_operator == Variant::OP_MODULE)) { |
| 597 | switch (p_left_operand.type.builtin_type) { |
| 598 | case Variant::INT: |
| 599 | // Cannot use modulo between int / float, we should raise an error later in GDScript |
| 600 | valid = p_right_operand.type.builtin_type != Variant::INT && p_operator == Variant::OP_DIVIDE; |
| 601 | break; |
| 602 | case Variant::VECTOR2I: |
| 603 | case Variant::VECTOR3I: |
| 604 | case Variant::VECTOR4I: |
| 605 | valid = p_right_operand.type.builtin_type != Variant::INT && p_right_operand.type.builtin_type != p_left_operand.type.builtin_type; |
| 606 | break; |
| 607 | default: |
| 608 | break; |
| 609 | } |
| 610 | } |
| 611 | |
| 612 | if (valid) { |
| 613 | if (p_target.mode == Address::TEMPORARY) { |
| 614 | Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type); |
| 615 | Variant::Type temp_type = temporaries[p_target.address].type; |
| 616 | if (result_type != temp_type) { |
| 617 | write_type_adjust(p_target, result_type); |
| 618 | } |
| 619 | } |
| 620 | |
| 621 | // Gather specific operator. |
| 622 | Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type); |
| 623 | |
| 624 | append_opcode(GDScriptFunction::OPCODE_OPERATOR_VALIDATED); |
| 625 | append(p_left_operand); |
| 626 | append(p_right_operand); |
| 627 | append(p_target); |
| 628 | append(op_func); |
| 629 | #ifdef DEBUG_ENABLED |
| 630 | add_debug_name(operator_names, get_operation_pos(op_func), Variant::get_operator_name(p_operator)); |
| 631 | #endif |
| 632 | return; |
| 633 | } |
| 634 | |
| 635 | // No specific types, perform variant evaluation. |
| 636 | append_opcode(GDScriptFunction::OPCODE_OPERATOR); |
| 637 | append(p_left_operand); |
| 638 | append(p_right_operand); |
| 639 | append(p_target); |
| 640 | append(p_operator); |
| 641 | append(0); // Signature storage. |
| 642 | append(0); // Return type storage. |
| 643 | constexpr int _pointer_size = sizeof(Variant::ValidatedOperatorEvaluator) / sizeof(*(opcodes.ptr())); |
| 644 | for (int i = 0; i < _pointer_size; i++) { |
| 645 | append(0); // Space for function pointer. |
| 646 | } |
| 647 | } |
| 648 | |
| 649 | void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) { |
no test coverage detected