summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuri Roubinsky <chaosus89@gmail.com>2022-03-07 20:25:21 +0300
committerYuri Rubinsky <chaosus89@gmail.com>2022-05-11 16:30:37 +0300
commitdbd7a315074257bca834e1448b53a905ebb8dd8b (patch)
treea13d08663bc046cb445373b7828d0f3ac42cd867
parent9963ae3553d059e4ac3b57c7a4cdc55d1a87d49a (diff)
Implement exponential operator (**) to GDScript/Expressions
-rw-r--r--core/core_constants.cpp1
-rw-r--r--core/extension/gdnative_interface.h1
-rw-r--r--core/math/expression.cpp40
-rw-r--r--core/math/expression.h1
-rw-r--r--core/variant/variant.h1
-rw-r--r--core/variant/variant_op.cpp6
-rw-r--r--core/variant/variant_op.h18
-rw-r--r--doc/classes/@GlobalScope.xml27
-rw-r--r--doc/classes/float.xml12
-rw-r--r--doc/classes/int.xml12
-rwxr-xr-xdoc/tools/make_rst.py2
-rw-r--r--modules/gdscript/gdscript_parser.cpp16
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp10
-rw-r--r--modules/gdscript/gdscript_tokenizer.h2
15 files changed, 125 insertions, 26 deletions
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 2a514b68d8..a53929a3af 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -703,6 +703,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NEGATE", Variant::OP_NEGATE);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_POSITIVE", Variant::OP_POSITIVE);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MODULE", Variant::OP_MODULE);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_POWER", Variant::OP_POWER);
//bitwise
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT);
BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT);
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 36d51ff2b9..98976b29f6 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -114,6 +114,7 @@ typedef enum {
GDNATIVE_VARIANT_OP_NEGATE,
GDNATIVE_VARIANT_OP_POSITIVE,
GDNATIVE_VARIANT_OP_MODULE,
+ GDNATIVE_VARIANT_OP_POWER,
/* bitwise */
GDNATIVE_VARIANT_OP_SHIFT_LEFT,
GDNATIVE_VARIANT_OP_SHIFT_RIGHT,
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 9dd1257474..97dc175d94 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -155,7 +155,12 @@ Error Expression::_get_token(Token &r_token) {
return OK;
}
case '*': {
- r_token.type = TK_OP_MUL;
+ if (expression[str_ofs] == '*') {
+ r_token.type = TK_OP_POW;
+ str_ofs++;
+ } else {
+ r_token.type = TK_OP_MUL;
+ }
return OK;
}
case '%': {
@@ -542,6 +547,7 @@ const char *Expression::token_name[TK_MAX] = {
"OP MUL",
"OP DIV",
"OP MOD",
+ "OP POW",
"OP SHIFT LEFT",
"OP SHIFT RIGHT",
"OP BIT AND",
@@ -1013,6 +1019,9 @@ Expression::ENode *Expression::_parse_expression() {
case TK_OP_MOD:
op = Variant::OP_MODULE;
break;
+ case TK_OP_POW:
+ op = Variant::OP_POWER;
+ break;
case TK_OP_SHIFT_LEFT:
op = Variant::OP_SHIFT_LEFT;
break;
@@ -1066,35 +1075,38 @@ Expression::ENode *Expression::_parse_expression() {
bool unary = false;
switch (expression[i].op) {
- case Variant::OP_BIT_NEGATE:
+ case Variant::OP_POWER:
priority = 0;
+ break;
+ case Variant::OP_BIT_NEGATE:
+ priority = 1;
unary = true;
break;
case Variant::OP_NEGATE:
- priority = 1;
+ priority = 2;
unary = true;
break;
case Variant::OP_MULTIPLY:
case Variant::OP_DIVIDE:
case Variant::OP_MODULE:
- priority = 2;
+ priority = 3;
break;
case Variant::OP_ADD:
case Variant::OP_SUBTRACT:
- priority = 3;
+ priority = 4;
break;
case Variant::OP_SHIFT_LEFT:
case Variant::OP_SHIFT_RIGHT:
- priority = 4;
+ priority = 5;
break;
case Variant::OP_BIT_AND:
- priority = 5;
+ priority = 6;
break;
case Variant::OP_BIT_XOR:
- priority = 6;
+ priority = 7;
break;
case Variant::OP_BIT_OR:
- priority = 7;
+ priority = 8;
break;
case Variant::OP_LESS:
case Variant::OP_LESS_EQUAL:
@@ -1102,20 +1114,20 @@ Expression::ENode *Expression::_parse_expression() {
case Variant::OP_GREATER_EQUAL:
case Variant::OP_EQUAL:
case Variant::OP_NOT_EQUAL:
- priority = 8;
+ priority = 9;
break;
case Variant::OP_IN:
- priority = 10;
+ priority = 11;
break;
case Variant::OP_NOT:
- priority = 11;
+ priority = 12;
unary = true;
break;
case Variant::OP_AND:
- priority = 12;
+ priority = 13;
break;
case Variant::OP_OR:
- priority = 13;
+ priority = 14;
break;
default: {
_set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op));
diff --git a/core/math/expression.h b/core/math/expression.h
index d43cc4091a..6ea3c1611f 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -85,6 +85,7 @@ private:
TK_OP_MUL,
TK_OP_DIV,
TK_OP_MOD,
+ TK_OP_POW,
TK_OP_SHIFT_LEFT,
TK_OP_SHIFT_RIGHT,
TK_OP_BIT_AND,
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 475bf7158d..726ba120b5 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -473,6 +473,7 @@ public:
OP_NEGATE,
OP_POSITIVE,
OP_MODULE,
+ OP_POWER,
//bitwise
OP_SHIFT_LEFT,
OP_SHIFT_RIGHT,
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 35e0319aa3..adace2b534 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -361,6 +361,11 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorStringModT<PackedVector3Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_VECTOR3_ARRAY);
register_op<OperatorEvaluatorStringModT<PackedColorArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_COLOR_ARRAY);
+ register_op<OperatorEvaluatorPow<int64_t, int64_t, int64_t>>(Variant::OP_POWER, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorPow<double, int64_t, double>>(Variant::OP_POWER, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorPow<double, double, double>>(Variant::OP_POWER, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorPow<double, double, int64_t>>(Variant::OP_POWER, Variant::FLOAT, Variant::INT);
+
register_op<OperatorEvaluatorNeg<int64_t, int64_t>>(Variant::OP_NEGATE, Variant::INT, Variant::NIL);
register_op<OperatorEvaluatorNeg<double, double>>(Variant::OP_NEGATE, Variant::FLOAT, Variant::NIL);
register_op<OperatorEvaluatorNeg<Vector2, Vector2>>(Variant::OP_NEGATE, Variant::VECTOR2, Variant::NIL);
@@ -929,6 +934,7 @@ static const char *_op_names[Variant::OP_MAX] = {
"unary-",
"unary+",
"%",
+ "**",
"<<",
">>",
"&",
diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h
index f72a92d31a..3e9bae1078 100644
--- a/core/variant/variant_op.h
+++ b/core/variant/variant_op.h
@@ -92,6 +92,24 @@ public:
};
template <class R, class A, class B>
+class OperatorEvaluatorPow {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = R(Math::pow((double)a, (double)b));
+ r_valid = true;
+ }
+ static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = R(Math::pow((double)*VariantGetInternalPtr<A>::get_ptr(left), (double)*VariantGetInternalPtr<B>::get_ptr(right)));
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(R(Math::pow((double)PtrToArg<A>::convert(left), (double)PtrToArg<B>::convert(right))), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
class OperatorEvaluatorXForm {
public:
static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index a40b851efc..5f81c80887 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -2799,40 +2799,43 @@
<constant name="OP_MODULE" value="12" enum="Variant.Operator">
Remainder/modulo operator ([code]%[/code]).
</constant>
- <constant name="OP_SHIFT_LEFT" value="13" enum="Variant.Operator">
+ <constant name="OP_POWER" value="13" enum="Variant.Operator">
+ Power operator ([code]**[/code]).
+ </constant>
+ <constant name="OP_SHIFT_LEFT" value="14" enum="Variant.Operator">
Left shift operator ([code]&lt;&lt;[/code]).
</constant>
- <constant name="OP_SHIFT_RIGHT" value="14" enum="Variant.Operator">
+ <constant name="OP_SHIFT_RIGHT" value="15" enum="Variant.Operator">
Right shift operator ([code]&gt;&gt;[/code]).
</constant>
- <constant name="OP_BIT_AND" value="15" enum="Variant.Operator">
+ <constant name="OP_BIT_AND" value="16" enum="Variant.Operator">
Bitwise AND operator ([code]&amp;[/code]).
</constant>
- <constant name="OP_BIT_OR" value="16" enum="Variant.Operator">
+ <constant name="OP_BIT_OR" value="17" enum="Variant.Operator">
Bitwise OR operator ([code]|[/code]).
</constant>
- <constant name="OP_BIT_XOR" value="17" enum="Variant.Operator">
+ <constant name="OP_BIT_XOR" value="18" enum="Variant.Operator">
Bitwise XOR operator ([code]^[/code]).
</constant>
- <constant name="OP_BIT_NEGATE" value="18" enum="Variant.Operator">
+ <constant name="OP_BIT_NEGATE" value="19" enum="Variant.Operator">
Bitwise NOT operator ([code]~[/code]).
</constant>
- <constant name="OP_AND" value="19" enum="Variant.Operator">
+ <constant name="OP_AND" value="20" enum="Variant.Operator">
Logical AND operator ([code]and[/code] or [code]&amp;&amp;[/code]).
</constant>
- <constant name="OP_OR" value="20" enum="Variant.Operator">
+ <constant name="OP_OR" value="21" enum="Variant.Operator">
Logical OR operator ([code]or[/code] or [code]||[/code]).
</constant>
- <constant name="OP_XOR" value="21" enum="Variant.Operator">
+ <constant name="OP_XOR" value="22" enum="Variant.Operator">
Logical XOR operator (not implemented in GDScript).
</constant>
- <constant name="OP_NOT" value="22" enum="Variant.Operator">
+ <constant name="OP_NOT" value="23" enum="Variant.Operator">
Logical NOT operator ([code]not[/code] or [code]![/code]).
</constant>
- <constant name="OP_IN" value="23" enum="Variant.Operator">
+ <constant name="OP_IN" value="24" enum="Variant.Operator">
Logical IN operator ([code]in[/code]).
</constant>
- <constant name="OP_MAX" value="24" enum="Variant.Operator">
+ <constant name="OP_MAX" value="25" enum="Variant.Operator">
Represents the size of the [enum Variant.Operator] enum.
</constant>
</constants>
diff --git a/doc/classes/float.xml b/doc/classes/float.xml
index 50961f9c7f..f36b1fddeb 100644
--- a/doc/classes/float.xml
+++ b/doc/classes/float.xml
@@ -124,6 +124,18 @@
Multiplies a [float] and an [int]. The result is a [float].
</description>
</operator>
+ <operator name="operator **">
+ <return type="float" />
+ <argument index="0" name="right" type="float" />
+ <description>
+ </description>
+ </operator>
+ <operator name="operator **">
+ <return type="float" />
+ <argument index="0" name="right" type="int" />
+ <description>
+ </description>
+ </operator>
<operator name="operator +">
<return type="float" />
<argument index="0" name="right" type="float" />
diff --git a/doc/classes/int.xml b/doc/classes/int.xml
index 609291b69c..2eceba40fa 100644
--- a/doc/classes/int.xml
+++ b/doc/classes/int.xml
@@ -171,6 +171,18 @@
Multiplies two [int]s.
</description>
</operator>
+ <operator name="operator **">
+ <return type="float" />
+ <argument index="0" name="right" type="float" />
+ <description>
+ </description>
+ </operator>
+ <operator name="operator **">
+ <return type="int" />
+ <argument index="0" name="right" type="int" />
+ <description>
+ </description>
+ </operator>
<operator name="operator +">
<return type="String" />
<argument index="0" name="right" type="String" />
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index eba4cee33a..1b98699c44 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -1409,6 +1409,8 @@ def sanitize_operator_name(dirty_name, state): # type: (str, State) -> str
clear_name = "div"
elif clear_name == "%":
clear_name = "mod"
+ elif clear_name == "**":
+ clear_name = "pow"
elif clear_name == "unary+":
clear_name = "unplus"
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 62330d23ed..e96a2b2025 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -2320,6 +2320,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_operator(Expression
operation->operation = BinaryOpNode::OP_MODULO;
operation->variant_op = Variant::OP_MODULE;
break;
+ case GDScriptTokenizer::Token::STAR_STAR:
+ operation->operation = BinaryOpNode::OP_POWER;
+ operation->variant_op = Variant::OP_POWER;
+ break;
case GDScriptTokenizer::Token::LESS_LESS:
operation->operation = BinaryOpNode::OP_BIT_LEFT_SHIFT;
operation->variant_op = Variant::OP_SHIFT_LEFT;
@@ -2483,6 +2487,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_assignment(ExpressionNode
assignment->operation = AssignmentNode::OP_MULTIPLICATION;
assignment->variant_op = Variant::OP_MULTIPLY;
break;
+ case GDScriptTokenizer::Token::STAR_STAR_EQUAL:
+ assignment->operation = AssignmentNode::OP_POWER;
+ assignment->variant_op = Variant::OP_POWER;
+ break;
case GDScriptTokenizer::Token::SLASH_EQUAL:
assignment->operation = AssignmentNode::OP_DIVISION;
assignment->variant_op = Variant::OP_DIVIDE;
@@ -3265,6 +3273,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION_SUBTRACTION }, // PLUS,
{ &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION_SUBTRACTION }, // MINUS,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // STAR,
+ { nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // STAR_STAR,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // SLASH,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // PERCENT,
// Assignment
@@ -3272,6 +3281,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // PLUS_EQUAL,
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // MINUS_EQUAL,
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // STAR_EQUAL,
+ { nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // STAR_STAR_EQUAL,
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // SLASH_EQUAL,
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // PERCENT_EQUAL,
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // LESS_LESS_EQUAL,
@@ -3896,6 +3906,9 @@ void GDScriptParser::TreePrinter::print_assignment(AssignmentNode *p_assignment)
case AssignmentNode::OP_MODULO:
push_text("%");
break;
+ case AssignmentNode::OP_POWER:
+ push_text("**");
+ break;
case AssignmentNode::OP_BIT_SHIFT_LEFT:
push_text("<<");
break;
@@ -3944,6 +3957,9 @@ void GDScriptParser::TreePrinter::print_binary_op(BinaryOpNode *p_binary_op) {
case BinaryOpNode::OP_MODULO:
push_text(" % ");
break;
+ case BinaryOpNode::OP_POWER:
+ push_text(" ** ");
+ break;
case BinaryOpNode::OP_BIT_LEFT_SHIFT:
push_text(" << ");
break;
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 10474db02f..a9f407fbb5 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -360,6 +360,7 @@ public:
OP_MULTIPLICATION,
OP_DIVISION,
OP_MODULO,
+ OP_POWER,
OP_BIT_SHIFT_LEFT,
OP_BIT_SHIFT_RIGHT,
OP_BIT_AND,
@@ -393,6 +394,7 @@ public:
OP_MULTIPLICATION,
OP_DIVISION,
OP_MODULO,
+ OP_POWER,
OP_BIT_LEFT_SHIFT,
OP_BIT_RIGHT_SHIFT,
OP_BIT_AND,
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 63fad0d9bb..6c17afe939 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -67,6 +67,7 @@ static const char *token_names[] = {
"+", // PLUS,
"-", // MINUS,
"*", // STAR,
+ "**", // STAR_STAR,
"/", // SLASH,
"%", // PERCENT,
// Assignment
@@ -74,6 +75,7 @@ static const char *token_names[] = {
"+=", // PLUS_EQUAL,
"-=", // MINUS_EQUAL,
"*=", // STAR_EQUAL,
+ "**=", // STAR_STAR_EQUAL,
"/=", // SLASH_EQUAL,
"%=", // PERCENT_EQUAL,
"<<=", // LESS_LESS_EQUAL,
@@ -1403,6 +1405,14 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
if (_peek() == '=') {
_advance();
return make_token(Token::STAR_EQUAL);
+ } else if (_peek() == '*') {
+ if (_peek(1) == '=') {
+ _advance();
+ _advance(); // Advance both '*' and '='
+ return make_token(Token::STAR_STAR_EQUAL);
+ }
+ _advance();
+ return make_token(Token::STAR_STAR);
} else {
return make_token(Token::STAR);
}
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index abd090e381..75f9a7626e 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -78,6 +78,7 @@ public:
PLUS,
MINUS,
STAR,
+ STAR_STAR,
SLASH,
PERCENT,
// Assignment
@@ -85,6 +86,7 @@ public:
PLUS_EQUAL,
MINUS_EQUAL,
STAR_EQUAL,
+ STAR_STAR_EQUAL,
SLASH_EQUAL,
PERCENT_EQUAL,
LESS_LESS_EQUAL,