Browse Source

Implement exponential operator (**) to GDScript/Expressions

Yuri Roubinsky 3 years ago
parent
commit
dbd7a31507

+ 1 - 0
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_NEGATE", Variant::OP_NEGATE);
 	BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_POSITIVE", Variant::OP_POSITIVE);
 	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_MODULE", Variant::OP_MODULE);
+	BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_POWER", Variant::OP_POWER);
 	//bitwise
 	//bitwise
 	BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT);
 	BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT);
 	BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT);
 	BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT);

+ 1 - 0
core/extension/gdnative_interface.h

@@ -114,6 +114,7 @@ typedef enum {
 	GDNATIVE_VARIANT_OP_NEGATE,
 	GDNATIVE_VARIANT_OP_NEGATE,
 	GDNATIVE_VARIANT_OP_POSITIVE,
 	GDNATIVE_VARIANT_OP_POSITIVE,
 	GDNATIVE_VARIANT_OP_MODULE,
 	GDNATIVE_VARIANT_OP_MODULE,
+	GDNATIVE_VARIANT_OP_POWER,
 	/* bitwise */
 	/* bitwise */
 	GDNATIVE_VARIANT_OP_SHIFT_LEFT,
 	GDNATIVE_VARIANT_OP_SHIFT_LEFT,
 	GDNATIVE_VARIANT_OP_SHIFT_RIGHT,
 	GDNATIVE_VARIANT_OP_SHIFT_RIGHT,

+ 26 - 14
core/math/expression.cpp

@@ -155,7 +155,12 @@ Error Expression::_get_token(Token &r_token) {
 				return OK;
 				return OK;
 			}
 			}
 			case '*': {
 			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;
 				return OK;
 			}
 			}
 			case '%': {
 			case '%': {
@@ -542,6 +547,7 @@ const char *Expression::token_name[TK_MAX] = {
 	"OP MUL",
 	"OP MUL",
 	"OP DIV",
 	"OP DIV",
 	"OP MOD",
 	"OP MOD",
+	"OP POW",
 	"OP SHIFT LEFT",
 	"OP SHIFT LEFT",
 	"OP SHIFT RIGHT",
 	"OP SHIFT RIGHT",
 	"OP BIT AND",
 	"OP BIT AND",
@@ -1013,6 +1019,9 @@ Expression::ENode *Expression::_parse_expression() {
 			case TK_OP_MOD:
 			case TK_OP_MOD:
 				op = Variant::OP_MODULE;
 				op = Variant::OP_MODULE;
 				break;
 				break;
+			case TK_OP_POW:
+				op = Variant::OP_POWER;
+				break;
 			case TK_OP_SHIFT_LEFT:
 			case TK_OP_SHIFT_LEFT:
 				op = Variant::OP_SHIFT_LEFT;
 				op = Variant::OP_SHIFT_LEFT;
 				break;
 				break;
@@ -1066,35 +1075,38 @@ Expression::ENode *Expression::_parse_expression() {
 			bool unary = false;
 			bool unary = false;
 
 
 			switch (expression[i].op) {
 			switch (expression[i].op) {
-				case Variant::OP_BIT_NEGATE:
+				case Variant::OP_POWER:
 					priority = 0;
 					priority = 0;
+					break;
+				case Variant::OP_BIT_NEGATE:
+					priority = 1;
 					unary = true;
 					unary = true;
 					break;
 					break;
 				case Variant::OP_NEGATE:
 				case Variant::OP_NEGATE:
-					priority = 1;
+					priority = 2;
 					unary = true;
 					unary = true;
 					break;
 					break;
 				case Variant::OP_MULTIPLY:
 				case Variant::OP_MULTIPLY:
 				case Variant::OP_DIVIDE:
 				case Variant::OP_DIVIDE:
 				case Variant::OP_MODULE:
 				case Variant::OP_MODULE:
-					priority = 2;
+					priority = 3;
 					break;
 					break;
 				case Variant::OP_ADD:
 				case Variant::OP_ADD:
 				case Variant::OP_SUBTRACT:
 				case Variant::OP_SUBTRACT:
-					priority = 3;
+					priority = 4;
 					break;
 					break;
 				case Variant::OP_SHIFT_LEFT:
 				case Variant::OP_SHIFT_LEFT:
 				case Variant::OP_SHIFT_RIGHT:
 				case Variant::OP_SHIFT_RIGHT:
-					priority = 4;
+					priority = 5;
 					break;
 					break;
 				case Variant::OP_BIT_AND:
 				case Variant::OP_BIT_AND:
-					priority = 5;
+					priority = 6;
 					break;
 					break;
 				case Variant::OP_BIT_XOR:
 				case Variant::OP_BIT_XOR:
-					priority = 6;
+					priority = 7;
 					break;
 					break;
 				case Variant::OP_BIT_OR:
 				case Variant::OP_BIT_OR:
-					priority = 7;
+					priority = 8;
 					break;
 					break;
 				case Variant::OP_LESS:
 				case Variant::OP_LESS:
 				case Variant::OP_LESS_EQUAL:
 				case Variant::OP_LESS_EQUAL:
@@ -1102,20 +1114,20 @@ Expression::ENode *Expression::_parse_expression() {
 				case Variant::OP_GREATER_EQUAL:
 				case Variant::OP_GREATER_EQUAL:
 				case Variant::OP_EQUAL:
 				case Variant::OP_EQUAL:
 				case Variant::OP_NOT_EQUAL:
 				case Variant::OP_NOT_EQUAL:
-					priority = 8;
+					priority = 9;
 					break;
 					break;
 				case Variant::OP_IN:
 				case Variant::OP_IN:
-					priority = 10;
+					priority = 11;
 					break;
 					break;
 				case Variant::OP_NOT:
 				case Variant::OP_NOT:
-					priority = 11;
+					priority = 12;
 					unary = true;
 					unary = true;
 					break;
 					break;
 				case Variant::OP_AND:
 				case Variant::OP_AND:
-					priority = 12;
+					priority = 13;
 					break;
 					break;
 				case Variant::OP_OR:
 				case Variant::OP_OR:
-					priority = 13;
+					priority = 14;
 					break;
 					break;
 				default: {
 				default: {
 					_set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op));
 					_set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op));

+ 1 - 0
core/math/expression.h

@@ -85,6 +85,7 @@ private:
 		TK_OP_MUL,
 		TK_OP_MUL,
 		TK_OP_DIV,
 		TK_OP_DIV,
 		TK_OP_MOD,
 		TK_OP_MOD,
+		TK_OP_POW,
 		TK_OP_SHIFT_LEFT,
 		TK_OP_SHIFT_LEFT,
 		TK_OP_SHIFT_RIGHT,
 		TK_OP_SHIFT_RIGHT,
 		TK_OP_BIT_AND,
 		TK_OP_BIT_AND,

+ 1 - 0
core/variant/variant.h

@@ -473,6 +473,7 @@ public:
 		OP_NEGATE,
 		OP_NEGATE,
 		OP_POSITIVE,
 		OP_POSITIVE,
 		OP_MODULE,
 		OP_MODULE,
+		OP_POWER,
 		//bitwise
 		//bitwise
 		OP_SHIFT_LEFT,
 		OP_SHIFT_LEFT,
 		OP_SHIFT_RIGHT,
 		OP_SHIFT_RIGHT,

+ 6 - 0
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<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<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<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<double, double>>(Variant::OP_NEGATE, Variant::FLOAT, Variant::NIL);
 	register_op<OperatorEvaluatorNeg<Vector2, Vector2>>(Variant::OP_NEGATE, Variant::VECTOR2, 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-",
 	"unary+",
 	"unary+",
 	"%",
 	"%",
+	"**",
 	"<<",
 	"<<",
 	">>",
 	">>",
 	"&",
 	"&",

+ 18 - 0
core/variant/variant_op.h

@@ -91,6 +91,24 @@ public:
 	static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
 	static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
 };
 };
 
 
+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>
 template <class R, class A, class B>
 class OperatorEvaluatorXForm {
 class OperatorEvaluatorXForm {
 public:
 public:

+ 15 - 12
doc/classes/@GlobalScope.xml

@@ -2799,40 +2799,43 @@
 		<constant name="OP_MODULE" value="12" enum="Variant.Operator">
 		<constant name="OP_MODULE" value="12" enum="Variant.Operator">
 			Remainder/modulo operator ([code]%[/code]).
 			Remainder/modulo operator ([code]%[/code]).
 		</constant>
 		</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]).
 			Left shift operator ([code]&lt;&lt;[/code]).
 		</constant>
 		</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]).
 			Right shift operator ([code]&gt;&gt;[/code]).
 		</constant>
 		</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]).
 			Bitwise AND operator ([code]&amp;[/code]).
 		</constant>
 		</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]).
 			Bitwise OR operator ([code]|[/code]).
 		</constant>
 		</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]).
 			Bitwise XOR operator ([code]^[/code]).
 		</constant>
 		</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]).
 			Bitwise NOT operator ([code]~[/code]).
 		</constant>
 		</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]).
 			Logical AND operator ([code]and[/code] or [code]&amp;&amp;[/code]).
 		</constant>
 		</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]).
 			Logical OR operator ([code]or[/code] or [code]||[/code]).
 		</constant>
 		</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).
 			Logical XOR operator (not implemented in GDScript).
 		</constant>
 		</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]).
 			Logical NOT operator ([code]not[/code] or [code]![/code]).
 		</constant>
 		</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]).
 			Logical IN operator ([code]in[/code]).
 		</constant>
 		</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.
 			Represents the size of the [enum Variant.Operator] enum.
 		</constant>
 		</constant>
 	</constants>
 	</constants>

