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

Add a const call mode to Object, Variant and Script. #62468

Merged
merged 1 commit into from
Jun 27, 2022
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
1 change: 1 addition & 0 deletions core/core_constants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_DIR);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RESOURCE_TYPE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MULTILINE_TEXT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXPRESSION);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PLACEHOLDER_TEXT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSY);
Expand Down
2 changes: 1 addition & 1 deletion core/extension/gdnative_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ typedef enum {
GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, /* expected is number of arguments */
GDNATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS, /* expected is number of arguments */
GDNATIVE_CALL_ERROR_INSTANCE_IS_NULL,

GDNATIVE_CALL_ERROR_METHOD_NOT_CONST, /* used for const call */
} GDNativeCallErrorType;

typedef struct {
Expand Down
38 changes: 21 additions & 17 deletions core/math/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1240,7 +1240,7 @@ bool Expression::_compile_expression() {
return false;
}

bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str) {
bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, bool p_const_calls_only, String &r_error_str) {
switch (p_node->type) {
case Expression::ENode::TYPE_INPUT: {
const Expression::InputNode *in = static_cast<const Expression::InputNode *>(p_node);
Expand All @@ -1266,15 +1266,15 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
const Expression::OperatorNode *op = static_cast<const Expression::OperatorNode *>(p_node);

Variant a;
bool ret = _execute(p_inputs, p_instance, op->nodes[0], a, r_error_str);
bool ret = _execute(p_inputs, p_instance, op->nodes[0], a, p_const_calls_only, r_error_str);
if (ret) {
return true;
}

Variant b;

if (op->nodes[1]) {
ret = _execute(p_inputs, p_instance, op->nodes[1], b, r_error_str);
ret = _execute(p_inputs, p_instance, op->nodes[1], b, p_const_calls_only, r_error_str);
if (ret) {
return true;
}
Expand All @@ -1292,14 +1292,14 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
const Expression::IndexNode *index = static_cast<const Expression::IndexNode *>(p_node);

Variant base;
bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str);
bool ret = _execute(p_inputs, p_instance, index->base, base, p_const_calls_only, r_error_str);
if (ret) {
return true;
}

Variant idx;

ret = _execute(p_inputs, p_instance, index->index, idx, r_error_str);
ret = _execute(p_inputs, p_instance, index->index, idx, p_const_calls_only, r_error_str);
if (ret) {
return true;
}
Expand All @@ -1316,7 +1316,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
const Expression::NamedIndexNode *index = static_cast<const Expression::NamedIndexNode *>(p_node);

Variant base;
bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str);
bool ret = _execute(p_inputs, p_instance, index->base, base, p_const_calls_only, r_error_str);
if (ret) {
return true;
}
Expand All @@ -1336,7 +1336,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
arr.resize(array->array.size());
for (int i = 0; i < array->array.size(); i++) {
Variant value;
bool ret = _execute(p_inputs, p_instance, array->array[i], value, r_error_str);
bool ret = _execute(p_inputs, p_instance, array->array[i], value, p_const_calls_only, r_error_str);

if (ret) {
return true;
Expand All @@ -1353,14 +1353,14 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
Dictionary d;
for (int i = 0; i < dictionary->dict.size(); i += 2) {
Variant key;
bool ret = _execute(p_inputs, p_instance, dictionary->dict[i + 0], key, r_error_str);
bool ret = _execute(p_inputs, p_instance, dictionary->dict[i + 0], key, p_const_calls_only, r_error_str);

if (ret) {
return true;
}

Variant value;
ret = _execute(p_inputs, p_instance, dictionary->dict[i + 1], value, r_error_str);
ret = _execute(p_inputs, p_instance, dictionary->dict[i + 1], value, p_const_calls_only, r_error_str);
if (ret) {
return true;
}
Expand All @@ -1380,7 +1380,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:

for (int i = 0; i < constructor->arguments.size(); i++) {
Variant value;
bool ret = _execute(p_inputs, p_instance, constructor->arguments[i], value, r_error_str);
bool ret = _execute(p_inputs, p_instance, constructor->arguments[i], value, p_const_calls_only, r_error_str);

if (ret) {
return true;
Expand Down Expand Up @@ -1408,7 +1408,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:

for (int i = 0; i < bifunc->arguments.size(); i++) {
Variant value;
bool ret = _execute(p_inputs, p_instance, bifunc->arguments[i], value, r_error_str);
bool ret = _execute(p_inputs, p_instance, bifunc->arguments[i], value, p_const_calls_only, r_error_str);
if (ret) {
return true;
}
Expand All @@ -1429,7 +1429,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
const Expression::CallNode *call = static_cast<const Expression::CallNode *>(p_node);

Variant base;
bool ret = _execute(p_inputs, p_instance, call->base, base, r_error_str);
bool ret = _execute(p_inputs, p_instance, call->base, base, p_const_calls_only, r_error_str);

if (ret) {
return true;
Expand All @@ -1442,7 +1442,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:

for (int i = 0; i < call->arguments.size(); i++) {
Variant value;
ret = _execute(p_inputs, p_instance, call->arguments[i], value, r_error_str);
ret = _execute(p_inputs, p_instance, call->arguments[i], value, p_const_calls_only, r_error_str);

if (ret) {
return true;
Expand All @@ -1452,7 +1452,11 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
}

Callable::CallError ce;
base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
if (p_const_calls_only) {
base.call_const(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
} else {
base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
}

if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = vformat(RTR("On call to '%s':"), String(call->method));
Expand Down Expand Up @@ -1491,13 +1495,13 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu
return OK;
}

Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) {
Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error, bool p_const_calls_only) {
ERR_FAIL_COND_V_MSG(error_set, Variant(), "There was previously a parse error: " + error_str + ".");

execution_error = false;
Variant output;
String error_txt;
bool err = _execute(p_inputs, p_base, root, output, error_txt);
bool err = _execute(p_inputs, p_base, root, output, p_const_calls_only, error_txt);
if (err) {
execution_error = true;
error_str = error_txt;
Expand All @@ -1517,7 +1521,7 @@ String Expression::get_error_text() const {

void Expression::_bind_methods() {
ClassDB::bind_method(D_METHOD("parse", "expression", "input_names"), &Expression::parse, DEFVAL(Vector<String>()));
ClassDB::bind_method(D_METHOD("execute", "inputs", "base_instance", "show_error"), &Expression::execute, DEFVAL(Array()), DEFVAL(Variant()), DEFVAL(true));
ClassDB::bind_method(D_METHOD("execute", "inputs", "base_instance", "show_error", "const_calls_only"), &Expression::execute, DEFVAL(Array()), DEFVAL(Variant()), DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("has_execute_failed"), &Expression::has_execute_failed);
ClassDB::bind_method(D_METHOD("get_error_text"), &Expression::get_error_text);
}
Expand Down
4 changes: 2 additions & 2 deletions core/math/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,14 +257,14 @@ class Expression : public RefCounted {
Vector<String> input_names;

bool execution_error = false;
bool _execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str);
bool _execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, bool p_const_calls_only, String &r_error_str);

protected:
static void _bind_methods();

public:
Error parse(const String &p_expression, const Vector<String> &p_input_names = Vector<String>());
Variant execute(Array p_inputs = Array(), Object *p_base = nullptr, bool p_show_error = true);
Variant execute(Array p_inputs = Array(), Object *p_base = nullptr, bool p_show_error = true, bool p_const_calls_only = false);
bool has_execute_failed() const;
String get_error_text() const;

Expand Down
49 changes: 49 additions & 0 deletions core/object/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,7 @@ Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
return ret;
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
}
Expand All @@ -688,6 +689,54 @@ Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_
return ret;
}

Variant Object::call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_OK;

if (p_method == CoreStringNames::get_singleton()->_free) {
// Free is not const, so fail.
r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST;
return Variant();
}

Variant ret;
OBJ_DEBUG_LOCK

if (script_instance) {
ret = script_instance->call_const(p_method, p_args, p_argcount, r_error);
//force jumptable
switch (r_error.error) {
case Callable::CallError::CALL_OK:
return ret;
case Callable::CallError::CALL_ERROR_INVALID_METHOD:
break;
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
break;
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
return ret;
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
}
}
}

//extension does not need this, because all methods are registered in MethodBind

MethodBind *method = ClassDB::get_method(get_class_name(), p_method);

if (method) {
if (!method->is_const()) {
r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST;
return ret;
}
ret = method->call(this, p_args, p_argcount, r_error);
} else {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
}

return ret;
}

void Object::notification(int p_notification, bool p_reversed) {
_notificationv(p_notification, p_reversed);

Expand Down
2 changes: 2 additions & 0 deletions core/object/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ enum PropertyHint {
PROPERTY_HINT_GLOBAL_DIR, ///< a directory path must be passed
PROPERTY_HINT_RESOURCE_TYPE, ///< a resource object type
PROPERTY_HINT_MULTILINE_TEXT, ///< used for string properties that can contain multiple lines
PROPERTY_HINT_EXPRESSION, ///< used for string properties that can contain multiple lines
PROPERTY_HINT_PLACEHOLDER_TEXT, ///< used to set a placeholder text for string properties
PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color
PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
Expand Down Expand Up @@ -759,6 +760,7 @@ class Object {
void get_method_list(List<MethodInfo> *p_list) const;
Variant callv(const StringName &p_method, const Array &p_args);
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
virtual Variant call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);

template <typename... VarArgs>
Variant call(const StringName &p_method, VarArgs... p_args) {
Expand Down
5 changes: 5 additions & 0 deletions core/object/script_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,11 @@ void ScriptServer::save_global_classes() {
}

////////////////////

Variant ScriptInstance::call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
return callp(p_method, p_args, p_argcount, r_error);
}

void ScriptInstance::get_property_state(List<Pair<StringName, Variant>> &state) {
List<PropertyInfo> pinfo;
get_property_list(&pinfo);
Expand Down
1 change: 1 addition & 0 deletions core/object/script_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ class ScriptInstance {
return callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), cerr);
}

virtual Variant call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); // implement if language supports const functions
virtual void notification(int p_notification) = 0;
virtual String to_string(bool *r_valid) {
if (r_valid) {
Expand Down
1 change: 1 addition & 0 deletions core/variant/callable.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class Callable {
CALL_ERROR_TOO_MANY_ARGUMENTS, // expected is number of arguments
CALL_ERROR_TOO_FEW_ARGUMENTS, // expected is number of arguments
CALL_ERROR_INSTANCE_IS_NULL,
CALL_ERROR_METHOD_NOT_CONST,
};
Error error = Error::CALL_OK;
int argument = 0;
Expand Down
2 changes: 2 additions & 0 deletions core/variant/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3395,6 +3395,8 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,
err_text = "Method not found.";
} else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
err_text = "Instance is null";
} else if (ce.error == Callable::CallError::CALL_ERROR_METHOD_NOT_CONST) {
err_text = "Method not const in const instance";
} else if (ce.error == Callable::CallError::CALL_OK) {
return "Call OK";
}
Expand Down
1 change: 1 addition & 0 deletions core/variant/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ class Variant {
return ret;
}

void call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
static void call_static(Variant::Type p_type, const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);

static String get_call_error_text(const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
Expand Down
36 changes: 36 additions & 0 deletions core/variant/variant_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,37 @@ void Variant::callp(const StringName &p_method, const Variant **p_args, int p_ar
#endif
r_ret = _get_obj().obj->callp(p_method, p_args, p_argcount, r_error);

} else {
r_error.error = Callable::CallError::CALL_OK;

const VariantBuiltInMethodInfo *imf = builtin_method_info[type].lookup_ptr(p_method);

if (!imf) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return;
}

imf->call(this, p_args, p_argcount, r_ret, imf->default_arguments, r_error);
}
}

void Variant::call_const(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
if (type == Variant::OBJECT) {
//call object
Object *obj = _get_obj().obj;
if (!obj) {
r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
return;
}
#ifdef DEBUG_ENABLED
if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
return;
}

#endif
r_ret = _get_obj().obj->call_const(p_method, p_args, p_argcount, r_error);

//else if (type==Variant::METHOD) {
} else {
r_error.error = Callable::CallError::CALL_OK;
Expand All @@ -1042,6 +1073,11 @@ void Variant::callp(const StringName &p_method, const Variant **p_args, int p_ar
return;
}

if (!imf->is_const) {
r_error.error = Callable::CallError::CALL_ERROR_METHOD_NOT_CONST;
return;
}

imf->call(this, p_args, p_argcount, r_ret, imf->default_arguments, r_error);
}
}
Expand Down
Loading