Skip to content

Commit

Permalink
Merge pull request #58873 from Chaosus/power_op
Browse files Browse the repository at this point in the history
Implement exponential operator (**) to GDScript/Expressions
  • Loading branch information
akien-mga authored May 11, 2022
2 parents 0b0beae + dbd7a31 commit d68c355
Show file tree
Hide file tree
Showing 15 changed files with 125 additions and 26 deletions.
1 change: 1 addition & 0 deletions core/core_constants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions core/extension/gdnative_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
40 changes: 26 additions & 14 deletions core/math/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 '%': {
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
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:
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));
Expand Down
1 change: 1 addition & 0 deletions core/math/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class Expression : public RefCounted {
TK_OP_MUL,
TK_OP_DIV,
TK_OP_MOD,
TK_OP_POW,
TK_OP_SHIFT_LEFT,
TK_OP_SHIFT_RIGHT,
TK_OP_BIT_AND,
Expand Down
1 change: 1 addition & 0 deletions core/variant/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ class Variant {
OP_NEGATE,
OP_POSITIVE,
OP_MODULE,
OP_POWER,
//bitwise
OP_SHIFT_LEFT,
OP_SHIFT_RIGHT,
Expand Down
6 changes: 6 additions & 0 deletions core/variant/variant_op.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -929,6 +934,7 @@ static const char *_op_names[Variant::OP_MAX] = {
"unary-",
"unary+",
"%",
"**",
"<<",
">>",
"&",
Expand Down
18 changes: 18 additions & 0 deletions core/variant/variant_op.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,24 @@ class OperatorEvaluatorMul {
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>
class OperatorEvaluatorXForm {
public:
Expand Down
27 changes: 15 additions & 12 deletions doc/classes/@GlobalScope.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
12 changes: 12 additions & 0 deletions doc/classes/float.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
12 changes: 12 additions & 0 deletions doc/classes/int.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
2 changes: 2 additions & 0 deletions doc/tools/make_rst.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
16 changes: 16 additions & 0 deletions modules/gdscript/gdscript_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -3265,13 +3273,15 @@ 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
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // EQUAL,
{ 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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions modules/gdscript/gdscript_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ class GDScriptParser {
OP_MULTIPLICATION,
OP_DIVISION,
OP_MODULO,
OP_POWER,
OP_BIT_SHIFT_LEFT,
OP_BIT_SHIFT_RIGHT,
OP_BIT_AND,
Expand Down Expand Up @@ -393,6 +394,7 @@ class GDScriptParser {
OP_MULTIPLICATION,
OP_DIVISION,
OP_MODULO,
OP_POWER,
OP_BIT_LEFT_SHIFT,
OP_BIT_RIGHT_SHIFT,
OP_BIT_AND,
Expand Down
10 changes: 10 additions & 0 deletions modules/gdscript/gdscript_tokenizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,15 @@ static const char *token_names[] = {
"+", // PLUS,
"-", // MINUS,
"*", // STAR,
"**", // STAR_STAR,
"/", // SLASH,
"%", // PERCENT,
// Assignment
"=", // EQUAL,
"+=", // PLUS_EQUAL,
"-=", // MINUS_EQUAL,
"*=", // STAR_EQUAL,
"**=", // STAR_STAR_EQUAL,
"/=", // SLASH_EQUAL,
"%=", // PERCENT_EQUAL,
"<<=", // LESS_LESS_EQUAL,
Expand Down Expand Up @@ -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);
}
Expand Down
Loading

0 comments on commit d68c355

Please sign in to comment.