GDScript: Add typed iterate instructions

This commit is contained in:
George Marques 2020-10-07 09:36:48 -03:00
parent 52ab64db69
commit e0dca3c6b6
No known key found for this signature in database
GPG Key ID: 046BD46A3201E43D
4 changed files with 944 additions and 89 deletions

View File

@ -864,8 +864,95 @@ void GDScriptByteCodeGenerator::write_for(const Address &p_variable, const Addre
append(container_pos);
append(p_list);
GDScriptFunction::Opcode begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN;
GDScriptFunction::Opcode iterate_opcode = GDScriptFunction::OPCODE_ITERATE;
if (p_list.type.has_type) {
if (p_list.type.kind == GDScriptDataType::BUILTIN) {
switch (p_list.type.builtin_type) {
case Variant::INT:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_INT;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_INT;
break;
case Variant::FLOAT:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_FLOAT;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_FLOAT;
break;
case Variant::VECTOR2:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR2;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR2;
break;
case Variant::VECTOR2I:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR2I;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR2I;
break;
case Variant::VECTOR3:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR3;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR3;
break;
case Variant::VECTOR3I:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR3I;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR3I;
break;
case Variant::STRING:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_STRING;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_STRING;
break;
case Variant::DICTIONARY:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_DICTIONARY;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_DICTIONARY;
break;
case Variant::ARRAY:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_ARRAY;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_ARRAY;
break;
case Variant::PACKED_BYTE_ARRAY:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_BYTE_ARRAY;
break;
case Variant::PACKED_INT32_ARRAY:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_INT32_ARRAY;
break;
case Variant::PACKED_INT64_ARRAY:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_INT64_ARRAY;
break;
case Variant::PACKED_FLOAT32_ARRAY:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_FLOAT32_ARRAY;
break;
case Variant::PACKED_FLOAT64_ARRAY:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_FLOAT64_ARRAY;
break;
case Variant::PACKED_STRING_ARRAY:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_STRING_ARRAY;
break;
case Variant::PACKED_VECTOR2_ARRAY:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR2_ARRAY;
break;
case Variant::PACKED_VECTOR3_ARRAY:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR3_ARRAY;
break;
case Variant::PACKED_COLOR_ARRAY:
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_COLOR_ARRAY;
break;
default:
break;
}
} else {
begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_OBJECT;
iterate_opcode = GDScriptFunction::OPCODE_ITERATE_OBJECT;
}
}
// Begin loop.
append(GDScriptFunction::OPCODE_ITERATE_BEGIN, 3);
append(begin_opcode, 3);
append(counter_pos);
append(container_pos);
append(p_variable);
@ -877,7 +964,7 @@ void GDScriptByteCodeGenerator::write_for(const Address &p_variable, const Addre
// Next iteration.
int continue_addr = opcodes.size();
continue_addrs.push_back(continue_addr);
append(GDScriptFunction::OPCODE_ITERATE, 3);
append(iterate_opcode, 3);
append(counter_pos);
append(container_pos);
append(p_variable);

View File

@ -674,6 +674,58 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 2;
} break;
#define DISASSEMBLE_ITERATE(m_type) \
case OPCODE_ITERATE_##m_type: { \
text += "for-loop (typed "; \
text += #m_type; \
text += ") "; \
text += DADDR(3); \
text += " in "; \
text += DADDR(2); \
text += " counter "; \
text += DADDR(1); \
text += " end "; \
text += itos(_code_ptr[ip + 4]); \
incr += 5; \
} break
#define DISASSEMBLE_ITERATE_BEGIN(m_type) \
case OPCODE_ITERATE_BEGIN_##m_type: { \
text += "for-init (typed "; \
text += #m_type; \
text += ") "; \
text += DADDR(3); \
text += " in "; \
text += DADDR(2); \
text += " counter "; \
text += DADDR(1); \
text += " end "; \
text += itos(_code_ptr[ip + 4]); \
incr += 5; \
} break
#define DISASSEMBLE_ITERATE_TYPES(m_macro) \
m_macro(INT); \
m_macro(FLOAT); \
m_macro(VECTOR2); \
m_macro(VECTOR2I); \
m_macro(VECTOR3); \
m_macro(VECTOR3I); \
m_macro(STRING); \
m_macro(DICTIONARY); \
m_macro(ARRAY); \
m_macro(PACKED_BYTE_ARRAY); \
m_macro(PACKED_INT32_ARRAY); \
m_macro(PACKED_INT64_ARRAY); \
m_macro(PACKED_FLOAT32_ARRAY); \
m_macro(PACKED_FLOAT64_ARRAY); \
m_macro(PACKED_STRING_ARRAY); \
m_macro(PACKED_VECTOR2_ARRAY); \
m_macro(PACKED_VECTOR3_ARRAY); \
m_macro(PACKED_COLOR_ARRAY); \
m_macro(OBJECT)
case OPCODE_ITERATE_BEGIN: {
text += "for-init ";
text += DADDR(3);
@ -686,6 +738,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 5;
} break;
DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE_BEGIN);
case OPCODE_ITERATE: {
text += "for-loop ";
text += DADDR(2);
@ -698,6 +751,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 5;
} break;
DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE);
case OPCODE_LINE: {
int line = _code_ptr[ip + 1] - 1;
if (line >= 0 && line < p_code_lines.size()) {

View File

@ -238,7 +238,45 @@ public:
OPCODE_JUMP_TO_DEF_ARGUMENT,
OPCODE_RETURN,
OPCODE_ITERATE_BEGIN,
OPCODE_ITERATE_BEGIN_INT,
OPCODE_ITERATE_BEGIN_FLOAT,
OPCODE_ITERATE_BEGIN_VECTOR2,
OPCODE_ITERATE_BEGIN_VECTOR2I,
OPCODE_ITERATE_BEGIN_VECTOR3,
OPCODE_ITERATE_BEGIN_VECTOR3I,
OPCODE_ITERATE_BEGIN_STRING,
OPCODE_ITERATE_BEGIN_DICTIONARY,
OPCODE_ITERATE_BEGIN_ARRAY,
OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY,
OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY,
OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY,
OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY,
OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY,
OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY,
OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY,
OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY,
OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY,
OPCODE_ITERATE_BEGIN_OBJECT,
OPCODE_ITERATE,
OPCODE_ITERATE_INT,
OPCODE_ITERATE_FLOAT,
OPCODE_ITERATE_VECTOR2,
OPCODE_ITERATE_VECTOR2I,
OPCODE_ITERATE_VECTOR3,
OPCODE_ITERATE_VECTOR3I,
OPCODE_ITERATE_STRING,
OPCODE_ITERATE_DICTIONARY,
OPCODE_ITERATE_ARRAY,
OPCODE_ITERATE_PACKED_BYTE_ARRAY,
OPCODE_ITERATE_PACKED_INT32_ARRAY,
OPCODE_ITERATE_PACKED_INT64_ARRAY,
OPCODE_ITERATE_PACKED_FLOAT32_ARRAY,
OPCODE_ITERATE_PACKED_FLOAT64_ARRAY,
OPCODE_ITERATE_PACKED_STRING_ARRAY,
OPCODE_ITERATE_PACKED_VECTOR2_ARRAY,
OPCODE_ITERATE_PACKED_VECTOR3_ARRAY,
OPCODE_ITERATE_PACKED_COLOR_ARRAY,
OPCODE_ITERATE_OBJECT,
OPCODE_ASSERT,
OPCODE_BREAKPOINT,
OPCODE_LINE,

View File

@ -30,6 +30,7 @@
#include "gdscript_function.h"
#include "core/core_string_names.h"
#include "core/os/os.h"
#include "gdscript.h"
#include "gdscript_functions.h"
@ -185,93 +186,131 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
}
#if defined(__GNUC__)
#define OPCODES_TABLE \
static const void *switch_table_ops[] = { \
&&OPCODE_OPERATOR, \
&&OPCODE_OPERATOR_VALIDATED, \
&&OPCODE_EXTENDS_TEST, \
&&OPCODE_IS_BUILTIN, \
&&OPCODE_SET_KEYED, \
&&OPCODE_SET_KEYED_VALIDATED, \
&&OPCODE_SET_INDEXED_VALIDATED, \
&&OPCODE_GET_KEYED, \
&&OPCODE_GET_KEYED_VALIDATED, \
&&OPCODE_GET_INDEXED_VALIDATED, \
&&OPCODE_SET_NAMED, \
&&OPCODE_SET_NAMED_VALIDATED, \
&&OPCODE_GET_NAMED, \
&&OPCODE_GET_NAMED_VALIDATED, \
&&OPCODE_SET_MEMBER, \
&&OPCODE_GET_MEMBER, \
&&OPCODE_ASSIGN, \
&&OPCODE_ASSIGN_TRUE, \
&&OPCODE_ASSIGN_FALSE, \
&&OPCODE_ASSIGN_TYPED_BUILTIN, \
&&OPCODE_ASSIGN_TYPED_NATIVE, \
&&OPCODE_ASSIGN_TYPED_SCRIPT, \
&&OPCODE_CAST_TO_BUILTIN, \
&&OPCODE_CAST_TO_NATIVE, \
&&OPCODE_CAST_TO_SCRIPT, \
&&OPCODE_CONSTRUCT, \
&&OPCODE_CONSTRUCT_ARRAY, \
&&OPCODE_CONSTRUCT_DICTIONARY, \
&&OPCODE_CALL, \
&&OPCODE_CALL_RETURN, \
&&OPCODE_CALL_ASYNC, \
&&OPCODE_CALL_BUILT_IN, \
&&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
&&OPCODE_CALL_SELF_BASE, \
&&OPCODE_CALL_METHOD_BIND, \
&&OPCODE_CALL_METHOD_BIND_RET, \
&&OPCODE_CALL_PTRCALL_NO_RETURN, \
&&OPCODE_CALL_PTRCALL_BOOL, \
&&OPCODE_CALL_PTRCALL_INT, \
&&OPCODE_CALL_PTRCALL_FLOAT, \
&&OPCODE_CALL_PTRCALL_STRING, \
&&OPCODE_CALL_PTRCALL_VECTOR2, \
&&OPCODE_CALL_PTRCALL_VECTOR2I, \
&&OPCODE_CALL_PTRCALL_RECT2, \
&&OPCODE_CALL_PTRCALL_RECT2I, \
&&OPCODE_CALL_PTRCALL_VECTOR3, \
&&OPCODE_CALL_PTRCALL_VECTOR3I, \
&&OPCODE_CALL_PTRCALL_TRANSFORM2D, \
&&OPCODE_CALL_PTRCALL_PLANE, \
&&OPCODE_CALL_PTRCALL_QUAT, \
&&OPCODE_CALL_PTRCALL_AABB, \
&&OPCODE_CALL_PTRCALL_BASIS, \
&&OPCODE_CALL_PTRCALL_TRANSFORM, \
&&OPCODE_CALL_PTRCALL_COLOR, \
&&OPCODE_CALL_PTRCALL_STRING_NAME, \
&&OPCODE_CALL_PTRCALL_NODE_PATH, \
&&OPCODE_CALL_PTRCALL_RID, \
&&OPCODE_CALL_PTRCALL_OBJECT, \
&&OPCODE_CALL_PTRCALL_CALLABLE, \
&&OPCODE_CALL_PTRCALL_SIGNAL, \
&&OPCODE_CALL_PTRCALL_DICTIONARY, \
&&OPCODE_CALL_PTRCALL_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_BYTE_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_INT32_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_INT64_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_FLOAT32_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_FLOAT64_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_STRING_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_VECTOR2_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_VECTOR3_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY, \
&&OPCODE_AWAIT, \
&&OPCODE_AWAIT_RESUME, \
&&OPCODE_JUMP, \
&&OPCODE_JUMP_IF, \
&&OPCODE_JUMP_IF_NOT, \
&&OPCODE_JUMP_TO_DEF_ARGUMENT, \
&&OPCODE_RETURN, \
&&OPCODE_ITERATE_BEGIN, \
&&OPCODE_ITERATE, \
&&OPCODE_ASSERT, \
&&OPCODE_BREAKPOINT, \
&&OPCODE_LINE, \
&&OPCODE_END \
}; \
#define OPCODES_TABLE \
static const void *switch_table_ops[] = { \
&&OPCODE_OPERATOR, \
&&OPCODE_OPERATOR_VALIDATED, \
&&OPCODE_EXTENDS_TEST, \
&&OPCODE_IS_BUILTIN, \
&&OPCODE_SET_KEYED, \
&&OPCODE_SET_KEYED_VALIDATED, \
&&OPCODE_SET_INDEXED_VALIDATED, \
&&OPCODE_GET_KEYED, \
&&OPCODE_GET_KEYED_VALIDATED, \
&&OPCODE_GET_INDEXED_VALIDATED, \
&&OPCODE_SET_NAMED, \
&&OPCODE_SET_NAMED_VALIDATED, \
&&OPCODE_GET_NAMED, \
&&OPCODE_GET_NAMED_VALIDATED, \
&&OPCODE_SET_MEMBER, \
&&OPCODE_GET_MEMBER, \
&&OPCODE_ASSIGN, \
&&OPCODE_ASSIGN_TRUE, \
&&OPCODE_ASSIGN_FALSE, \
&&OPCODE_ASSIGN_TYPED_BUILTIN, \
&&OPCODE_ASSIGN_TYPED_NATIVE, \
&&OPCODE_ASSIGN_TYPED_SCRIPT, \
&&OPCODE_CAST_TO_BUILTIN, \
&&OPCODE_CAST_TO_NATIVE, \
&&OPCODE_CAST_TO_SCRIPT, \
&&OPCODE_CONSTRUCT, \
&&OPCODE_CONSTRUCT_ARRAY, \
&&OPCODE_CONSTRUCT_DICTIONARY, \
&&OPCODE_CALL, \
&&OPCODE_CALL_RETURN, \
&&OPCODE_CALL_ASYNC, \
&&OPCODE_CALL_BUILT_IN, \
&&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
&&OPCODE_CALL_SELF_BASE, \
&&OPCODE_CALL_METHOD_BIND, \
&&OPCODE_CALL_METHOD_BIND_RET, \
&&OPCODE_CALL_PTRCALL_NO_RETURN, \
&&OPCODE_CALL_PTRCALL_BOOL, \
&&OPCODE_CALL_PTRCALL_INT, \
&&OPCODE_CALL_PTRCALL_FLOAT, \
&&OPCODE_CALL_PTRCALL_STRING, \
&&OPCODE_CALL_PTRCALL_VECTOR2, \
&&OPCODE_CALL_PTRCALL_VECTOR2I, \
&&OPCODE_CALL_PTRCALL_RECT2, \
&&OPCODE_CALL_PTRCALL_RECT2I, \
&&OPCODE_CALL_PTRCALL_VECTOR3, \
&&OPCODE_CALL_PTRCALL_VECTOR3I, \
&&OPCODE_CALL_PTRCALL_TRANSFORM2D, \
&&OPCODE_CALL_PTRCALL_PLANE, \
&&OPCODE_CALL_PTRCALL_QUAT, \
&&OPCODE_CALL_PTRCALL_AABB, \
&&OPCODE_CALL_PTRCALL_BASIS, \
&&OPCODE_CALL_PTRCALL_TRANSFORM, \
&&OPCODE_CALL_PTRCALL_COLOR, \
&&OPCODE_CALL_PTRCALL_STRING_NAME, \
&&OPCODE_CALL_PTRCALL_NODE_PATH, \
&&OPCODE_CALL_PTRCALL_RID, \
&&OPCODE_CALL_PTRCALL_OBJECT, \
&&OPCODE_CALL_PTRCALL_CALLABLE, \
&&OPCODE_CALL_PTRCALL_SIGNAL, \
&&OPCODE_CALL_PTRCALL_DICTIONARY, \
&&OPCODE_CALL_PTRCALL_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_BYTE_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_INT32_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_INT64_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_FLOAT32_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_FLOAT64_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_STRING_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_VECTOR2_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_VECTOR3_ARRAY, \
&&OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY, \
&&OPCODE_AWAIT, \
&&OPCODE_AWAIT_RESUME, \
&&OPCODE_JUMP, \
&&OPCODE_JUMP_IF, \
&&OPCODE_JUMP_IF_NOT, \
&&OPCODE_JUMP_TO_DEF_ARGUMENT, \
&&OPCODE_RETURN, \
&&OPCODE_ITERATE_BEGIN, \
&&OPCODE_ITERATE_BEGIN_INT, \
&&OPCODE_ITERATE_BEGIN_FLOAT, \
&&OPCODE_ITERATE_BEGIN_VECTOR2, \
&&OPCODE_ITERATE_BEGIN_VECTOR2I, \
&&OPCODE_ITERATE_BEGIN_VECTOR3, \
&&OPCODE_ITERATE_BEGIN_VECTOR3I, \
&&OPCODE_ITERATE_BEGIN_STRING, \
&&OPCODE_ITERATE_BEGIN_DICTIONARY, \
&&OPCODE_ITERATE_BEGIN_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY, \
&&OPCODE_ITERATE_BEGIN_OBJECT, \
&&OPCODE_ITERATE, \
&&OPCODE_ITERATE_INT, \
&&OPCODE_ITERATE_FLOAT, \
&&OPCODE_ITERATE_VECTOR2, \
&&OPCODE_ITERATE_VECTOR2I, \
&&OPCODE_ITERATE_VECTOR3, \
&&OPCODE_ITERATE_VECTOR3I, \
&&OPCODE_ITERATE_STRING, \
&&OPCODE_ITERATE_DICTIONARY, \
&&OPCODE_ITERATE_ARRAY, \
&&OPCODE_ITERATE_PACKED_BYTE_ARRAY, \
&&OPCODE_ITERATE_PACKED_INT32_ARRAY, \
&&OPCODE_ITERATE_PACKED_INT64_ARRAY, \
&&OPCODE_ITERATE_PACKED_FLOAT32_ARRAY, \
&&OPCODE_ITERATE_PACKED_FLOAT64_ARRAY, \
&&OPCODE_ITERATE_PACKED_STRING_ARRAY, \
&&OPCODE_ITERATE_PACKED_VECTOR2_ARRAY, \
&&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \
&&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
&&OPCODE_ITERATE_OBJECT, \
&&OPCODE_ASSERT, \
&&OPCODE_BREAKPOINT, \
&&OPCODE_LINE, \
&&OPCODE_END \
}; \
static_assert((sizeof(switch_table_ops) / sizeof(switch_table_ops[0]) == (OPCODE_END + 1)), "Opcodes in jump table aren't the same as opcodes in enum.");
#define OPCODE(m_op) \
@ -1979,6 +2018,344 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_BEGIN_INT) {
CHECK_SPACE(8); // Check space for iterate instruction too.
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
int64_t size = *VariantInternal::get_int(container);
VariantInternal::initialize(counter, Variant::INT);
*VariantInternal::get_int(counter) = 0;
if (size > 0) {
GET_INSTRUCTION_ARG(iterator, 2);
VariantInternal::initialize(iterator, Variant::INT);
*VariantInternal::get_int(iterator) = 0;
// Skip regular iterate.
ip += 5;
} else {
// Jump to end of loop.
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_BEGIN_FLOAT) {
CHECK_SPACE(8); // Check space for iterate instruction too.
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
double size = *VariantInternal::get_float(container);
VariantInternal::initialize(counter, Variant::FLOAT);
*VariantInternal::get_float(counter) = 0.0;
if (size > 0) {
GET_INSTRUCTION_ARG(iterator, 2);
VariantInternal::initialize(iterator, Variant::FLOAT);
*VariantInternal::get_float(iterator) = 0;
// Skip regular iterate.
ip += 5;
} else {
// Jump to end of loop.
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_BEGIN_VECTOR2) {
CHECK_SPACE(8); // Check space for iterate instruction too.
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
Vector2 *bounds = VariantInternal::get_vector2(container);
VariantInternal::initialize(counter, Variant::FLOAT);
*VariantInternal::get_float(counter) = bounds->x;
if (bounds->x < bounds->y) {
GET_INSTRUCTION_ARG(iterator, 2);
VariantInternal::initialize(iterator, Variant::FLOAT);
*VariantInternal::get_float(iterator) = bounds->x;
// Skip regular iterate.
ip += 5;
} else {
// Jump to end of loop.
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_BEGIN_VECTOR2I) {
CHECK_SPACE(8); // Check space for iterate instruction too.
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
Vector2i *bounds = VariantInternal::get_vector2i(container);
VariantInternal::initialize(counter, Variant::FLOAT);
*VariantInternal::get_int(counter) = bounds->x;
if (bounds->x < bounds->y) {
GET_INSTRUCTION_ARG(iterator, 2);
VariantInternal::initialize(iterator, Variant::INT);
*VariantInternal::get_int(iterator) = bounds->x;
// Skip regular iterate.
ip += 5;
} else {
// Jump to end of loop.
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_BEGIN_VECTOR3) {
CHECK_SPACE(8); // Check space for iterate instruction too.
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
Vector3 *bounds = VariantInternal::get_vector3(container);
double from = bounds->x;
double to = bounds->y;
double step = bounds->z;
VariantInternal::initialize(counter, Variant::FLOAT);
*VariantInternal::get_float(counter) = from;
bool do_continue = from == to ? false : (from < to ? step > 0 : step < 0);
if (do_continue) {
GET_INSTRUCTION_ARG(iterator, 2);
VariantInternal::initialize(iterator, Variant::FLOAT);
*VariantInternal::get_float(iterator) = from;
// Skip regular iterate.
ip += 5;
} else {
// Jump to end of loop.
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_BEGIN_VECTOR3I) {
CHECK_SPACE(8); // Check space for iterate instruction too.
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
Vector3i *bounds = VariantInternal::get_vector3i(container);
int64_t from = bounds->x;
int64_t to = bounds->y;
int64_t step = bounds->z;
VariantInternal::initialize(counter, Variant::INT);
*VariantInternal::get_int(counter) = from;
bool do_continue = from == to ? false : (from < to ? step > 0 : step < 0);
if (do_continue) {
GET_INSTRUCTION_ARG(iterator, 2);
VariantInternal::initialize(iterator, Variant::INT);
*VariantInternal::get_int(iterator) = from;
// Skip regular iterate.
ip += 5;
} else {
// Jump to end of loop.
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_BEGIN_STRING) {
CHECK_SPACE(8); // Check space for iterate instruction too.
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
String *str = VariantInternal::get_string(container);
VariantInternal::initialize(counter, Variant::INT);
*VariantInternal::get_int(counter) = 0;
if (!str->empty()) {
GET_INSTRUCTION_ARG(iterator, 2);
VariantInternal::initialize(iterator, Variant::STRING);
*VariantInternal::get_string(iterator) = str->substr(0, 1);
// Skip regular iterate.
ip += 5;
} else {
// Jump to end of loop.
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_BEGIN_DICTIONARY) {
CHECK_SPACE(8); // Check space for iterate instruction too.
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
Dictionary *dict = VariantInternal::get_dictionary(container);
const Variant *next = dict->next(nullptr);
*counter = *next;
if (!dict->empty()) {
GET_INSTRUCTION_ARG(iterator, 2);
*iterator = *next;
// Skip regular iterate.
ip += 5;
} else {
// Jump to end of loop.
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_BEGIN_ARRAY) {
CHECK_SPACE(8); // Check space for iterate instruction too.
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
Array *array = VariantInternal::get_array(container);
VariantInternal::initialize(counter, Variant::INT);
*VariantInternal::get_int(counter) = 0;
if (!array->empty()) {
GET_INSTRUCTION_ARG(iterator, 2);
*iterator = array->get(0);
// Skip regular iterate.
ip += 5;
} else {
// Jump to end of loop.
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
}
}
DISPATCH_OPCODE;
#define OPCODE_ITERATE_BEGIN_PACKED_ARRAY(m_var_type, m_elem_type, m_get_func, m_var_ret_type, m_ret_type, m_ret_get_func) \
OPCODE(OPCODE_ITERATE_BEGIN_PACKED_##m_var_type##_ARRAY) { \
CHECK_SPACE(8); \
GET_INSTRUCTION_ARG(counter, 0); \
GET_INSTRUCTION_ARG(container, 1); \
Vector<m_elem_type> *array = VariantInternal::m_get_func(container); \
VariantInternal::initialize(counter, Variant::INT); \
*VariantInternal::get_int(counter) = 0; \
if (!array->empty()) { \
GET_INSTRUCTION_ARG(iterator, 2); \
VariantInternal::initialize(iterator, Variant::m_var_ret_type); \
m_ret_type *it = VariantInternal::m_ret_get_func(iterator); \
*it = array->get(0); \
ip += 5; \
} else { \
int jumpto = _code_ptr[ip + 4]; \
GD_ERR_BREAK(jumpto<0 || jumpto> _code_size); \
ip = jumpto; \
} \
} \
DISPATCH_OPCODE
OPCODE_ITERATE_BEGIN_PACKED_ARRAY(BYTE, uint8_t, get_byte_array, INT, int64_t, get_int);
OPCODE_ITERATE_BEGIN_PACKED_ARRAY(INT32, int32_t, get_int32_array, INT, int64_t, get_int);
OPCODE_ITERATE_BEGIN_PACKED_ARRAY(INT64, int64_t, get_int64_array, INT, int64_t, get_int);
OPCODE_ITERATE_BEGIN_PACKED_ARRAY(FLOAT32, float, get_float32_array, FLOAT, double, get_float);
OPCODE_ITERATE_BEGIN_PACKED_ARRAY(FLOAT64, double, get_float64_array, FLOAT, double, get_float);
OPCODE_ITERATE_BEGIN_PACKED_ARRAY(STRING, String, get_string_array, STRING, String, get_string);
OPCODE_ITERATE_BEGIN_PACKED_ARRAY(VECTOR2, Vector2, get_vector2_array, VECTOR2, Vector2, get_vector2);
OPCODE_ITERATE_BEGIN_PACKED_ARRAY(VECTOR3, Vector3, get_vector3_array, VECTOR3, Vector3, get_vector3);
OPCODE_ITERATE_BEGIN_PACKED_ARRAY(COLOR, Color, get_color_array, COLOR, Color, get_color);
OPCODE(OPCODE_ITERATE_BEGIN_OBJECT) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
#ifdef DEBUG_ENABLED
bool freed = false;
Object *obj = container->get_validated_object_with_check(freed);
if (freed) {
err_text = "Trying to iterate on a previously freed object.";
OPCODE_BREAK;
} else if (!obj) {
err_text = "Trying to iterate on a null value.";
OPCODE_BREAK;
}
#else
Object *obj = *VariantInternal::get_object(container);
#endif
Array ref;
ref.push_back(*counter);
Variant vref;
VariantInternal::initialize(&vref, Variant::ARRAY);
*VariantInternal::get_array(&vref) = ref;
Variant **args = instruction_args; // Overriding an instruction argument, but we don't need access to that anymore.
args[0] = &vref;
Callable::CallError ce;
Variant has_next = obj->call(CoreStringNames::get_singleton()->_iter_init, (const Variant **)args, 1, ce);
#ifdef DEBUG_ENABLED
if (ce.error != Callable::CallError::CALL_OK) {
err_text = vformat(R"(There was an error calling "_iter_next" on iterator object of type %s.)", *container);
OPCODE_BREAK;
}
#endif
if (!has_next.booleanize()) {
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
} else {
GET_INSTRUCTION_ARG(iterator, 2);
*iterator = obj->call(CoreStringNames::get_singleton()->_iter_get, (const Variant **)args, 1, ce);
#ifdef DEBUG_ENABLED
if (ce.error != Callable::CallError::CALL_OK) {
err_text = vformat(R"(There was an error calling "_iter_get" on iterator object of type %s.)", *container);
OPCODE_BREAK;
}
#endif
ip += 5; // Loop again.
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE) {
CHECK_SPACE(4);
@ -2011,6 +2388,305 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_INT) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
int64_t size = *VariantInternal::get_int(container);
int64_t *count = VariantInternal::get_int(counter);
(*count)++;
if (*count >= size) {
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
} else {
GET_INSTRUCTION_ARG(iterator, 2);
*VariantInternal::get_int(iterator) = *count;
ip += 5; // Loop again.
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_FLOAT) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
double size = *VariantInternal::get_float(container);
double *count = VariantInternal::get_float(counter);
(*count)++;
if (*count >= size) {
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
} else {
GET_INSTRUCTION_ARG(iterator, 2);
*VariantInternal::get_float(iterator) = *count;
ip += 5; // Loop again.
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_VECTOR2) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
const Vector2 *bounds = VariantInternal::get_vector2((const Variant *)container);
double *count = VariantInternal::get_float(counter);
(*count)++;
if (*count >= bounds->y) {
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
} else {
GET_INSTRUCTION_ARG(iterator, 2);
*VariantInternal::get_float(iterator) = *count;
ip += 5; // Loop again.
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_VECTOR2I) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
const Vector2i *bounds = VariantInternal::get_vector2i((const Variant *)container);
int64_t *count = VariantInternal::get_int(counter);
(*count)++;
if (*count >= bounds->y) {
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
} else {
GET_INSTRUCTION_ARG(iterator, 2);
*VariantInternal::get_int(iterator) = *count;
ip += 5; // Loop again.
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_VECTOR3) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
const Vector3 *bounds = VariantInternal::get_vector3((const Variant *)container);
double *count = VariantInternal::get_float(counter);
*count += bounds->z;
if ((bounds->z < 0 && *count <= bounds->y) || (bounds->z > 0 && *count >= bounds->y)) {
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
} else {
GET_INSTRUCTION_ARG(iterator, 2);
*VariantInternal::get_float(iterator) = *count;
ip += 5; // Loop again.
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_VECTOR3I) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
const Vector3i *bounds = VariantInternal::get_vector3i((const Variant *)container);
int64_t *count = VariantInternal::get_int(counter);
*count += bounds->z;
if ((bounds->z < 0 && *count <= bounds->y) || (bounds->z > 0 && *count >= bounds->y)) {
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
} else {
GET_INSTRUCTION_ARG(iterator, 2);
*VariantInternal::get_int(iterator) = *count;
ip += 5; // Loop again.
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_STRING) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
const String *str = VariantInternal::get_string((const Variant *)container);
int64_t *idx = VariantInternal::get_int(counter);
(*idx)++;
if (*idx >= str->length()) {
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
} else {
GET_INSTRUCTION_ARG(iterator, 2);
*VariantInternal::get_string(iterator) = str->substr(*idx, 1);
ip += 5; // Loop again.
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_DICTIONARY) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
const Dictionary *dict = VariantInternal::get_dictionary((const Variant *)container);
const Variant *next = dict->next(counter);
if (!next) {
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
} else {
GET_INSTRUCTION_ARG(iterator, 2);
*counter = *next;
*iterator = *next;
ip += 5; // Loop again.
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ITERATE_ARRAY) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
const Array *array = VariantInternal::get_array((const Variant *)container);
int64_t *idx = VariantInternal::get_int(counter);
(*idx)++;
if (*idx >= array->size()) {
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
} else {
GET_INSTRUCTION_ARG(iterator, 2);
*iterator = array->get(*idx);
ip += 5; // Loop again.
}
}
DISPATCH_OPCODE;
#define OPCODE_ITERATE_PACKED_ARRAY(m_var_type, m_elem_type, m_get_func, m_ret_get_func) \
OPCODE(OPCODE_ITERATE_PACKED_##m_var_type##_ARRAY) { \
CHECK_SPACE(4); \
GET_INSTRUCTION_ARG(counter, 0); \
GET_INSTRUCTION_ARG(container, 1); \
const Vector<m_elem_type> *array = VariantInternal::m_get_func((const Variant *)container); \
int64_t *idx = VariantInternal::get_int(counter); \
(*idx)++; \
if (*idx >= array->size()) { \
int jumpto = _code_ptr[ip + 4]; \
GD_ERR_BREAK(jumpto<0 || jumpto> _code_size); \
ip = jumpto; \
} else { \
GET_INSTRUCTION_ARG(iterator, 2); \
*VariantInternal::m_ret_get_func(iterator) = array->get(*idx); \
ip += 5; \
} \
} \
DISPATCH_OPCODE
OPCODE_ITERATE_PACKED_ARRAY(BYTE, uint8_t, get_byte_array, get_int);
OPCODE_ITERATE_PACKED_ARRAY(INT32, int32_t, get_int32_array, get_int);
OPCODE_ITERATE_PACKED_ARRAY(INT64, int64_t, get_int64_array, get_int);
OPCODE_ITERATE_PACKED_ARRAY(FLOAT32, float, get_float32_array, get_float);
OPCODE_ITERATE_PACKED_ARRAY(FLOAT64, double, get_float64_array, get_float);
OPCODE_ITERATE_PACKED_ARRAY(STRING, String, get_string_array, get_string);
OPCODE_ITERATE_PACKED_ARRAY(VECTOR2, Vector2, get_vector2_array, get_vector2);
OPCODE_ITERATE_PACKED_ARRAY(VECTOR3, Vector3, get_vector3_array, get_vector3);
OPCODE_ITERATE_PACKED_ARRAY(COLOR, Color, get_color_array, get_color);
OPCODE(OPCODE_ITERATE_OBJECT) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(counter, 0);
GET_INSTRUCTION_ARG(container, 1);
#ifdef DEBUG_ENABLED
bool freed = false;
Object *obj = container->get_validated_object_with_check(freed);
if (freed) {
err_text = "Trying to iterate on a previously freed object.";
OPCODE_BREAK;
} else if (!obj) {
err_text = "Trying to iterate on a null value.";
OPCODE_BREAK;
}
#else
Object *obj = *VariantInternal::get_object(container);
#endif
Array ref;
ref.push_back(*counter);
Variant vref;
VariantInternal::initialize(&vref, Variant::ARRAY);
*VariantInternal::get_array(&vref) = ref;
Variant **args = instruction_args; // Overriding an instruction argument, but we don't need access to that anymore.
args[0] = &vref;
Callable::CallError ce;
Variant has_next = obj->call(CoreStringNames::get_singleton()->_iter_next, (const Variant **)args, 1, ce);
#ifdef DEBUG_ENABLED
if (ce.error != Callable::CallError::CALL_OK) {
err_text = vformat(R"(There was an error calling "_iter_next" on iterator object of type %s.)", *container);
OPCODE_BREAK;
}
#endif
if (!has_next.booleanize()) {
int jumpto = _code_ptr[ip + 4];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
} else {
GET_INSTRUCTION_ARG(iterator, 2);
*iterator = obj->call(CoreStringNames::get_singleton()->_iter_get, (const Variant **)args, 1, ce);
#ifdef DEBUG_ENABLED
if (ce.error != Callable::CallError::CALL_OK) {
err_text = vformat(R"(There was an error calling "_iter_get" on iterator object of type %s.)", *container);
OPCODE_BREAK;
}
#endif
ip += 5; // Loop again.
}
}
DISPATCH_OPCODE;
OPCODE(OPCODE_ASSERT) {
CHECK_SPACE(3);