Add a const call mode to Object, Variant and Script.
For this to work safely (user not call queue_free or something in the expression), a const call mode was added to Object and Variant (and optionally Script). This mode ensures only const functions can be called, making it safe to use from the editor. Co-Authored-By: reduz <reduzio@gmail.com>
This commit is contained in:
parent
c41e4b10c3
commit
9ddebc0c22
23 changed files with 179 additions and 53 deletions
|
@ -588,6 +588,7 @@ void register_global_constants() {
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_DIR);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_DIR);
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RESOURCE_TYPE);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RESOURCE_TYPE);
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MULTILINE_TEXT);
|
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_PLACEHOLDER_TEXT);
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
|
||||||
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSY);
|
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSY);
|
||||||
|
|
|
@ -153,7 +153,7 @@ typedef enum {
|
||||||
GDNATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, /* expected is number of arguments */
|
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_TOO_FEW_ARGUMENTS, /* expected is number of arguments */
|
||||||
GDNATIVE_CALL_ERROR_INSTANCE_IS_NULL,
|
GDNATIVE_CALL_ERROR_INSTANCE_IS_NULL,
|
||||||
|
GDNATIVE_CALL_ERROR_METHOD_NOT_CONST, /* used for const call */
|
||||||
} GDNativeCallErrorType;
|
} GDNativeCallErrorType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -1240,7 +1240,7 @@ bool Expression::_compile_expression() {
|
||||||
return false;
|
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) {
|
switch (p_node->type) {
|
||||||
case Expression::ENode::TYPE_INPUT: {
|
case Expression::ENode::TYPE_INPUT: {
|
||||||
const Expression::InputNode *in = static_cast<const Expression::InputNode *>(p_node);
|
const Expression::InputNode *in = static_cast<const Expression::InputNode *>(p_node);
|
||||||
|
@ -1266,7 +1266,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
|
||||||
const Expression::OperatorNode *op = static_cast<const Expression::OperatorNode *>(p_node);
|
const Expression::OperatorNode *op = static_cast<const Expression::OperatorNode *>(p_node);
|
||||||
|
|
||||||
Variant a;
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1274,7 +1274,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
|
||||||
Variant b;
|
Variant b;
|
||||||
|
|
||||||
if (op->nodes[1]) {
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
const Expression::IndexNode *index = static_cast<const Expression::IndexNode *>(p_node);
|
||||||
|
|
||||||
Variant base;
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant idx;
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
const Expression::NamedIndexNode *index = static_cast<const Expression::NamedIndexNode *>(p_node);
|
||||||
|
|
||||||
Variant base;
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1336,7 +1336,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
|
||||||
arr.resize(array->array.size());
|
arr.resize(array->array.size());
|
||||||
for (int i = 0; i < array->array.size(); i++) {
|
for (int i = 0; i < array->array.size(); i++) {
|
||||||
Variant value;
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1353,14 +1353,14 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
|
||||||
Dictionary d;
|
Dictionary d;
|
||||||
for (int i = 0; i < dictionary->dict.size(); i += 2) {
|
for (int i = 0; i < dictionary->dict.size(); i += 2) {
|
||||||
Variant key;
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant value;
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1380,7 +1380,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
|
||||||
|
|
||||||
for (int i = 0; i < constructor->arguments.size(); i++) {
|
for (int i = 0; i < constructor->arguments.size(); i++) {
|
||||||
Variant value;
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1408,7 +1408,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
|
||||||
|
|
||||||
for (int i = 0; i < bifunc->arguments.size(); i++) {
|
for (int i = 0; i < bifunc->arguments.size(); i++) {
|
||||||
Variant value;
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
const Expression::CallNode *call = static_cast<const Expression::CallNode *>(p_node);
|
||||||
|
|
||||||
Variant base;
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1442,7 +1442,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
|
||||||
|
|
||||||
for (int i = 0; i < call->arguments.size(); i++) {
|
for (int i = 0; i < call->arguments.size(); i++) {
|
||||||
Variant value;
|
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) {
|
if (ret) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1452,7 +1452,11 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
|
||||||
}
|
}
|
||||||
|
|
||||||
Callable::CallError ce;
|
Callable::CallError 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);
|
base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
|
||||||
|
}
|
||||||
|
|
||||||
if (ce.error != Callable::CallError::CALL_OK) {
|
if (ce.error != Callable::CallError::CALL_OK) {
|
||||||
r_error_str = vformat(RTR("On call to '%s':"), String(call->method));
|
r_error_str = vformat(RTR("On call to '%s':"), String(call->method));
|
||||||
|
@ -1491,13 +1495,13 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu
|
||||||
return OK;
|
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 + ".");
|
ERR_FAIL_COND_V_MSG(error_set, Variant(), "There was previously a parse error: " + error_str + ".");
|
||||||
|
|
||||||
execution_error = false;
|
execution_error = false;
|
||||||
Variant output;
|
Variant output;
|
||||||
String error_txt;
|
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) {
|
if (err) {
|
||||||
execution_error = true;
|
execution_error = true;
|
||||||
error_str = error_txt;
|
error_str = error_txt;
|
||||||
|
@ -1517,7 +1521,7 @@ String Expression::get_error_text() const {
|
||||||
|
|
||||||
void Expression::_bind_methods() {
|
void Expression::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("parse", "expression", "input_names"), &Expression::parse, DEFVAL(Vector<String>()));
|
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("has_execute_failed"), &Expression::has_execute_failed);
|
||||||
ClassDB::bind_method(D_METHOD("get_error_text"), &Expression::get_error_text);
|
ClassDB::bind_method(D_METHOD("get_error_text"), &Expression::get_error_text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -257,14 +257,14 @@ private:
|
||||||
Vector<String> input_names;
|
Vector<String> input_names;
|
||||||
|
|
||||||
bool execution_error = false;
|
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:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Error parse(const String &p_expression, const Vector<String> &p_input_names = Vector<String>());
|
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;
|
bool has_execute_failed() const;
|
||||||
String get_error_text() const;
|
String get_error_text() const;
|
||||||
|
|
||||||
|
|
|
@ -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_INVALID_ARGUMENT:
|
||||||
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
|
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
|
||||||
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
|
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
|
||||||
|
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
|
||||||
return ret;
|
return ret;
|
||||||
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
|
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: {
|
||||||
}
|
}
|
||||||
|
@ -688,6 +689,54 @@ Variant Object::callp(const StringName &p_method, const Variant **p_args, int p_
|
||||||
return ret;
|
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) {
|
void Object::notification(int p_notification, bool p_reversed) {
|
||||||
_notificationv(p_notification, p_reversed);
|
_notificationv(p_notification, p_reversed);
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ enum PropertyHint {
|
||||||
PROPERTY_HINT_GLOBAL_DIR, ///< a directory path must be passed
|
PROPERTY_HINT_GLOBAL_DIR, ///< a directory path must be passed
|
||||||
PROPERTY_HINT_RESOURCE_TYPE, ///< a resource object type
|
PROPERTY_HINT_RESOURCE_TYPE, ///< a resource object type
|
||||||
PROPERTY_HINT_MULTILINE_TEXT, ///< used for string properties that can contain multiple lines
|
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_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_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color
|
||||||
PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
|
PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
|
||||||
|
@ -759,6 +760,7 @@ public:
|
||||||
void get_method_list(List<MethodInfo> *p_list) const;
|
void get_method_list(List<MethodInfo> *p_list) const;
|
||||||
Variant callv(const StringName &p_method, const Array &p_args);
|
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 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>
|
template <typename... VarArgs>
|
||||||
Variant call(const StringName &p_method, VarArgs... p_args) {
|
Variant call(const StringName &p_method, VarArgs... p_args) {
|
||||||
|
|
|
@ -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) {
|
void ScriptInstance::get_property_state(List<Pair<StringName, Variant>> &state) {
|
||||||
List<PropertyInfo> pinfo;
|
List<PropertyInfo> pinfo;
|
||||||
get_property_list(&pinfo);
|
get_property_list(&pinfo);
|
||||||
|
|
|
@ -190,6 +190,7 @@ public:
|
||||||
return callp(p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args), cerr);
|
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 void notification(int p_notification) = 0;
|
||||||
virtual String to_string(bool *r_valid) {
|
virtual String to_string(bool *r_valid) {
|
||||||
if (r_valid) {
|
if (r_valid) {
|
||||||
|
|
|
@ -61,6 +61,7 @@ public:
|
||||||
CALL_ERROR_TOO_MANY_ARGUMENTS, // expected is number of arguments
|
CALL_ERROR_TOO_MANY_ARGUMENTS, // expected is number of arguments
|
||||||
CALL_ERROR_TOO_FEW_ARGUMENTS, // expected is number of arguments
|
CALL_ERROR_TOO_FEW_ARGUMENTS, // expected is number of arguments
|
||||||
CALL_ERROR_INSTANCE_IS_NULL,
|
CALL_ERROR_INSTANCE_IS_NULL,
|
||||||
|
CALL_ERROR_METHOD_NOT_CONST,
|
||||||
};
|
};
|
||||||
Error error = Error::CALL_OK;
|
Error error = Error::CALL_OK;
|
||||||
int argument = 0;
|
int argument = 0;
|
||||||
|
|
|
@ -3395,6 +3395,8 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,
|
||||||
err_text = "Method not found.";
|
err_text = "Method not found.";
|
||||||
} else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
|
} else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
|
||||||
err_text = "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) {
|
} else if (ce.error == Callable::CallError::CALL_OK) {
|
||||||
return "Call OK";
|
return "Call OK";
|
||||||
}
|
}
|
||||||
|
|
|
@ -555,6 +555,7 @@ public:
|
||||||
return ret;
|
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 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);
|
static String get_call_error_text(const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
|
||||||
|
|
|
@ -1031,6 +1031,37 @@ void Variant::callp(const StringName &p_method, const Variant **p_args, int p_ar
|
||||||
#endif
|
#endif
|
||||||
r_ret = _get_obj().obj->callp(p_method, p_args, p_argcount, r_error);
|
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 if (type==Variant::METHOD) {
|
||||||
} else {
|
} else {
|
||||||
r_error.error = Callable::CallError::CALL_OK;
|
r_error.error = Callable::CallError::CALL_OK;
|
||||||
|
@ -1042,6 +1073,11 @@ void Variant::callp(const StringName &p_method, const Variant **p_args, int p_ar
|
||||||
return;
|
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);
|
imf->call(this, p_args, p_argcount, r_ret, imf->default_arguments, r_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2521,21 +2521,24 @@
|
||||||
<constant name="PROPERTY_HINT_MULTILINE_TEXT" value="20" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_MULTILINE_TEXT" value="20" enum="PropertyHint">
|
||||||
Hints that a string property is text with line breaks. Editing it will show a text input field where line breaks can be typed.
|
Hints that a string property is text with line breaks. Editing it will show a text input field where line breaks can be typed.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="21" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_EXPRESSION" value="21" enum="PropertyHint">
|
||||||
|
Hints that a string property is an [Expression].
|
||||||
|
</constant>
|
||||||
|
<constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="22" enum="PropertyHint">
|
||||||
Hints that a string property should have a placeholder text visible on its input field, whenever the property is empty. The hint string is the placeholder text to use.
|
Hints that a string property should have a placeholder text visible on its input field, whenever the property is empty. The hint string is the placeholder text to use.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="22" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="23" enum="PropertyHint">
|
||||||
Hints that a color property should be edited without changing its alpha component, i.e. only R, G and B channels are edited.
|
Hints that a color property should be edited without changing its alpha component, i.e. only R, G and B channels are edited.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="23" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="24" enum="PropertyHint">
|
||||||
Hints that an image is compressed using lossy compression.
|
Hints that an image is compressed using lossy compression.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="24" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="25" enum="PropertyHint">
|
||||||
Hints that an image is compressed using lossless compression.
|
Hints that an image is compressed using lossless compression.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_OBJECT_ID" value="25" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_OBJECT_ID" value="26" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_TYPE_STRING" value="26" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_TYPE_STRING" value="27" enum="PropertyHint">
|
||||||
Hint that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For instance:
|
Hint that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For instance:
|
||||||
[codeblock]
|
[codeblock]
|
||||||
hint_string = "%s:" % [TYPE_INT] # Array of inteters.
|
hint_string = "%s:" % [TYPE_INT] # Array of inteters.
|
||||||
|
@ -2545,47 +2548,47 @@
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
[b]Note:[/b] The final colon is required to specify for properly detecting built-in types.
|
[b]Note:[/b] The final colon is required to specify for properly detecting built-in types.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE" value="27" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE" value="28" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_METHOD_OF_VARIANT_TYPE" value="28" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_METHOD_OF_VARIANT_TYPE" value="29" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_METHOD_OF_BASE_TYPE" value="29" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_METHOD_OF_BASE_TYPE" value="30" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_METHOD_OF_INSTANCE" value="30" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_METHOD_OF_INSTANCE" value="31" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_METHOD_OF_SCRIPT" value="31" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_METHOD_OF_SCRIPT" value="32" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE" value="32" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE" value="33" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_PROPERTY_OF_BASE_TYPE" value="33" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_PROPERTY_OF_BASE_TYPE" value="34" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_PROPERTY_OF_INSTANCE" value="34" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_PROPERTY_OF_INSTANCE" value="35" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_PROPERTY_OF_SCRIPT" value="35" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_PROPERTY_OF_SCRIPT" value="36" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_OBJECT_TOO_BIG" value="36" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_OBJECT_TOO_BIG" value="37" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_NODE_PATH_VALID_TYPES" value="37" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_NODE_PATH_VALID_TYPES" value="38" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_SAVE_FILE" value="38" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_SAVE_FILE" value="39" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_GLOBAL_SAVE_FILE" value="39" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_GLOBAL_SAVE_FILE" value="40" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_INT_IS_OBJECTID" value="40" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_INT_IS_OBJECTID" value="41" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_INT_IS_POINTER" value="42" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_INT_IS_POINTER" value="43" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_ARRAY_TYPE" value="41" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_ARRAY_TYPE" value="42" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_LOCALE_ID" value="43" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_LOCALE_ID" value="44" enum="PropertyHint">
|
||||||
Hints that a string property is a locale code. Editing it will show a locale dialog for picking language and country.
|
Hints that a string property is a locale code. Editing it will show a locale dialog for picking language and country.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_LOCALIZABLE_STRING" value="44" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_LOCALIZABLE_STRING" value="45" enum="PropertyHint">
|
||||||
Hints that a dictionary property is string translation map. Dictionary keys are locale codes and, values are translated strings.
|
Hints that a dictionary property is string translation map. Dictionary keys are locale codes and, values are translated strings.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_NODE_TYPE" value="45" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_NODE_TYPE" value="46" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_HINT_MAX" value="46" enum="PropertyHint">
|
<constant name="PROPERTY_HINT_MAX" value="47" enum="PropertyHint">
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags">
|
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags">
|
||||||
</constant>
|
</constant>
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
<argument index="0" name="inputs" type="Array" default="[]" />
|
<argument index="0" name="inputs" type="Array" default="[]" />
|
||||||
<argument index="1" name="base_instance" type="Object" default="null" />
|
<argument index="1" name="base_instance" type="Object" default="null" />
|
||||||
<argument index="2" name="show_error" type="bool" default="true" />
|
<argument index="2" name="show_error" type="bool" default="true" />
|
||||||
|
<argument index="3" name="const_calls_only" type="bool" default="false" />
|
||||||
<description>
|
<description>
|
||||||
Executes the expression that was previously parsed by [method parse] and returns the result. Before you use the returned object, you should check if the method failed by calling [method has_execute_failed].
|
Executes the expression that was previously parsed by [method parse] and returns the result. Before you use the returned object, you should check if the method failed by calling [method has_execute_failed].
|
||||||
If you defined input variables in [method parse], you can specify their values in the inputs array, in the same order.
|
If you defined input variables in [method parse], you can specify their values in the inputs array, in the same order.
|
||||||
|
|
|
@ -165,6 +165,9 @@ void EditorPropertyMultilineText::_notification(int p_what) {
|
||||||
Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
|
Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
|
||||||
int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
|
int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
|
||||||
text->set_custom_minimum_size(Vector2(0, font->get_height(font_size) * 6));
|
text->set_custom_minimum_size(Vector2(0, font->get_height(font_size) * 6));
|
||||||
|
text->add_theme_font_override("font", get_theme_font("expression", "EditorFonts"));
|
||||||
|
text->add_theme_font_size_override("font_size", get_theme_font_size("expression_size", "EditorFonts"));
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +175,7 @@ void EditorPropertyMultilineText::_notification(int p_what) {
|
||||||
void EditorPropertyMultilineText::_bind_methods() {
|
void EditorPropertyMultilineText::_bind_methods() {
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorPropertyMultilineText::EditorPropertyMultilineText() {
|
EditorPropertyMultilineText::EditorPropertyMultilineText(bool p_expression) {
|
||||||
HBoxContainer *hb = memnew(HBoxContainer);
|
HBoxContainer *hb = memnew(HBoxContainer);
|
||||||
hb->add_theme_constant_override("separation", 0);
|
hb->add_theme_constant_override("separation", 0);
|
||||||
add_child(hb);
|
add_child(hb);
|
||||||
|
@ -189,6 +192,12 @@ EditorPropertyMultilineText::EditorPropertyMultilineText() {
|
||||||
hb->add_child(open_big_text);
|
hb->add_child(open_big_text);
|
||||||
big_text_dialog = nullptr;
|
big_text_dialog = nullptr;
|
||||||
big_text = nullptr;
|
big_text = nullptr;
|
||||||
|
if (p_expression) {
|
||||||
|
expression = true;
|
||||||
|
Ref<EditorStandardSyntaxHighlighter> highlighter;
|
||||||
|
highlighter.instantiate();
|
||||||
|
text->set_syntax_highlighter(highlighter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////// TEXT ENUM /////////////////////////
|
///////////////////// TEXT ENUM /////////////////////////
|
||||||
|
@ -3771,6 +3780,9 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
|
||||||
} else if (p_hint == PROPERTY_HINT_MULTILINE_TEXT) {
|
} else if (p_hint == PROPERTY_HINT_MULTILINE_TEXT) {
|
||||||
EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText);
|
EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText);
|
||||||
return editor;
|
return editor;
|
||||||
|
} else if (p_hint == PROPERTY_HINT_EXPRESSION) {
|
||||||
|
EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText(true));
|
||||||
|
return editor;
|
||||||
} else if (p_hint == PROPERTY_HINT_TYPE_STRING) {
|
} else if (p_hint == PROPERTY_HINT_TYPE_STRING) {
|
||||||
EditorPropertyClassName *editor = memnew(EditorPropertyClassName);
|
EditorPropertyClassName *editor = memnew(EditorPropertyClassName);
|
||||||
editor->setup("Object", p_hint_text);
|
editor->setup("Object", p_hint_text);
|
||||||
|
|
|
@ -81,6 +81,7 @@ class EditorPropertyMultilineText : public EditorProperty {
|
||||||
void _big_text_changed();
|
void _big_text_changed();
|
||||||
void _text_changed();
|
void _text_changed();
|
||||||
void _open_big_text();
|
void _open_big_text();
|
||||||
|
bool expression = false;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void _set_read_only(bool p_read_only) override;
|
virtual void _set_read_only(bool p_read_only) override;
|
||||||
|
@ -89,7 +90,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void update_property() override;
|
virtual void update_property() override;
|
||||||
EditorPropertyMultilineText();
|
EditorPropertyMultilineText(bool p_expression = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditorPropertyTextEnum : public EditorProperty {
|
class EditorPropertyTextEnum : public EditorProperty {
|
||||||
|
|
|
@ -530,7 +530,7 @@ void EditorSpinSlider::_evaluate_input_text() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant v = expr->execute(Array(), nullptr, false);
|
Variant v = expr->execute(Array(), nullptr, false, true);
|
||||||
if (v.get_type() == Variant::NIL) {
|
if (v.get_type() == Variant::NIL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1196,7 +1196,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
|
||||||
String whitespace = line.substr(0, line.size() - line.strip_edges(true, false).size()); //extract the whitespace at the beginning
|
String whitespace = line.substr(0, line.size() - line.strip_edges(true, false).size()); //extract the whitespace at the beginning
|
||||||
|
|
||||||
if (expression.parse(line) == OK) {
|
if (expression.parse(line) == OK) {
|
||||||
Variant result = expression.execute(Array(), Variant(), false);
|
Variant result = expression.execute(Array(), Variant(), false, true);
|
||||||
if (expression.get_error_text().is_empty()) {
|
if (expression.get_error_text().is_empty()) {
|
||||||
results.push_back(whitespace + result.get_construct_string());
|
results.push_back(whitespace + result.get_construct_string());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1474,7 +1474,7 @@ void CustomPropertyEditor::_modified(String p_string) {
|
||||||
v = value_editor[0]->get_text().to_int();
|
v = value_editor[0]->get_text().to_int();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
v = expr->execute(Array(), nullptr, false);
|
v = expr->execute(Array(), nullptr, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v != prev_v) {
|
if (v != prev_v) {
|
||||||
|
@ -1650,7 +1650,7 @@ real_t CustomPropertyEditor::_parse_real_expression(String text) {
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
out = value_editor[0]->get_text().to_float();
|
out = value_editor[0]->get_text().to_float();
|
||||||
} else {
|
} else {
|
||||||
out = expr->execute(Array(), nullptr, false);
|
out = expr->execute(Array(), nullptr, false, true);
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2278,6 +2278,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
||||||
push_error(vformat(R"(Too few arguments for %s constructor. Received %d but expected %d.)", Variant::get_type_name(builtin_type), p_call->arguments.size(), err.expected), p_call);
|
push_error(vformat(R"(Too few arguments for %s constructor. Received %d but expected %d.)", Variant::get_type_name(builtin_type), p_call->arguments.size(), err.expected), p_call);
|
||||||
break;
|
break;
|
||||||
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
|
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
|
||||||
|
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
|
||||||
break; // Can't happen in a builtin constructor.
|
break; // Can't happen in a builtin constructor.
|
||||||
case Callable::CallError::CALL_OK:
|
case Callable::CallError::CALL_OK:
|
||||||
p_call->is_constant = true;
|
p_call->is_constant = true;
|
||||||
|
@ -2380,6 +2381,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
||||||
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
|
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
|
||||||
push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
|
push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
|
||||||
break;
|
break;
|
||||||
|
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
|
||||||
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
|
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
|
||||||
break; // Can't happen in a builtin constructor.
|
break; // Can't happen in a builtin constructor.
|
||||||
case Callable::CallError::CALL_OK:
|
case Callable::CallError::CALL_OK:
|
||||||
|
@ -2422,6 +2424,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
||||||
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
|
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
|
||||||
push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
|
push_error(vformat(R"*(Too few arguments for "%s()" call. Expected at least %d but received %d.)*", function_name, err.expected, p_call->arguments.size()), p_call);
|
||||||
break;
|
break;
|
||||||
|
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
|
||||||
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
|
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
|
||||||
break; // Can't happen in a builtin constructor.
|
break; // Can't happen in a builtin constructor.
|
||||||
case Callable::CallError::CALL_OK:
|
case Callable::CallError::CALL_OK:
|
||||||
|
|
|
@ -177,6 +177,8 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
|
||||||
err_text = "Invalid call. Nonexistent " + p_where + ".";
|
err_text = "Invalid call. Nonexistent " + p_where + ".";
|
||||||
} else if (p_err.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
|
} else if (p_err.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
|
||||||
err_text = "Attempt to call " + p_where + " on a null instance.";
|
err_text = "Attempt to call " + p_where + " on a null instance.";
|
||||||
|
} else if (p_err.error == Callable::CallError::CALL_ERROR_METHOD_NOT_CONST) {
|
||||||
|
err_text = "Attempt to call " + p_where + " on a const instance.";
|
||||||
} else {
|
} else {
|
||||||
err_text = "Bug, call error: #" + itos(p_err.error);
|
err_text = "Bug, call error: #" + itos(p_err.error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1655,6 +1655,8 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
|
||||||
error_str += "Expected " + itos(r_error.argument) + " arguments.";
|
error_str += "Expected " + itos(r_error.argument) + " arguments.";
|
||||||
} else if (r_error.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
|
} else if (r_error.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
|
||||||
error_str += "Invalid Call.";
|
error_str += "Invalid Call.";
|
||||||
|
} else if (r_error.error == Callable::CallError::CALL_ERROR_METHOD_NOT_CONST) {
|
||||||
|
error_str += "Method not const in a const instance.";
|
||||||
} else if (r_error.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
|
} else if (r_error.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
|
||||||
error_str += "Base Instance is null";
|
error_str += "Base Instance is null";
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ void SpinBox::_text_submitted(const String &p_string) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant value = expr->execute(Array(), nullptr, false);
|
Variant value = expr->execute(Array(), nullptr, false, true);
|
||||||
if (value.get_type() != Variant::NIL) {
|
if (value.get_type() != Variant::NIL) {
|
||||||
set_value(value);
|
set_value(value);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue