summaryrefslogtreecommitdiff
path: root/core/math/expression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/math/expression.cpp')
-rw-r--r--core/math/expression.cpp189
1 files changed, 118 insertions, 71 deletions
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index c0d7f874d2..46f81ce5c3 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -52,6 +52,7 @@ const char *Expression::func_name[Expression::FUNC_MAX] = {
"sqrt",
"fmod",
"fposmod",
+ "posmod",
"floor",
"ceil",
"round",
@@ -64,10 +65,14 @@ const char *Expression::func_name[Expression::FUNC_MAX] = {
"is_inf",
"ease",
"decimals",
+ "step_decimals",
"stepify",
"lerp",
+ "lerp_angle",
"inverse_lerp",
"range_lerp",
+ "smoothstep",
+ "move_toward",
"dectime",
"randomize",
"randi",
@@ -148,6 +153,7 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) {
case MATH_ISNAN:
case MATH_ISINF:
case MATH_DECIMALS:
+ case MATH_STEP_DECIMALS:
case MATH_SEED:
case MATH_RANDSEED:
case MATH_DEG2RAD:
@@ -164,13 +170,14 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) {
case TEXT_PRINTRAW:
case VAR_TO_STR:
case STR_TO_VAR:
- case VAR_TO_BYTES:
- case BYTES_TO_VAR:
case TYPE_EXISTS:
return 1;
+ case VAR_TO_BYTES:
+ case BYTES_TO_VAR:
case MATH_ATAN2:
case MATH_FMOD:
case MATH_FPOSMOD:
+ case MATH_POSMOD:
case MATH_POW:
case MATH_EASE:
case MATH_STEPIFY:
@@ -184,7 +191,10 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) {
case COLORN:
return 2;
case MATH_LERP:
+ case MATH_LERP_ANGLE:
case MATH_INVERSE_LERP:
+ case MATH_SMOOTHSTEP:
+ case MATH_MOVE_TOWARD:
case MATH_DECTIME:
case MATH_WRAP:
case MATH_WRAPF:
@@ -277,6 +287,12 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
VALIDATE_ARG_NUM(1);
*r_return = Math::fposmod((double)*p_inputs[0], (double)*p_inputs[1]);
} break;
+ case MATH_POSMOD: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ *r_return = Math::posmod((int)*p_inputs[0], (int)*p_inputs[1]);
+ } break;
case MATH_FLOOR: {
VALIDATE_ARG_NUM(0);
@@ -363,6 +379,11 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
VALIDATE_ARG_NUM(0);
*r_return = Math::step_decimals((double)*p_inputs[0]);
} break;
+ case MATH_STEP_DECIMALS: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::step_decimals((double)*p_inputs[0]);
+ } break;
case MATH_STEPIFY: {
VALIDATE_ARG_NUM(0);
@@ -376,6 +397,13 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
VALIDATE_ARG_NUM(2);
*r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
} break;
+ case MATH_LERP_ANGLE: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::lerp_angle((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
case MATH_INVERSE_LERP: {
VALIDATE_ARG_NUM(0);
@@ -392,6 +420,19 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
VALIDATE_ARG_NUM(4);
*r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]);
} break;
+ case MATH_SMOOTHSTEP: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::smoothstep((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
+ case MATH_MOVE_TOWARD: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::move_toward((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
case MATH_DECTIME: {
VALIDATE_ARG_NUM(0);
@@ -696,8 +737,9 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
case VAR_TO_BYTES: {
PoolByteArray barr;
+ bool full_objects = *p_inputs[1];
int len;
- Error err = encode_variant(*p_inputs[0], NULL, len);
+ Error err = encode_variant(*p_inputs[0], NULL, len, full_objects);
if (err) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
@@ -709,7 +751,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
barr.resize(len);
{
PoolByteArray::Write w = barr.write();
- encode_variant(*p_inputs[0], w.ptr(), len);
+ encode_variant(*p_inputs[0], w.ptr(), len, full_objects);
}
*r_return = barr;
} break;
@@ -724,10 +766,11 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
}
PoolByteArray varr = *p_inputs[0];
+ bool allow_objects = *p_inputs[1];
Variant ret;
{
PoolByteArray::Read r = varr.read();
- Error err = decode_variant(ret, r.ptr(), varr.size(), NULL);
+ Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects);
if (err != OK) {
r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format.");
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
@@ -750,29 +793,30 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
*r_return = String(color);
} break;
- default: {}
+ default: {
+ }
}
}
////////
+static bool _is_number(CharType c) {
+ return (c >= '0' && c <= '9');
+}
+
Error Expression::_get_token(Token &r_token) {
while (true) {
#define GET_CHAR() (str_ofs >= expression.length() ? 0 : expression[str_ofs++])
CharType cchar = GET_CHAR();
- if (cchar == 0) {
- r_token.type = TK_EOF;
- return OK;
- }
switch (cchar) {
case 0: {
r_token.type = TK_EOF;
return OK;
- } break;
+ };
case '{': {
r_token.type = TK_CURLY_BRACKET_OPEN;
@@ -813,17 +857,12 @@ Error Expression::_get_token(Token &r_token) {
r_token.type = TK_COLON;
return OK;
};
- case '.': {
-
- r_token.type = TK_PERIOD;
- return OK;
- };
case '$': {
r_token.type = TK_INPUT;
int index = 0;
do {
- if (expression[str_ofs] < '0' || expression[str_ofs] > '9') {
+ if (!_is_number(expression[str_ofs])) {
_set_error("Expected number after '$'");
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
@@ -832,7 +871,7 @@ Error Expression::_get_token(Token &r_token) {
index += expression[str_ofs] - '0';
str_ofs++;
- } while (expression[str_ofs] >= '0' && expression[str_ofs] <= '9');
+ } while (_is_number(expression[str_ofs]));
r_token.value = index;
return OK;
@@ -979,14 +1018,14 @@ Error Expression::_get_token(Token &r_token) {
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
+ if (!(_is_number(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
_set_error("Malformed hex constant in string");
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
CharType v;
- if (c >= '0' && c <= '9') {
+ if (_is_number(c)) {
v = c - '0';
} else if (c >= 'a' && c <= 'f') {
v = c - 'a';
@@ -1032,7 +1071,8 @@ Error Expression::_get_token(Token &r_token) {
break;
}
- if (cchar >= '0' && cchar <= '9') {
+ CharType next_char = (str_ofs >= expression.length()) ? 0 : expression[str_ofs];
+ if (_is_number(cchar) || (cchar == '.' && _is_number(next_char))) {
//a number
String num;
@@ -1053,7 +1093,7 @@ Error Expression::_get_token(Token &r_token) {
switch (reading) {
case READING_INT: {
- if (c >= '0' && c <= '9') {
+ if (_is_number(c)) {
//pass
} else if (c == '.') {
reading = READING_DEC;
@@ -1067,7 +1107,7 @@ Error Expression::_get_token(Token &r_token) {
} break;
case READING_DEC: {
- if (c >= '0' && c <= '9') {
+ if (_is_number(c)) {
} else if (c == 'e') {
reading = READING_EXP;
@@ -1079,7 +1119,7 @@ Error Expression::_get_token(Token &r_token) {
} break;
case READING_EXP: {
- if (c >= '0' && c <= '9') {
+ if (_is_number(c)) {
exp_beg = true;
} else if ((c == '-' || c == '+') && !exp_sign && !exp_beg) {
@@ -1114,7 +1154,7 @@ Error Expression::_get_token(Token &r_token) {
String id;
bool first = true;
- while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && cchar >= '0' && cchar <= '9')) {
+ while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && _is_number(cchar))) {
id += String::chr(cchar);
cchar = GET_CHAR();
@@ -1176,6 +1216,12 @@ Error Expression::_get_token(Token &r_token) {
}
return OK;
+
+ } else if (cchar == '.') {
+ // Handled down there as we support '.[0-9]' as numbers above
+ r_token.type = TK_PERIOD;
+ return OK;
+
} else {
_set_error("Unexpected character.");
r_token.type = TK_ERROR;
@@ -1183,6 +1229,7 @@ Error Expression::_get_token(Token &r_token) {
}
}
}
+#undef GET_CHAR
}
r_token.type = TK_ERROR;
@@ -1257,10 +1304,10 @@ Expression::ENode *Expression::_parse_expression() {
}
str_ofs = cofs; //revert
//parse an expression
- ENode *expr = _parse_expression();
- if (!expr)
+ ENode *subexpr = _parse_expression();
+ if (!subexpr)
return NULL;
- dn->dict.push_back(expr);
+ dn->dict.push_back(subexpr);
_get_token(tk);
if (tk.type != TK_COLON) {
@@ -1268,11 +1315,11 @@ Expression::ENode *Expression::_parse_expression() {
return NULL;
}
- expr = _parse_expression();
- if (!expr)
+ subexpr = _parse_expression();
+ if (!subexpr)
return NULL;
- dn->dict.push_back(expr);
+ dn->dict.push_back(subexpr);
cofs = str_ofs;
_get_token(tk);
@@ -1301,10 +1348,10 @@ Expression::ENode *Expression::_parse_expression() {
}
str_ofs = cofs; //revert
//parse an expression
- ENode *expr = _parse_expression();
- if (!expr)
+ ENode *subexpr = _parse_expression();
+ if (!subexpr)
return NULL;
- an->array.push_back(expr);
+ an->array.push_back(subexpr);
cofs = str_ofs;
_get_token(tk);
@@ -1348,25 +1395,25 @@ Expression::ENode *Expression::_parse_expression() {
while (true) {
- int cofs = str_ofs;
+ int cofs2 = str_ofs;
_get_token(tk);
if (tk.type == TK_PARENTHESIS_CLOSE) {
break;
}
- str_ofs = cofs; //revert
+ str_ofs = cofs2; //revert
//parse an expression
- ENode *expr = _parse_expression();
- if (!expr)
+ ENode *subexpr = _parse_expression();
+ if (!subexpr)
return NULL;
- func_call->arguments.push_back(expr);
+ func_call->arguments.push_back(subexpr);
- cofs = str_ofs;
+ cofs2 = str_ofs;
_get_token(tk);
if (tk.type == TK_COMMA) {
//all good
} else if (tk.type == TK_PARENTHESIS_CLOSE) {
- str_ofs = cofs;
+ str_ofs = cofs2;
} else {
_set_error("Expected ',' or ')'");
}
@@ -1437,11 +1484,11 @@ Expression::ENode *Expression::_parse_expression() {
}
str_ofs = cofs; //revert
//parse an expression
- ENode *expr = _parse_expression();
- if (!expr)
+ ENode *subexpr = _parse_expression();
+ if (!subexpr)
return NULL;
- constructor->arguments.push_back(expr);
+ constructor->arguments.push_back(subexpr);
cofs = str_ofs;
_get_token(tk);
@@ -1478,11 +1525,11 @@ Expression::ENode *Expression::_parse_expression() {
}
str_ofs = cofs; //revert
//parse an expression
- ENode *expr = _parse_expression();
- if (!expr)
+ ENode *subexpr = _parse_expression();
+ if (!subexpr)
return NULL;
- bifunc->arguments.push_back(expr);
+ bifunc->arguments.push_back(subexpr);
cofs = str_ofs;
_get_token(tk);
@@ -1577,25 +1624,25 @@ Expression::ENode *Expression::_parse_expression() {
while (true) {
- int cofs = str_ofs;
+ int cofs3 = str_ofs;
_get_token(tk);
if (tk.type == TK_PARENTHESIS_CLOSE) {
break;
}
- str_ofs = cofs; //revert
+ str_ofs = cofs3; //revert
//parse an expression
- ENode *expr = _parse_expression();
- if (!expr)
+ ENode *subexpr = _parse_expression();
+ if (!subexpr)
return NULL;
- func_call->arguments.push_back(expr);
+ func_call->arguments.push_back(subexpr);
- cofs = str_ofs;
+ cofs3 = str_ofs;
_get_token(tk);
if (tk.type == TK_COMMA) {
//all good
} else if (tk.type == TK_PARENTHESIS_CLOSE) {
- str_ofs = cofs;
+ str_ofs = cofs3;
} else {
_set_error("Expected ',' or ')'");
}
@@ -1662,7 +1709,8 @@ Expression::ENode *Expression::_parse_expression() {
case TK_OP_BIT_OR: op = Variant::OP_BIT_OR; break;
case TK_OP_BIT_XOR: op = Variant::OP_BIT_XOR; break;
case TK_OP_BIT_INVERT: op = Variant::OP_BIT_NEGATE; break;
- default: {};
+ default: {
+ };
}
if (op == Variant::OP_MAX) { //stop appending stuff
@@ -1759,7 +1807,7 @@ Expression::ENode *Expression::_parse_expression() {
if (next_op == -1) {
_set_error("Yet another parser bug....");
- ERR_FAIL_COND_V(next_op == -1, NULL);
+ ERR_FAIL_V(NULL);
}
// OK! create operator..
@@ -1895,7 +1943,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
Variant b;
if (op->nodes[1]) {
- bool ret = _execute(p_inputs, p_instance, op->nodes[1], b, r_error_str);
+ ret = _execute(p_inputs, p_instance, op->nodes[1], b, r_error_str);
if (ret)
return true;
}
@@ -2063,7 +2111,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
for (int i = 0; i < call->arguments.size(); i++) {
Variant value;
- bool ret = _execute(p_inputs, p_instance, call->arguments[i], value, r_error_str);
+ ret = _execute(p_inputs, p_instance, call->arguments[i], value, r_error_str);
if (ret)
return true;
@@ -2114,6 +2162,8 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu
Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) {
+ ERR_FAIL_COND_V_MSG(error_set, Variant(), "There was previously a parse error: " + error_str + ".");
+
execution_error = false;
Variant output;
String error_txt;
@@ -2121,10 +2171,7 @@ Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) {
if (err) {
execution_error = true;
error_str = error_txt;
- if (p_show_error) {
- ERR_EXPLAIN(error_str);
- ERR_FAIL_V(Variant());
- }
+ ERR_FAIL_COND_V_MSG(p_show_error, Variant(), error_str);
}
return output;
@@ -2146,13 +2193,13 @@ void Expression::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_error_text"), &Expression::get_error_text);
}
-Expression::Expression() {
- output_type = Variant::NIL;
- error_set = true;
- root = NULL;
- nodes = NULL;
- sequenced = false;
- execution_error = false;
+Expression::Expression() :
+ output_type(Variant::NIL),
+ sequenced(false),
+ error_set(true),
+ root(NULL),
+ nodes(NULL),
+ execution_error(false) {
}
Expression::~Expression() {