diff options
| -rw-r--r-- | core/core_constants.cpp | 1 | ||||
| -rw-r--r-- | core/extension/gdnative_interface.h | 2 | ||||
| -rw-r--r-- | core/math/expression.cpp | 38 | ||||
| -rw-r--r-- | core/math/expression.h | 4 | ||||
| -rw-r--r-- | core/object/object.cpp | 49 | ||||
| -rw-r--r-- | core/object/object.h | 2 | ||||
| -rw-r--r-- | core/object/script_language.cpp | 5 | ||||
| -rw-r--r-- | core/object/script_language.h | 1 | ||||
| -rw-r--r-- | core/variant/callable.h | 1 | ||||
| -rw-r--r-- | core/variant/variant.cpp | 2 | ||||
| -rw-r--r-- | core/variant/variant.h | 1 | ||||
| -rw-r--r-- | core/variant/variant_call.cpp | 36 | ||||
| -rw-r--r-- | doc/classes/@GlobalScope.xml | 55 | ||||
| -rw-r--r-- | doc/classes/Expression.xml | 1 | ||||
| -rw-r--r-- | editor/editor_properties.cpp | 14 | ||||
| -rw-r--r-- | editor/editor_properties.h | 3 | ||||
| -rw-r--r-- | editor/editor_spin_slider.cpp | 2 | ||||
| -rw-r--r-- | editor/plugins/script_text_editor.cpp | 2 | ||||
| -rw-r--r-- | editor/property_editor.cpp | 4 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_analyzer.cpp | 3 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_vm.cpp | 2 | ||||
| -rw-r--r-- | modules/visual_script/visual_script.cpp | 2 | ||||
| -rw-r--r-- | scene/gui/spin_box.cpp | 2 | 
23 files changed, 179 insertions, 53 deletions
diff --git a/core/core_constants.cpp b/core/core_constants.cpp index 67aa2bbbfb..24d8b0af6e 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -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); diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h index 095c7983ee..ccd6fb0f7e 100644 --- a/core/extension/gdnative_interface.h +++ b/core/extension/gdnative_interface.h @@ -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 { diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 5a90f68b66..419056d7d6 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -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); @@ -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);  			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;  			} @@ -1274,7 +1274,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:  			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;  				} @@ -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;  			} @@ -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;  			} @@ -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; @@ -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;  				} @@ -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; @@ -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;  				} @@ -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; @@ -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; @@ -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)); @@ -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; @@ -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);  } diff --git a/core/math/expression.h b/core/math/expression.h index 6ea3c1611f..2d58915996 100644 --- a/core/math/expression.h +++ b/core/math/expression.h @@ -257,14 +257,14 @@ private:  	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; diff --git a/core/object/object.cpp b/core/object/object.cpp index 6585c3fa79..440da00c17 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -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: {  			} @@ -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); diff --git a/core/object/object.h b/core/object/object.h index 7dac96bc2b..e065634000 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -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, @@ -759,6 +760,7 @@ public:  	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) { diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 66c9a80193..4623d0e525 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -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); diff --git a/core/object/script_language.h b/core/object/script_language.h index 0a8e79a24e..776a9bfaab 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -190,6 +190,7 @@ public:  		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) { diff --git a/core/variant/callable.h b/core/variant/callable.h index 6a760958d6..bbcf5427ba 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -61,6 +61,7 @@ public:  			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; diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 6007268e21..75aec9a619 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -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";  	} diff --git a/core/variant/variant.h b/core/variant/variant.h index 992d9cad40..83d244145b 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -555,6 +555,7 @@ public:  		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); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 8e420ecf04..19c0e35777 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -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; @@ -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);  	}  } diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 863ea899ee..ebda0794ce 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2521,21 +2521,24 @@  		<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.  		</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.  		</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.  		</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.  		</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.  		</constant> -		<constant name="PROPERTY_HINT_OBJECT_ID" value="25" enum="PropertyHint"> +		<constant name="PROPERTY_HINT_OBJECT_ID" value="26" enum="PropertyHint">  		</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:  			[codeblock]  			hint_string = "%s:" % [TYPE_INT] # Array of inteters. @@ -2545,47 +2548,47 @@  			[/codeblock]  			[b]Note:[/b] The final colon is required to specify for properly detecting built-in types.  		</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 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 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 name="PROPERTY_HINT_METHOD_OF_INSTANCE" value="30" enum="PropertyHint"> +		<constant name="PROPERTY_HINT_METHOD_OF_INSTANCE" value="31" enum="PropertyHint">  		</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 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 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 name="PROPERTY_HINT_PROPERTY_OF_INSTANCE" value="34" enum="PropertyHint"> +		<constant name="PROPERTY_HINT_PROPERTY_OF_INSTANCE" value="35" enum="PropertyHint">  		</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 name="PROPERTY_HINT_OBJECT_TOO_BIG" value="36" enum="PropertyHint"> +		<constant name="PROPERTY_HINT_OBJECT_TOO_BIG" value="37" enum="PropertyHint">  		</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 name="PROPERTY_HINT_SAVE_FILE" value="38" enum="PropertyHint"> +		<constant name="PROPERTY_HINT_SAVE_FILE" value="39" enum="PropertyHint">  		</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 name="PROPERTY_HINT_INT_IS_OBJECTID" value="40" enum="PropertyHint"> +		<constant name="PROPERTY_HINT_INT_IS_OBJECTID" value="41" enum="PropertyHint">  		</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 name="PROPERTY_HINT_ARRAY_TYPE" value="41" enum="PropertyHint"> +		<constant name="PROPERTY_HINT_ARRAY_TYPE" value="42" enum="PropertyHint">  		</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.  		</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.  		</constant> -		<constant name="PROPERTY_HINT_NODE_TYPE" value="45" enum="PropertyHint"> +		<constant name="PROPERTY_HINT_NODE_TYPE" value="46" enum="PropertyHint">  		</constant> -		<constant name="PROPERTY_HINT_MAX" value="46" enum="PropertyHint"> +		<constant name="PROPERTY_HINT_MAX" value="47" enum="PropertyHint">  		</constant>  		<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags">  		</constant> diff --git a/doc/classes/Expression.xml b/doc/classes/Expression.xml index b37de09e04..50979c9b68 100644 --- a/doc/classes/Expression.xml +++ b/doc/classes/Expression.xml @@ -56,6 +56,7 @@  			<argument index="0" name="inputs" type="Array" default="[]" />  			<argument index="1" name="base_instance" type="Object" default="null" />  			<argument index="2" name="show_error" type="bool" default="true" /> +			<argument index="3" name="const_calls_only" type="bool" default="false" />  			<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].  				If you defined input variables in [method parse], you can specify their values in the inputs array, in the same order. diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 0e6c9162ce..e5105fdedc 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -165,6 +165,9 @@ void EditorPropertyMultilineText::_notification(int p_what) {  			Ref<Font> font = get_theme_font(SNAME("font"), 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->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;  	}  } @@ -172,7 +175,7 @@ void EditorPropertyMultilineText::_notification(int p_what) {  void EditorPropertyMultilineText::_bind_methods() {  } -EditorPropertyMultilineText::EditorPropertyMultilineText() { +EditorPropertyMultilineText::EditorPropertyMultilineText(bool p_expression) {  	HBoxContainer *hb = memnew(HBoxContainer);  	hb->add_theme_constant_override("separation", 0);  	add_child(hb); @@ -189,6 +192,12 @@ EditorPropertyMultilineText::EditorPropertyMultilineText() {  	hb->add_child(open_big_text);  	big_text_dialog = nullptr;  	big_text = nullptr; +	if (p_expression) { +		expression = true; +		Ref<EditorStandardSyntaxHighlighter> highlighter; +		highlighter.instantiate(); +		text->set_syntax_highlighter(highlighter); +	}  }  ///////////////////// TEXT ENUM ///////////////////////// @@ -3771,6 +3780,9 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_  			} else if (p_hint == PROPERTY_HINT_MULTILINE_TEXT) {  				EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText);  				return editor; +			} else if (p_hint == PROPERTY_HINT_EXPRESSION) { +				EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText(true)); +				return editor;  			} else if (p_hint == PROPERTY_HINT_TYPE_STRING) {  				EditorPropertyClassName *editor = memnew(EditorPropertyClassName);  				editor->setup("Object", p_hint_text); diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 72b2b0b283..7cd6ea4f6b 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -81,6 +81,7 @@ class EditorPropertyMultilineText : public EditorProperty {  	void _big_text_changed();  	void _text_changed();  	void _open_big_text(); +	bool expression = false;  protected:  	virtual void _set_read_only(bool p_read_only) override; @@ -89,7 +90,7 @@ protected:  public:  	virtual void update_property() override; -	EditorPropertyMultilineText(); +	EditorPropertyMultilineText(bool p_expression = false);  };  class EditorPropertyTextEnum : public EditorProperty { diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index a0c818ba84..f23f0cf758 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -530,7 +530,7 @@ void EditorSpinSlider::_evaluate_input_text() {  		return;  	} -	Variant v = expr->execute(Array(), nullptr, false); +	Variant v = expr->execute(Array(), nullptr, false, true);  	if (v.get_type() == Variant::NIL) {  		return;  	} diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 05c707c065..7d4ffd1a25 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -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  				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()) {  						results.push_back(whitespace + result.get_construct_string());  					} else { diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 771d34d841..d936e821df 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -1474,7 +1474,7 @@ void CustomPropertyEditor::_modified(String p_string) {  				v = value_editor[0]->get_text().to_int();  				return;  			} else { -				v = expr->execute(Array(), nullptr, false); +				v = expr->execute(Array(), nullptr, false, false);  			}  			if (v != prev_v) { @@ -1650,7 +1650,7 @@ real_t CustomPropertyEditor::_parse_real_expression(String text) {  	if (err != OK) {  		out = value_editor[0]->get_text().to_float();  	} else { -		out = expr->execute(Array(), nullptr, false); +		out = expr->execute(Array(), nullptr, false, true);  	}  	return out;  } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 42b02ce3b9..ea994654bf 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -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);  						break;  					case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: +					case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:  						break; // Can't happen in a builtin constructor.  					case Callable::CallError::CALL_OK:  						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:  						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; +					case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:  					case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:  						break; // Can't happen in a builtin constructor.  					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:  						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; +					case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:  					case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:  						break; // Can't happen in a builtin constructor.  					case Callable::CallError::CALL_OK: diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 20b8d29ec3..3f25c2fa43 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -177,6 +177,8 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const  		err_text = "Invalid call. Nonexistent " + p_where + ".";  	} else if (p_err.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {  		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 {  		err_text = "Bug, call error: #" + itos(p_err.error);  	} diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index c4fafb6676..c5bcf23c8e 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -1655,6 +1655,8 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p  				error_str += "Expected " + itos(r_error.argument) + " arguments.";  			} else if (r_error.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {  				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) {  				error_str += "Base Instance is null";  			} diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index e50d7e765c..890e349afb 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -62,7 +62,7 @@ void SpinBox::_text_submitted(const String &p_string) {  		return;  	} -	Variant value = expr->execute(Array(), nullptr, false); +	Variant value = expr->execute(Array(), nullptr, false, true);  	if (value.get_type() != Variant::NIL) {  		set_value(value);  	}  |