+ 12 - 0
doc/classes/float.xml

@@ -124,6 +124,18 @@
 				Multiplies a [float] and an [int]. The result is a [float].
 				Multiplies a [float] and an [int]. The result is a [float].
 			</description>
 			</description>
 		</operator>
 		</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 +">
 		<operator name="operator +">
 			<return type="float" />
 			<return type="float" />
 			<argument index="0" name="right" type="float" />
 			<argument index="0" name="right" type="float" />

+ 12 - 0
doc/classes/int.xml

@@ -171,6 +171,18 @@
 				Multiplies two [int]s.
 				Multiplies two [int]s.
 			</description>
 			</description>
 		</operator>
 		</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 +">
 		<operator name="operator +">
 			<return type="String" />
 			<return type="String" />
 			<argument index="0" name="right" type="String" />
 			<argument index="0" name="right" type="String" />

+ 2 - 0
doc/tools/make_rst.py

@@ -1409,6 +1409,8 @@ def sanitize_operator_name(dirty_name, state):  # type: (str, State) -> str
         clear_name = "div"
         clear_name = "div"
     elif clear_name == "%":
     elif clear_name == "%":
         clear_name = "mod"
         clear_name = "mod"
+    elif clear_name == "**":
+        clear_name = "pow"
 
 
     elif clear_name == "unary+":
     elif clear_name == "unary+":
         clear_name = "unplus"
         clear_name = "unplus"

