summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml88
-rw-r--r--modules/gdscript/doc_classes/GDScriptFunctionState.xml5
-rw-r--r--modules/gdscript/gdscript.cpp33
-rw-r--r--modules/gdscript/gdscript.h5
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp22
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/gdscript/gdscript_functions.cpp2
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp2
8 files changed, 60 insertions, 99 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 36de66ea52..9e40a69712 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -112,7 +112,7 @@
</argument>
<description>
Returns the arc tangent of [code]s[/code] in radians. Use it to get the angle from an angle's tangent in trigonometry: [code]atan(tan(angle)) == angle[/code].
- The method cannot know in which quadrant the angle should fall. See [method atan2] if you have both [code]y[code] and [code]x[/code].
+ The method cannot know in which quadrant the angle should fall. See [method atan2] if you have both [code]y[/code] and [code]x[/code].
[codeblock]
a = atan(0.5) # a is 0.463648
[/codeblock]
@@ -318,7 +318,7 @@
</argument>
<description>
The natural exponential function. It raises the mathematical constant [b]e[/b] to the power of [code]s[/code] and returns it.
- [b]e[/b] has an approximate value of 2.71828.
+ [b]e[/b] has an approximate value of 2.71828, and can be obtained with [code]exp(1)[/code].
For exponents to other bases use the method [method pow].
[codeblock]
a = exp(2) # Approximately 7.39
@@ -505,6 +505,8 @@
</argument>
<description>
Returns [code]true[/code] if [code]a[/code] and [code]b[/code] are approximately equal to each other.
+ Here, approximately equal means that [code]a[/code] and [code]b[/code] are within a small internal epsilon of each other, which scales with the magnitude of the numbers.
+ Infinity values of the same sign are considered equal.
</description>
</method>
<method name="is_inf">
@@ -641,6 +643,7 @@
[codeblock]
log(10) # Returns 2.302585
[/codeblock]
+ [b]Note:[/b] The logarithm of [code]0[/code] returns [code]-inf[/code], while negative values return [code]-nan[/code].
</description>
</method>
<method name="max">
@@ -686,7 +689,9 @@
Moves [code]from[/code] toward [code]to[/code] by the [code]delta[/code] value.
Use a negative [code]delta[/code] value to move away.
[codeblock]
+ move_toward(5, 10, 4) # Returns 9
move_toward(10, 5, 4) # Returns 6
+ move_toward(10, 5, -1.5) # Returns 11.5
[/codeblock]
</description>
</method>
@@ -696,12 +701,17 @@
<argument index="0" name="value" type="int">
</argument>
<description>
- Returns the nearest larger power of 2 for integer [code]value[/code].
+ Returns the nearest equal or larger power of 2 for integer [code]value[/code].
+ In other words, returns the smallest value [code]a[/code] where [code]a = pow(2, n)[/code] such that [code]value &lt;= a[/code] for some non-negative integer [code]n[/code].
[codeblock]
nearest_po2(3) # Returns 4
nearest_po2(4) # Returns 4
nearest_po2(5) # Returns 8
+
+ nearest_po2(0) # Returns 0 (this may not be what you expect)
+ nearest_po2(-1) # Returns 0 (this may not be what you expect)
[/codeblock]
+ [b]WARNING:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for non-positive values of [code]value[/code] (in reality, 1 is the smallest integer power of 2).
</description>
</method>
<method name="ord">
@@ -725,16 +735,17 @@
<argument index="0" name="json" type="String">
</argument>
<description>
- Parse JSON text to a Variant (use [method typeof] to check if it is what you expect).
- Be aware that the JSON specification does not define integer or float types, but only a number type. Therefore, parsing a JSON text will convert all numerical values to [float] types.
- Note that JSON objects do not preserve key order like Godot dictionaries, thus you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements:
+ Parse JSON text to a Variant. (Use [method typeof] to check if the Variant's type is what you expect.)
+ [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, parsing a JSON text will convert all numerical values to [float] types.
+ [b]Note:[/b] JSON objects do not preserve key order like Godot dictionaries, thus, you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements:
[codeblock]
- p = parse_json('["a", "b", "c"]')
- if typeof(p) == TYPE_ARRAY:
- print(p[0]) # Prints a
+ var p = JSON.parse('["hello", "world", "!"]')
+ if typeof(p.result) == TYPE_ARRAY:
+ print(p.result[0]) # Prints "hello"
else:
- print("unexpected results")
+ push_error("Unexpected results.")
[/codeblock]
+ See also [JSON] for an alternative way to parse JSON text.
</description>
</method>
<method name="polar2cartesian">
@@ -1093,12 +1104,15 @@
</argument>
<argument index="1" name="to" type="float">
</argument>
- <argument index="2" name="weight" type="float">
+ <argument index="2" name="s" type="float">
</argument>
<description>
- Returns a number smoothly interpolated between the [code]from[/code] and [code]to[/code], based on the [code]weight[/code]. Similar to [method lerp], but interpolates faster at the beginning and slower at the end.
+ Returns the result of smoothly interpolating the value of [code]s[/code] between [code]0[/code] and [code]1[/code], based on the where [code]s[/code] lies with respect to the edges [code]from[/code] and [code]to[/code].
+ The return value is [code]0[/code] if [code]s &lt;= from[/code], and [code]1[/code] if [code]s &gt;= to[/code]. If [code]s[/code] lies between [code]from[/code] and [code]to[/code], the returned value follows an S-shaped curve that maps [code]s[/code] between [code]0[/code] and [code]1[/code].
+ This S-shaped curve is the cubic Hermite interpolator, given by [code]f(s) = 3*s^2 - 2*s^3[/code].
[codeblock]
- smoothstep(0, 2, 0.5) # Returns 0.15
+ smoothstep(0, 2, -5.0) # Returns 0.0
+ smoothstep(0, 2, 0.5) # Returns 0.15625
smoothstep(0, 2, 1.0) # Returns 0.5
smoothstep(0, 2, 2.0) # Returns 1.0
[/codeblock]
@@ -1114,7 +1128,7 @@
[codeblock]
sqrt(9) # Returns 3
[/codeblock]
- If you need negative inputs, use [code]System.Numerics.Complex[/code] in C#.
+ [b]Note:[/b]Negative values of [code]s[/code] return NaN. If you need negative inputs, use [code]System.Numerics.Complex[/code] in C#.
</description>
</method>
<method name="step_decimals">
@@ -1207,12 +1221,16 @@
<argument index="0" name="var" type="Variant">
</argument>
<description>
- Converts a Variant [code]var[/code] to JSON text and return the result. Useful for serializing data to store or send over the network.
+ Converts a [Variant] [code]var[/code] to JSON text and return the result. Useful for serializing data to store or send over the network.
[codeblock]
+ # Both numbers below are integers.
a = { "a": 1, "b": 2 }
b = to_json(a)
print(b) # {"a":1, "b":2}
+ # Both numbers above are floats, even if they display without any decimal places.
[/codeblock]
+ [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a [Variant] to JSON text will convert all numerical values to [float] types.
+ See also [JSON] for an alternative way to convert a [Variant] to JSON text.
</description>
</method>
<method name="type_exists">
@@ -1255,9 +1273,9 @@
j = to_json([1, 2, 3])
v = validate_json(j)
if not v:
- print("valid")
+ print("Valid JSON.")
else:
- prints("invalid", v)
+ push_error("Invalid JSON: " + v)
[/codeblock]
</description>
</method>
@@ -1354,42 +1372,6 @@
[code]wrapi[/code] is more flexible than using the [method posmod] approach by giving the user control over the minimum value.
</description>
</method>
- <method name="yield">
- <return type="GDScriptFunctionState">
- </return>
- <argument index="0" name="object" type="Object" default="null">
- </argument>
- <argument index="1" name="signal" type="String" default="&quot;&quot;">
- </argument>
- <description>
- Stops the function execution and returns the current suspended state to the calling function.
- From the caller, call [method GDScriptFunctionState.resume] on the state to resume execution. This invalidates the state. Within the resumed function, [code]yield()[/code] returns whatever was passed to the [code]resume()[/code] function call.
- If passed an object and a signal, the execution is resumed when the object emits the given signal. In this case, [code]yield()[/code] returns the argument passed to [code]emit_signal()[/code] if the signal takes only one argument, or an array containing all the arguments passed to [code]emit_signal()[/code] if the signal takes multiple arguments.
- You can also use [code]yield[/code] to wait for a function to finish:
- [codeblock]
- func _ready():
- yield(countdown(), "completed") # waiting for the countdown() function to complete
- print('Ready')
-
- func countdown():
- yield(get_tree(), "idle_frame") # returns a GDScriptFunctionState object to _ready()
- print(3)
- yield(get_tree().create_timer(1.0), "timeout")
- print(2)
- yield(get_tree().create_timer(1.0), "timeout")
- print(1)
- yield(get_tree().create_timer(1.0), "timeout")
-
- # prints:
- # 3
- # 2
- # 1
- # Ready
- [/codeblock]
- When yielding on a function, the [code]completed[/code] signal will be emitted automatically when the function returns. It can, therefore, be used as the [code]signal[/code] parameter of the [code]yield[/code] method to resume.
- In order to yield on a function, the resulting function should also return a [code]GDScriptFunctionState[/code]. Notice [code]yield(get_tree(), "idle_frame")[/code] from the above example.
- </description>
- </method>
</methods>
<constants>
<constant name="PI" value="3.141593">
diff --git a/modules/gdscript/doc_classes/GDScriptFunctionState.xml b/modules/gdscript/doc_classes/GDScriptFunctionState.xml
index 9a73764646..5e369b32d9 100644
--- a/modules/gdscript/doc_classes/GDScriptFunctionState.xml
+++ b/modules/gdscript/doc_classes/GDScriptFunctionState.xml
@@ -4,7 +4,8 @@
State of a function call after yielding.
</brief_description>
<description>
- Calling [method @GDScript.yield] within a function will cause that function to yield and return its current state as an object of this type. The yielded function call can then be resumed later by calling [method resume] on this state object.
+ FIXME: Outdated docs as of GDScript rewrite in 4.0.
+ Calling [code]yield[/code] within a function will cause that function to yield and return its current state as an object of this type. The yielded function call can then be resumed later by calling [method resume] on this state object.
</description>
<tutorials>
</tutorials>
@@ -26,7 +27,7 @@
</argument>
<description>
Resume execution of the yielded function call.
- If handed an argument, return the argument from the [method @GDScript.yield] call in the yielded function call. You can pass e.g. an [Array] to hand multiple arguments.
+ If handed an argument, return the argument from the [code]yield[/code] call in the yielded function call. You can pass e.g. an [Array] to hand multiple arguments.
This function returns what the resumed function call returns, possibly another function state if yielded again.
</description>
</method>
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 40ef0aeec6..9170255c02 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -1309,39 +1309,6 @@ Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_arg
return Variant();
}
-void GDScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
- GDScript *sptr = script.ptr();
- Callable::CallError ce;
-
- while (sptr) {
- Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
- if (E) {
- E->get()->call(this, p_args, p_argcount, ce);
- return;
- }
- sptr = sptr->_base;
- }
-}
-
-void GDScriptInstance::_ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount) {
- if (sptr->_base) {
- _ml_call_reversed(sptr->_base, p_method, p_args, p_argcount);
- }
-
- Callable::CallError ce;
-
- Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
- if (E) {
- E->get()->call(this, p_args, p_argcount, ce);
- }
-}
-
-void GDScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
- if (script.ptr()) {
- _ml_call_reversed(script.ptr(), p_method, p_args, p_argcount);
- }
-}
-
void GDScriptInstance::notification(int p_notification) {
//notification is not virtual, it gets called at ALL levels just like in C.
Variant value = p_notification;
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 8236464f15..9906b4014d 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -146,7 +146,6 @@ protected:
void _get_property_list(List<PropertyInfo> *p_properties) const;
Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
- //void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount);
static void _bind_methods();
@@ -258,8 +257,6 @@ class GDScriptInstance : public ScriptInstance {
SelfList<GDScriptFunctionState>::List pending_func_states;
- void _ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount);
-
public:
virtual Object *get_owner() { return owner; }
@@ -271,8 +268,6 @@ public:
virtual void get_method_list(List<MethodInfo> *p_list) const;
virtual bool has_method(const StringName &p_method) const;
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
- virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount);
Variant debug_get_member_by_index(int p_idx) const { return members[p_idx]; }
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index fdcd4412d2..531666bec5 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -342,6 +342,16 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return result;
}
+ if (first == "Object") {
+ result.kind = GDScriptParser::DataType::NATIVE;
+ result.native_type = "Object";
+ if (p_type->type_chain.size() > 1) {
+ push_error(R"("Object" type don't contain nested types.)", p_type->type_chain[1]);
+ return GDScriptParser::DataType();
+ }
+ return result;
+ }
+
if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) {
// Built-in types.
if (p_type->type_chain.size() > 1) {
@@ -484,7 +494,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
if (member.variable->initializer != nullptr) {
if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true)) {
- push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer);
+ push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer);
} else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) {
#ifdef DEBUG_ENABLED
parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION);
@@ -979,7 +989,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
if (p_variable->initializer != nullptr) {
if (!is_type_compatible(type, p_variable->initializer->get_datatype(), true)) {
- push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer);
+ push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer);
#ifdef DEBUG_ENABLED
} else if (type.builtin_type == Variant::INT && p_variable->initializer->get_datatype().builtin_type == Variant::FLOAT) {
parser->push_warning(p_variable->initializer, GDScriptWarning::NARROWING_CONVERSION);
@@ -1468,6 +1478,12 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
}
void GDScriptAnalyzer::reduce_await(GDScriptParser::AwaitNode *p_await) {
+ if (p_await->to_await == nullptr) {
+ GDScriptParser::DataType await_type;
+ await_type.kind = GDScriptParser::DataType::VARIANT;
+ p_await->set_datatype(await_type);
+ return;
+ }
if (p_await->to_await->type == GDScriptParser::Node::CALL) {
reduce_call(static_cast<GDScriptParser::CallNode *>(p_await->to_await), true);
} else {
@@ -2051,7 +2067,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
GDScriptParser::ClassNode *outer = base_class->outer;
while (outer != nullptr) {
if (outer->has_member(name)) {
- const GDScriptParser::ClassNode::Member &member = base_class->get_member(name);
+ const GDScriptParser::ClassNode::Member &member = outer->get_member(name);
if (member.type == GDScriptParser::ClassNode::Member::CONSTANT) {
// TODO: Make sure loops won't cause problem. And make special error message for those.
// For out-of-order resolution:
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 3d37c7f803..e34d87f5cc 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -736,7 +736,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
} else {
if (callee->type == GDScriptParser::Node::IDENTIFIER) {
// Self function call.
- if (codegen.function_node && codegen.function_node->is_static) {
+ if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
ret = (GDScriptFunction::ADDR_TYPE_CLASS << GDScriptFunction::ADDR_BITS);
} else {
ret = (GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index 7f2a62a8e9..fefbf906f0 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -1636,7 +1636,7 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
return mi;
} break;
case MATH_SMOOTHSTEP: {
- MethodInfo mi("smoothstep", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "weight"));
+ MethodInfo mi("smoothstep", PropertyInfo(Variant::FLOAT, "from"), PropertyInfo(Variant::FLOAT, "to"), PropertyInfo(Variant::FLOAT, "s"));
mi.return_val.type = Variant::FLOAT;
return mi;
} break;
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index d230173e9a..7a4bdd88ba 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -646,7 +646,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
int64_t value = number.bin_to_int();
return make_literal(value);
} else if (has_decimal || has_exponent) {
- double value = number.to_double();
+ double value = number.to_float();
return make_literal(value);
} else {
int64_t value = number.to_int();