diff options
author | Yuri Roubinsky <chaosus89@gmail.com> | 2022-03-07 20:25:21 +0300 |
---|---|---|
committer | Yuri Rubinsky <chaosus89@gmail.com> | 2022-05-11 16:30:37 +0300 |
commit | dbd7a315074257bca834e1448b53a905ebb8dd8b (patch) | |
tree | a13d08663bc046cb445373b7828d0f3ac42cd867 | |
parent | 9963ae3553d059e4ac3b57c7a4cdc55d1a87d49a (diff) |
Implement exponential operator (**) to GDScript/Expressions
-rw-r--r-- | core/core_constants.cpp | 1 | ||||
-rw-r--r-- | core/extension/gdnative_interface.h | 1 | ||||
-rw-r--r-- | core/math/expression.cpp | 40 | ||||
-rw-r--r-- | core/math/expression.h | 1 | ||||
-rw-r--r-- | core/variant/variant.h | 1 | ||||
-rw-r--r-- | core/variant/variant_op.cpp | 6 | ||||
-rw-r--r-- | core/variant/variant_op.h | 18 | ||||
-rw-r--r-- | doc/classes/@GlobalScope.xml | 27 | ||||
-rw-r--r-- | doc/classes/float.xml | 12 | ||||
-rw-r--r-- | doc/classes/int.xml | 12 | ||||
-rwxr-xr-x | doc/tools/make_rst.py | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 16 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_tokenizer.cpp | 10 | ||||
-rw-r--r-- | modules/gdscript/gdscript_tokenizer.h | 2 |
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]<<[/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]>>[/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]&[/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]&&[/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, |