+ 16 - 0
modules/gdscript/gdscript_parser.cpp

@@ -2320,6 +2320,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_operator(Expression
 			operation->operation = BinaryOpNode::OP_MODULO;
 			operation->operation = BinaryOpNode::OP_MODULO;
 			operation->variant_op = Variant::OP_MODULE;
 			operation->variant_op = Variant::OP_MODULE;
 			break;
 			break;
+		case GDScriptTokenizer::Token::STAR_STAR:
+			operation->operation = BinaryOpNode::OP_POWER;
+			operation->variant_op = Variant::OP_POWER;
+			break;
 		case GDScriptTokenizer::Token::LESS_LESS:
 		case GDScriptTokenizer::Token::LESS_LESS:
 			operation->operation = BinaryOpNode::OP_BIT_LEFT_SHIFT;
 			operation->operation = BinaryOpNode::OP_BIT_LEFT_SHIFT;
 			operation->variant_op = Variant::OP_SHIFT_LEFT;
 			operation->variant_op = Variant::OP_SHIFT_LEFT;
@@ -2483,6 +2487,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_assignment(ExpressionNode
 			assignment->operation = AssignmentNode::OP_MULTIPLICATION;
 			assignment->operation = AssignmentNode::OP_MULTIPLICATION;
 			assignment->variant_op = Variant::OP_MULTIPLY;
 			assignment->variant_op = Variant::OP_MULTIPLY;
 			break;
 			break;
+		case GDScriptTokenizer::Token::STAR_STAR_EQUAL:
+			assignment->operation = AssignmentNode::OP_POWER;
+			assignment->variant_op = Variant::OP_POWER;
+			break;
 		case GDScriptTokenizer::Token::SLASH_EQUAL:
 		case GDScriptTokenizer::Token::SLASH_EQUAL:
 			assignment->operation = AssignmentNode::OP_DIVISION;
 			assignment->operation = AssignmentNode::OP_DIVISION;
 			assignment->variant_op = Variant::OP_DIVIDE;
 			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 }, // PLUS,
 		{ &GDScriptParser::parse_unary_operator,         	&GDScriptParser::parse_binary_operator,      	PREC_ADDITION_SUBTRACTION }, // MINUS,
 		{ &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,
+		{ nullptr,                                          &GDScriptParser::parse_binary_operator,      	PREC_FACTOR }, // STAR_STAR,
 		{ nullptr,                                          &GDScriptParser::parse_binary_operator,      	PREC_FACTOR }, // SLASH,
 		{ nullptr,                                          &GDScriptParser::parse_binary_operator,      	PREC_FACTOR }, // SLASH,
 		{ nullptr,                                          &GDScriptParser::parse_binary_operator,      	PREC_FACTOR }, // PERCENT,
 		{ nullptr,                                          &GDScriptParser::parse_binary_operator,      	PREC_FACTOR }, // PERCENT,
 		// Assignment
 		// 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 }, // PLUS_EQUAL,
 		{ nullptr,                                          &GDScriptParser::parse_assignment,           	PREC_ASSIGNMENT }, // MINUS_EQUAL,
 		{ nullptr,                                          &GDScriptParser::parse_assignment,           	PREC_ASSIGNMENT }, // MINUS_EQUAL,
 		{ nullptr,                                          &GDScriptParser::parse_assignment,           	PREC_ASSIGNMENT }, // STAR_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 }, // SLASH_EQUAL,
 		{ nullptr,                                          &GDScriptParser::parse_assignment,           	PREC_ASSIGNMENT }, // PERCENT_EQUAL,
 		{ nullptr,                                          &GDScriptParser::parse_assignment,           	PREC_ASSIGNMENT }, // PERCENT_EQUAL,
 		{ nullptr,                                          &GDScriptParser::parse_assignment,           	PREC_ASSIGNMENT }, // LESS_LESS_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:
 		case AssignmentNode::OP_MODULO:
 			push_text("%");
 			push_text("%");
 			break;
 			break;
+		case AssignmentNode::OP_POWER:
+			push_text("**");
+			break;
 		case AssignmentNode::OP_BIT_SHIFT_LEFT:
 		case AssignmentNode::OP_BIT_SHIFT_LEFT:
 			push_text("<<");
 			push_text("<<");
 			break;
 			break;
@@ -3944,6 +3957,9 @@ void GDScriptParser::TreePrinter::print_binary_op(BinaryOpNode *p_binary_op) {
 		case BinaryOpNode::OP_MODULO:
 		case BinaryOpNode::OP_MODULO:
 			push_text(" % ");
 			push_text(" % ");
 			break;
 			break;
+		case BinaryOpNode::OP_POWER:
+			push_text(" ** ");
+			break;
 		case BinaryOpNode::OP_BIT_LEFT_SHIFT:
 		case BinaryOpNode::OP_BIT_LEFT_SHIFT:
 			push_text(" << ");
 			push_text(" << ");
 			break;
 			break;

+ 2 - 0
modules/gdscript/gdscript_parser.h

@@ -360,6 +360,7 @@ public:
 			OP_MULTIPLICATION,
 			OP_MULTIPLICATION,
 			OP_DIVISION,
 			OP_DIVISION,
 			OP_MODULO,
 			OP_MODULO,
+			OP_POWER,
 			OP_BIT_SHIFT_LEFT,
 			OP_BIT_SHIFT_LEFT,
 			OP_BIT_SHIFT_RIGHT,
 			OP_BIT_SHIFT_RIGHT,
 			OP_BIT_AND,
 			OP_BIT_AND,
@@ -393,6 +394,7 @@ public:
 			OP_MULTIPLICATION,
 			OP_MULTIPLICATION,
 			OP_DIVISION,
 			OP_DIVISION,
 			OP_MODULO,
 			OP_MODULO,
+			OP_POWER,
 			OP_BIT_LEFT_SHIFT,
 			OP_BIT_LEFT_SHIFT,
 			OP_BIT_RIGHT_SHIFT,
 			OP_BIT_RIGHT_SHIFT,
 			OP_BIT_AND,
 			OP_BIT_AND,

+ 10 - 0
modules/gdscript/gdscript_tokenizer.cpp

@@ -67,6 +67,7 @@ static const char *token_names[] = {
 	"+", // PLUS,
 	"+", // PLUS,
 	"-", // MINUS,
 	"-", // MINUS,
 	"*", // STAR,
 	"*", // STAR,
+	"**", // STAR_STAR,
 	"/", // SLASH,
 	"/", // SLASH,
 	"%", // PERCENT,
 	"%", // PERCENT,
 	// Assignment
 	// Assignment
@@ -74,6 +75,7 @@ static const char *token_names[] = {
 	"+=", // PLUS_EQUAL,
 	"+=", // PLUS_EQUAL,
 	"-=", // MINUS_EQUAL,
 	"-=", // MINUS_EQUAL,
 	"*=", // STAR_EQUAL,
 	"*=", // STAR_EQUAL,
+	"**=", // STAR_STAR_EQUAL,
 	"/=", // SLASH_EQUAL,
 	"/=", // SLASH_EQUAL,
 	"%=", // PERCENT_EQUAL,
 	"%=", // PERCENT_EQUAL,
 	"<<=", // LESS_LESS_EQUAL,
 	"<<=", // LESS_LESS_EQUAL,
@@ -1403,6 +1405,14 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
 			if (_peek() == '=') {
 			if (_peek() == '=') {
 				_advance();
 				_advance();
 				return make_token(Token::STAR_EQUAL);
 				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 {
 			} else {
 				return make_token(Token::STAR);
 				return make_token(Token::STAR);
 			}
 			}

+ 2 - 0
modules/gdscript/gdscript_tokenizer.h

@@ -78,6 +78,7 @@ public:
 			PLUS,
 			PLUS,
 			MINUS,
 			MINUS,
 			STAR,
 			STAR,
+			STAR_STAR,
 			SLASH,
 			SLASH,
 			PERCENT,
 			PERCENT,
 			// Assignment
 			// Assignment
@@ -85,6 +86,7 @@ public:
 			PLUS_EQUAL,
 			PLUS_EQUAL,
 			MINUS_EQUAL,
 			MINUS_EQUAL,
 			STAR_EQUAL,
 			STAR_EQUAL,
+			STAR_STAR_EQUAL,
 			SLASH_EQUAL,
 			SLASH_EQUAL,
 			PERCENT_EQUAL,
 			PERCENT_EQUAL,
 			LESS_LESS_EQUAL,
 			LESS_LESS_EQUAL,