diff --git a/core/core_constants.cpp b/core/core_constants.cpp index 2a514b68d8a..a53929a3aff 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 36d51ff2b9a..98976b29f68 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 9dd12574745..97dc175d944 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,56 +1075,59 @@ 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; - break; - case Variant::OP_BIT_AND: priority = 5; break; - case Variant::OP_BIT_XOR: + case Variant::OP_BIT_AND: priority = 6; break; - case Variant::OP_BIT_OR: + case Variant::OP_BIT_XOR: priority = 7; break; + case Variant::OP_BIT_OR: + priority = 8; + break; case Variant::OP_LESS: case Variant::OP_LESS_EQUAL: case Variant::OP_GREATER: 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 d43cc4091a5..6ea3c1611f1 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 475bf7158d6..726ba120b59 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 35e0319aa3a..adace2b5345 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -361,6 +361,11 @@ void Variant::_register_variant_operators() { register_op>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_VECTOR3_ARRAY); register_op>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_COLOR_ARRAY); + register_op>(Variant::OP_POWER, Variant::INT, Variant::INT); + register_op>(Variant::OP_POWER, Variant::INT, Variant::FLOAT); + register_op>(Variant::OP_POWER, Variant::FLOAT, Variant::FLOAT); + register_op>(Variant::OP_POWER, Variant::FLOAT, Variant::INT); + register_op>(Variant::OP_NEGATE, Variant::INT, Variant::NIL); register_op>(Variant::OP_NEGATE, Variant::FLOAT, Variant::NIL); register_op>(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 f72a92d31a3..3e9bae10786 100644 --- a/core/variant/variant_op.h +++ b/core/variant/variant_op.h @@ -91,6 +91,24 @@ public: static Variant::Type get_return_type() { return GetTypeInfo::VARIANT_TYPE; } }; +template +class OperatorEvaluatorPow { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr::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::get_ptr(r_ret) = R(Math::pow((double)*VariantGetInternalPtr::get_ptr(left), (double)*VariantGetInternalPtr::get_ptr(right))); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg::encode(R(Math::pow((double)PtrToArg::convert(left), (double)PtrToArg::convert(right))), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo::VARIANT_TYPE; } +}; + template class OperatorEvaluatorXForm { public: diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index a40b851efc5..5f81c808877 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2799,40 +2799,43 @@ Remainder/modulo operator ([code]%[/code]). - + + Power operator ([code]**[/code]). + + Left shift operator ([code]<<[/code]). - + Right shift operator ([code]>>[/code]). - + Bitwise AND operator ([code]&[/code]). - + Bitwise OR operator ([code]|[/code]). - + Bitwise XOR operator ([code]^[/code]). - + Bitwise NOT operator ([code]~[/code]). - + Logical AND operator ([code]and[/code] or [code]&&[/code]). - + Logical OR operator ([code]or[/code] or [code]||[/code]). - + Logical XOR operator (not implemented in GDScript). - + Logical NOT operator ([code]not[/code] or [code]![/code]). - + Logical IN operator ([code]in[/code]). - + Represents the size of the [enum Variant.Operator] enum. diff --git a/doc/classes/float.xml b/doc/classes/float.xml index 50961f9c7f0..f36b1fddeb3 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]. + + + + + + + + + + + + diff --git a/doc/classes/int.xml b/doc/classes/int.xml index 609291b69c6..2eceba40fa4 100644 --- a/doc/classes/int.xml +++ b/doc/classes/int.xml @@ -171,6 +171,18 @@ Multiplies two [int]s. + + + + + + + + + + + + diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index eba4cee33ac..1b98699c441 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 62330d23ed0..e96a2b20254 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 10474db02f9..a9f407fbb5a 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 63fad0d9bb6..6c17afe9394 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 abd090e3811..75f9a7626e0 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,