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.cpp171
1 files changed, 127 insertions, 44 deletions
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 05f2c8dac9..97dc175d94 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -37,10 +37,6 @@
#include "core/os/os.h"
#include "core/variant/variant_parser.h"
-static bool _is_number(char32_t 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++])
@@ -88,7 +84,7 @@ Error Expression::_get_token(Token &r_token) {
r_token.type = TK_INPUT;
int index = 0;
do {
- if (!_is_number(expression[str_ofs])) {
+ if (!is_digit(expression[str_ofs])) {
_set_error("Expected number after '$'");
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
@@ -97,7 +93,7 @@ Error Expression::_get_token(Token &r_token) {
index += expression[str_ofs] - '0';
str_ofs++;
- } while (_is_number(expression[str_ofs]));
+ } while (is_digit(expression[str_ofs]));
r_token.value = index;
return OK;
@@ -159,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 '%': {
@@ -197,6 +198,7 @@ Error Expression::_get_token(Token &r_token) {
case '\'':
case '"': {
String str;
+ char32_t prev = 0;
while (true) {
char32_t ch = GET_CHAR();
@@ -234,9 +236,11 @@ Error Expression::_get_token(Token &r_token) {
case 'r':
res = 13;
break;
+ case 'U':
case 'u': {
- // hex number
- for (int j = 0; j < 4; j++) {
+ // Hexadecimal sequence.
+ int hex_len = (next == 'U') ? 6 : 4;
+ for (int j = 0; j < hex_len; j++) {
char32_t c = GET_CHAR();
if (c == 0) {
@@ -244,13 +248,13 @@ Error Expression::_get_token(Token &r_token) {
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- if (!(_is_number(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
+ if (!is_hex_digit(c)) {
_set_error("Malformed hex constant in string");
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
char32_t v;
- if (_is_number(c)) {
+ if (is_digit(c)) {
v = c - '0';
} else if (c >= 'a' && c <= 'f') {
v = c - 'a';
@@ -273,12 +277,46 @@ Error Expression::_get_token(Token &r_token) {
} break;
}
+ // Parse UTF-16 pair.
+ if ((res & 0xfffffc00) == 0xd800) {
+ if (prev == 0) {
+ prev = res;
+ continue;
+ } else {
+ _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ } else if ((res & 0xfffffc00) == 0xdc00) {
+ if (prev == 0) {
+ _set_error("Invalid UTF-16 sequence in string, unpaired trail surrogate");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ } else {
+ res = (prev << 10UL) + res - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ prev = 0;
+ }
+ }
+ if (prev != 0) {
+ _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
str += res;
-
} else {
+ if (prev != 0) {
+ _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
str += ch;
}
}
+ if (prev != 0) {
+ _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
+ r_token.type = TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
r_token.type = TK_CONSTANT;
r_token.value = str;
@@ -291,39 +329,67 @@ Error Expression::_get_token(Token &r_token) {
}
char32_t next_char = (str_ofs >= expression.length()) ? 0 : expression[str_ofs];
- if (_is_number(cchar) || (cchar == '.' && _is_number(next_char))) {
+ if (is_digit(cchar) || (cchar == '.' && is_digit(next_char))) {
//a number
String num;
#define READING_SIGN 0
#define READING_INT 1
-#define READING_DEC 2
-#define READING_EXP 3
-#define READING_DONE 4
+#define READING_HEX 2
+#define READING_BIN 3
+#define READING_DEC 4
+#define READING_EXP 5
+#define READING_DONE 6
int reading = READING_INT;
char32_t c = cchar;
bool exp_sign = false;
bool exp_beg = false;
+ bool bin_beg = false;
+ bool hex_beg = false;
bool is_float = false;
+ bool is_first_char = true;
while (true) {
switch (reading) {
case READING_INT: {
- if (_is_number(c)) {
- //pass
+ if (is_digit(c)) {
+ if (is_first_char && c == '0') {
+ if (next_char == 'b') {
+ reading = READING_BIN;
+ } else if (next_char == 'x') {
+ reading = READING_HEX;
+ }
+ }
} else if (c == '.') {
reading = READING_DEC;
is_float = true;
} else if (c == 'e') {
reading = READING_EXP;
+ is_float = true;
} else {
reading = READING_DONE;
}
} break;
+ case READING_BIN: {
+ if (bin_beg && !is_binary_digit(c)) {
+ reading = READING_DONE;
+ } else if (c == 'b') {
+ bin_beg = true;
+ }
+
+ } break;
+ case READING_HEX: {
+ if (hex_beg && !is_hex_digit(c)) {
+ reading = READING_DONE;
+ } else if (c == 'x') {
+ hex_beg = true;
+ }
+
+ } break;
case READING_DEC: {
- if (_is_number(c)) {
+ if (is_digit(c)) {
} else if (c == 'e') {
reading = READING_EXP;
@@ -333,13 +399,10 @@ Error Expression::_get_token(Token &r_token) {
} break;
case READING_EXP: {
- if (_is_number(c)) {
+ if (is_digit(c)) {
exp_beg = true;
} else if ((c == '-' || c == '+') && !exp_sign && !exp_beg) {
- if (c == '-') {
- is_float = true;
- }
exp_sign = true;
} else {
@@ -353,6 +416,7 @@ Error Expression::_get_token(Token &r_token) {
}
num += String::chr(c);
c = GET_CHAR();
+ is_first_char = false;
}
str_ofs--;
@@ -361,16 +425,20 @@ Error Expression::_get_token(Token &r_token) {
if (is_float) {
r_token.value = num.to_float();
+ } else if (bin_beg) {
+ r_token.value = num.bin_to_int();
+ } else if (hex_beg) {
+ r_token.value = num.hex_to_int();
} else {
r_token.value = num.to_int();
}
return OK;
- } else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') {
+ } else if (is_ascii_char(cchar) || is_underscore(cchar)) {
String id;
bool first = true;
- while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && _is_number(cchar))) {
+ while (is_ascii_char(cchar) || is_underscore(cchar) || (!first && is_digit(cchar))) {
id += String::chr(cchar);
cchar = GET_CHAR();
first = false;
@@ -410,6 +478,14 @@ Error Expression::_get_token(Token &r_token) {
} else if (id == "self") {
r_token.type = TK_SELF;
} else {
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ if (id == Variant::get_type_name(Variant::Type(i))) {
+ r_token.type = TK_BASIC_TYPE;
+ r_token.value = i;
+ return OK;
+ }
+ }
+
if (Variant::has_utility_function(id)) {
r_token.type = TK_BUILTIN_FUNC;
r_token.value = id;
@@ -471,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",
@@ -942,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;
@@ -995,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:
@@ -1031,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));
@@ -1087,7 +1170,7 @@ Expression::ENode *Expression::_parse_expression() {
op->nodes[1] = nullptr;
expression.write[i].is_op = false;
expression.write[i].node = op;
- expression.remove(i + 1);
+ expression.remove_at(i + 1);
}
} else {
@@ -1119,8 +1202,8 @@ Expression::ENode *Expression::_parse_expression() {
//replace all 3 nodes by this operator and make it an expression
expression.write[next_op - 1].node = op;
- expression.remove(next_op);
- expression.remove(next_op);
+ expression.remove_at(next_op);
+ expression.remove_at(next_op);
}
}
@@ -1369,7 +1452,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
}
Callable::CallError ce;
- base.call(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
+ base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = vformat(RTR("On call to '%s':"), String(call->method));