Codebase Enhancements and Performance Improvements

We've made several updates to improve our codebase and application performance.

- Clang format was applied for better readability and consistency, aiding other developers in understanding and contributing to the code.
- We resolved issues that were causing visual script compilation failure. The visual script now compiles successfully, ensuring application functionality.
- Broken sections within the codebase were fixed, improving overall stability.
- Built-in functions from the visual script were removed to simplify the code and enhance readability.
- Generic search performance was improved to provide faster results, enhancing user experience.
- Missing flow nodes were added to the Visual Script, ensuring all necessary components are present for correct functioning.

In an effort to streamline the codebase:

- `VisualScriptComment` class and related code were removed, reducing complexity and improving maintainability.
- Error messages were optimized for quicker feedback when errors occur.
- Licenses were updated to reflect recent changes, ensuring legal compliance and project transparency.
- The `get_global_name()` override in `visual_script.h` was fixed, and `TYPE_BUILTIN_FUNC` in `visual_script_expression.h` was removed, improving code functionality.
- Search logic was refactored to avoid double searching, enhancing performance.
- Documentation was updated to reflect recent changes, providing accurate information to users and developers.
- Property selection logic in `VisualScriptPropertySelector` was refactored for easier understanding and modification.
- Code was refactored to avoid variable shadowing, improving readability and reducing potential errors.
- `.clang-format` and `.clang-tidy` configuration files were added to ensure consistent code styling.

To make the code more robust and easier to understand:

- Variable names were corrected for clarity, and error handling in `visual_script_expression.cpp` was improved.
- Function and variable names were refactored for better readability and maintainability.
- Member editing logic in `VisualScriptEditor` was simplified.
- Name variables were updated to be unique, avoiding potential conflicts and errors.
- The `VisualScriptSubCall` class was refactored for simplicity and ease of understanding.

For macOS workflow:

- It was updated to use the latest version and correct path for installing Vulkan SDK, enabling the application to leverage the latest features and improvements from the Vulkan SDK.
- Mac Vulkan SDK was installed to support Vulkan-based functionalities.

Lastly, we made necessary changes to pass CI/CD tests, ensuring the code quality and stability of the application.
This commit is contained in:
K. S. Ernest (iFire) Lee
2023-08-15 09:34:34 -07:00
parent 40bdeebc80
commit 9a4df15d3e
78 changed files with 5752 additions and 6218 deletions

View File

@@ -1,36 +1,37 @@
/*************************************************************************/
/* visual_script_expression.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* 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 */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
/**************************************************************************/
/* visual_script_expression.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "visual_script_expression.h"
bool VisualScriptExpression::_set(const StringName &p_name, const Variant &p_value) {
bool VisualScriptExpression::_set(const StringName &p_name,
const Variant &p_value) {
if (String(p_name) == "expression") {
expression = p_value;
expression_dirty = true;
@@ -89,7 +90,8 @@ bool VisualScriptExpression::_set(const StringName &p_name, const Variant &p_val
return false;
}
bool VisualScriptExpression::_get(const StringName &p_name, Variant &r_ret) const {
bool VisualScriptExpression::_get(const StringName &p_name,
Variant &r_ret) const {
if (String(p_name) == "expression") {
r_ret = expression;
return true;
@@ -130,20 +132,27 @@ bool VisualScriptExpression::_get(const StringName &p_name, Variant &r_ret) cons
return false;
}
void VisualScriptExpression::_get_property_list(List<PropertyInfo> *p_list) const {
void VisualScriptExpression::_get_property_list(
List<PropertyInfo> *p_list) const {
String argt = "Any";
for (int i = 1; i < Variant::VARIANT_MAX; i++) {
argt += "," + Variant::get_type_name(Variant::Type(i));
}
p_list->push_back(PropertyInfo(Variant::STRING, "expression", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
p_list->push_back(PropertyInfo(Variant::INT, "out_type", PROPERTY_HINT_ENUM, argt));
p_list->push_back(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1"));
p_list->push_back(PropertyInfo(Variant::STRING, "expression",
PROPERTY_HINT_NONE, "",
PROPERTY_USAGE_NO_EDITOR));
p_list->push_back(
PropertyInfo(Variant::INT, "out_type", PROPERTY_HINT_ENUM, argt));
p_list->push_back(
PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1"));
p_list->push_back(PropertyInfo(Variant::BOOL, "sequenced"));
for (int i = 0; i < inputs.size(); i++) {
p_list->push_back(PropertyInfo(Variant::INT, "input_" + itos(i) + "/type", PROPERTY_HINT_ENUM, argt));
p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name"));
p_list->push_back(PropertyInfo(Variant::INT, "input_" + itos(i) + "/type",
PROPERTY_HINT_ENUM, argt));
p_list->push_back(
PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name"));
}
}
@@ -163,25 +172,21 @@ int VisualScriptExpression::get_input_value_port_count() const {
return inputs.size();
}
int VisualScriptExpression::get_output_value_port_count() const {
return 1;
}
int VisualScriptExpression::get_output_value_port_count() const { return 1; }
PropertyInfo VisualScriptExpression::get_input_value_port_info(int p_idx) const {
PropertyInfo
VisualScriptExpression::get_input_value_port_info(int p_idx) const {
return PropertyInfo(inputs[p_idx].type, inputs[p_idx].name);
}
PropertyInfo VisualScriptExpression::get_output_value_port_info(int p_idx) const {
PropertyInfo
VisualScriptExpression::get_output_value_port_info(int p_idx) const {
return PropertyInfo(output_type, "result");
}
String VisualScriptExpression::get_caption() const {
return RTR("Expression");
}
String VisualScriptExpression::get_caption() const { return RTR("Expression"); }
String VisualScriptExpression::get_text() const {
return expression;
}
String VisualScriptExpression::get_text() const { return expression; }
Error VisualScriptExpression::_get_token(Token &r_token) {
while (true) {
@@ -339,7 +344,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
} else if (ch == '"') {
break;
} else if (ch == '\\') {
//escaped characters...
// escaped characters...
char32_t next = GET_CHAR();
if (next == 0) {
@@ -412,29 +417,34 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
prev = res;
continue;
} else {
_set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
_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");
_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);
res =
(prev << 10UL) + res - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
prev = 0;
}
}
if (prev != 0) {
_set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
_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");
_set_error(
"Invalid UTF-16 sequence in string, unpaired lead surrogate");
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
@@ -442,7 +452,8 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
}
}
if (prev != 0) {
_set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
_set_error(
"Invalid UTF-16 sequence in string, unpaired lead surrogate");
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
@@ -458,7 +469,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
}
if (is_digit(cchar)) {
//a number
// a number
String num;
#define READING_SIGN 0
@@ -477,7 +488,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
switch (reading) {
case READING_INT: {
if (is_digit(c)) {
//pass
// pass
} else if (c == '.') {
reading = READING_DEC;
is_float = true;
@@ -536,13 +547,14 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
String id;
bool first = true;
while (is_ascii_char(cchar) || cchar == '_' || (!first && is_digit(cchar))) {
while (is_ascii_char(cchar) || cchar == '_' ||
(!first && is_digit(cchar))) {
id += String::chr(cchar);
cchar = GET_CHAR();
first = false;
}
str_ofs--; //go back one
str_ofs--; // go back one
if (id == "in") {
r_token.type = TK_OP_IN;
@@ -584,13 +596,6 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
}
}
VisualScriptBuiltinFunc::BuiltinFunc bifunc = VisualScriptBuiltinFunc::find_function(id);
if (bifunc != VisualScriptBuiltinFunc::FUNC_MAX) {
r_token.type = TK_BUILTIN_FUNC;
r_token.value = bifunc;
return OK;
}
r_token.type = TK_IDENTIFIER;
r_token.value = id;
}
@@ -609,8 +614,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
return ERR_PARSE_ERROR;
}
const char *VisualScriptExpression::token_name[TK_MAX] = {
"CURLY BRACKET OPEN",
const char *VisualScriptExpression::token_name[TK_MAX] = { "CURLY BRACKET OPEN",
"CURLY BRACKET CLOSE",
"BRACKET OPEN",
"BRACKET CLOSE",
@@ -646,14 +650,13 @@ const char *VisualScriptExpression::token_name[TK_MAX] = {
"OP BIT XOR",
"OP BIT INVERT",
"EOF",
"ERROR"
};
"ERROR" };
VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
Vector<Expression> expression;
Vector<Expression> parse_expression;
while (true) {
//keep appending stuff to expression
// keep appending stuff to expression
ENode *expr = nullptr;
Token tk;
@@ -664,7 +667,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
switch (tk.type) {
case TK_CURLY_BRACKET_OPEN: {
//a dictionary
// a dictionary
DictionaryNode *dn = alloc_node<DictionaryNode>();
while (true) {
@@ -673,8 +676,8 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
if (tk.type == TK_CURLY_BRACKET_CLOSE) {
break;
}
str_ofs = cofs; //revert
//parse an expression
str_ofs = cofs; // revert
// parse an expression
ENode *expr2 = _parse_expression();
if (!expr2) {
return nullptr;
@@ -697,7 +700,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
cofs = str_ofs;
_get_token(tk);
if (tk.type == TK_COMMA) {
//all good
// all good
} else if (tk.type == TK_CURLY_BRACKET_CLOSE) {
str_ofs = cofs;
} else {
@@ -708,7 +711,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
expr = dn;
} break;
case TK_BRACKET_OPEN: {
//an array
// an array
ArrayNode *an = alloc_node<ArrayNode>();
@@ -718,8 +721,8 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
if (tk.type == TK_BRACKET_CLOSE) {
break;
}
str_ofs = cofs; //revert
//parse an expression
str_ofs = cofs; // revert
// parse an expression
ENode *expr2 = _parse_expression();
if (!expr2) {
return nullptr;
@@ -729,7 +732,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
cofs = str_ofs;
_get_token(tk);
if (tk.type == TK_COMMA) {
//all good
// all good
} else if (tk.type == TK_BRACKET_CLOSE) {
str_ofs = cofs;
} else {
@@ -740,7 +743,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
expr = an;
} break;
case TK_PARENTHESIS_OPEN: {
//a suexpression
// a suexpression
ENode *e = _parse_expression();
if (error_set) {
return nullptr;
@@ -769,7 +772,10 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
input->index = index;
expr = input;
} else {
_set_error("Invalid input identifier '" + what + "'. For script variables, use self (locals are for inputs)." + what);
_set_error(
"Invalid input identifier '" + what +
"'. For script variables, use self (locals are for inputs)." +
what);
return nullptr;
}
} break;
@@ -783,7 +789,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
expr = constant;
} break;
case TK_BASIC_TYPE: {
//constructor..
// constructor..
Variant::Type bt = Variant::Type(int(tk.value));
_get_token(tk);
@@ -801,8 +807,8 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
if (tk.type == TK_PARENTHESIS_CLOSE) {
break;
}
str_ofs = cofs; //revert
//parse an expression
str_ofs = cofs; // revert
// parse an expression
ENode *expr2 = _parse_expression();
if (!expr2) {
return nullptr;
@@ -813,7 +819,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
cofs = str_ofs;
_get_token(tk);
if (tk.type == TK_COMMA) {
//all good
// all good
} else if (tk.type == TK_PARENTHESIS_CLOSE) {
str_ofs = cofs;
} else {
@@ -823,65 +829,19 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
expr = constructor;
} break;
case TK_BUILTIN_FUNC: {
//builtin function
_get_token(tk);
if (tk.type != TK_PARENTHESIS_OPEN) {
_set_error("Expected '('");
return nullptr;
}
BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>();
bifunc->func = VisualScriptBuiltinFunc::BuiltinFunc(int(tk.value));
while (true) {
int cofs = str_ofs;
_get_token(tk);
if (tk.type == TK_PARENTHESIS_CLOSE) {
break;
}
str_ofs = cofs; //revert
//parse an expression
ENode *expr2 = _parse_expression();
if (!expr2) {
return nullptr;
}
bifunc->arguments.push_back(expr2);
cofs = str_ofs;
_get_token(tk);
if (tk.type == TK_COMMA) {
//all good
} else if (tk.type == TK_PARENTHESIS_CLOSE) {
str_ofs = cofs;
} else {
_set_error("Expected ',' or ')'");
}
}
int expected_args = VisualScriptBuiltinFunc::get_func_argument_count(bifunc->func);
if (bifunc->arguments.size() != expected_args) {
_set_error("Builtin func '" + VisualScriptBuiltinFunc::get_func_name(bifunc->func) + "' expects " + itos(expected_args) + " arguments.");
}
expr = bifunc;
} break;
case TK_OP_SUB: {
Expression e;
e.is_op = true;
e.op = Variant::OP_NEGATE;
expression.push_back(e);
parse_expression.push_back(e);
continue;
} break;
case TK_OP_NOT: {
Expression e;
e.is_op = true;
e.op = Variant::OP_NOT;
expression.push_back(e);
parse_expression.push_back(e);
continue;
} break;
@@ -891,7 +851,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
} break;
}
//before going to operators, must check indexing!
// before going to operators, must check indexing!
while (true) {
int cofs2 = str_ofs;
@@ -904,7 +864,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
switch (tk.type) {
case TK_BRACKET_OPEN: {
//value indexing
// value indexing
IndexNode *index = alloc_node<IndexNode>();
index->base = expr;
@@ -925,7 +885,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
} break;
case TK_PERIOD: {
//named indexing or function call
// named indexing or function call
_get_token(tk);
if (tk.type != TK_IDENTIFIER) {
_set_error("Expected identifier after '.'");
@@ -937,7 +897,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
int cofs = str_ofs;
_get_token(tk);
if (tk.type == TK_PARENTHESIS_OPEN) {
//function call
// function call
CallNode *func_call = alloc_node<CallNode>();
func_call->method = identifier;
func_call->base = expr;
@@ -948,8 +908,8 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
if (tk.type == TK_PARENTHESIS_CLOSE) {
break;
}
str_ofs = cofs3; //revert
//parse an expression
str_ofs = cofs3; // revert
// parse an expression
ENode *expr2 = _parse_expression();
if (!expr2) {
return nullptr;
@@ -960,7 +920,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
cofs3 = str_ofs;
_get_token(tk);
if (tk.type == TK_COMMA) {
//all good
// all good
} else if (tk.type == TK_PARENTHESIS_CLOSE) {
str_ofs = cofs3;
} else {
@@ -970,7 +930,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
expr = func_call;
} else {
//named indexing
// named indexing
str_ofs = cofs;
NamedIndexNode *index = alloc_node<NamedIndexNode>();
@@ -991,15 +951,15 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
}
}
//push expression
// push expression
{
Expression e;
e.is_op = false;
e.node = expr;
expression.push_back(e);
parse_expression.push_back(e);
}
//ok finally look for an operator
// ok finally look for an operator
int cofs = str_ofs;
_get_token(tk);
@@ -1077,29 +1037,30 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
};
}
if (op == Variant::OP_MAX) { //stop appending stuff
if (op == Variant::OP_MAX) { // stop appending stuff
str_ofs = cofs;
break;
}
//push operator and go on
// push operator and go on
{
Expression e;
e.is_op = true;
e.op = op;
expression.push_back(e);
parse_expression.push_back(e);
}
}
/* Reduce the set of expressions and place them in an operator tree, respecting precedence */
/* Reduce the set of expressions and place them in an operator tree,
* respecting precedence */
while (expression.size() > 1) {
while (parse_expression.size() > 1) {
int next_op = -1;
int min_priority = 0xFFFFF;
bool is_unary = false;
for (int i = 0; i < expression.size(); i++) {
if (!expression[i].is_op) {
for (int i = 0; i < parse_expression.size(); i++) {
if (!parse_expression[i].is_op) {
continue;
}
@@ -1107,7 +1068,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
bool unary = false;
switch (expression[i].op) {
switch (parse_expression[i].op) {
case Variant::OP_BIT_NEGATE:
priority = 0;
unary = true;
@@ -1187,7 +1148,8 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
break;
default: {
_set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op));
_set_error("Parser bug, invalid operator in expression: " +
itos(parse_expression[i].op));
return nullptr;
}
}
@@ -1210,41 +1172,41 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
// OK! create operator..
if (is_unary) {
int expr_pos = next_op;
while (expression[expr_pos].is_op) {
while (parse_expression[expr_pos].is_op) {
expr_pos++;
if (expr_pos == expression.size()) {
//can happen..
// can happen..
_set_error("Unexpected end of expression...");
return nullptr;
}
}
//consecutively do unary operators
// consecutively do unary operators
for (int i = expr_pos - 1; i >= next_op; i--) {
OperatorNode *op = alloc_node<OperatorNode>();
op->op = expression[i].op;
op->nodes[0] = expression[i + 1].node;
op->op = parse_expression[i].op;
op->nodes[0] = parse_expression[i + 1].node;
op->nodes[1] = nullptr;
expression.write[i].is_op = false;
expression.write[i].node = op;
expression.remove_at(i + 1);
parse_expression.write[i].is_op = false;
parse_expression.write[i].node = op;
parse_expression.remove_at(i + 1);
}
} else {
if (next_op < 1 || next_op >= (expression.size() - 1)) {
if (next_op < 1 || next_op >= (parse_expression.size() - 1)) {
_set_error("Parser bug...");
ERR_FAIL_V(nullptr);
}
OperatorNode *op = alloc_node<OperatorNode>();
op->op = expression[next_op].op;
op->op = parse_expression[next_op].op;
if (expression[next_op - 1].is_op) {
if (parse_expression[next_op - 1].is_op) {
_set_error("Parser bug...");
ERR_FAIL_V(nullptr);
}
if (expression[next_op + 1].is_op) {
if (parse_expression[next_op + 1].is_op) {
// this is not invalid and can really appear
// but it becomes invalid anyway because no binary op
// can be followed by a unary op in a valid combination,
@@ -1254,17 +1216,17 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
return nullptr;
}
op->nodes[0] = expression[next_op - 1].node; //expression goes as left
op->nodes[1] = expression[next_op + 1].node; //next expression goes as right
op->nodes[0] = parse_expression[next_op - 1].node; // expression goes as left
op->nodes[1] = parse_expression[next_op + 1].node; // next expression goes as right
//replace all 3 nodes by this operator and make it an expression
expression.write[next_op - 1].node = op;
expression.remove_at(next_op);
expression.remove_at(next_op);
// replace all 3 nodes by this operator and make it an expression
parse_expression.write[next_op - 1].node = op;
parse_expression.remove_at(next_op);
parse_expression.remove_at(next_op);
}
}
return expression[0].node;
return parse_expression[0].node;
}
bool VisualScriptExpression::_compile_expression() {
@@ -1302,16 +1264,20 @@ public:
VisualScriptInstance *instance = nullptr;
VisualScriptExpression *expression = nullptr;
//virtual int get_working_memory_size() const override { return 0; }
//execute by parsing the tree directly
virtual bool _execute(const Variant **p_inputs, VisualScriptExpression::ENode *p_node, Variant &r_ret, String &r_error_str, Callable::CallError &ce) {
// virtual int get_working_memory_size() const override { return 0; }
// execute by parsing the tree directly
virtual bool _execute(const Variant **p_inputs,
VisualScriptExpression::ENode *p_node, Variant &r_ret,
String &r_error_str, Callable::CallError &ce) {
switch (p_node->type) {
case VisualScriptExpression::ENode::TYPE_INPUT: {
const VisualScriptExpression::InputNode *in = static_cast<const VisualScriptExpression::InputNode *>(p_node);
const VisualScriptExpression::InputNode *in =
static_cast<const VisualScriptExpression::InputNode *>(p_node);
r_ret = *p_inputs[in->index];
} break;
case VisualScriptExpression::ENode::TYPE_CONSTANT: {
const VisualScriptExpression::ConstantNode *c = static_cast<const VisualScriptExpression::ConstantNode *>(p_node);
const VisualScriptExpression::ConstantNode *c =
static_cast<const VisualScriptExpression::ConstantNode *>(p_node);
r_ret = c->value;
} break;
@@ -1319,7 +1285,8 @@ public:
r_ret = instance->get_owner_ptr();
} break;
case VisualScriptExpression::ENode::TYPE_OPERATOR: {
const VisualScriptExpression::OperatorNode *op = static_cast<const VisualScriptExpression::OperatorNode *>(p_node);
const VisualScriptExpression::OperatorNode *op =
static_cast<const VisualScriptExpression::OperatorNode *>(p_node);
Variant a;
bool ret = _execute(p_inputs, op->nodes[0], a, r_error_str, ce);
@@ -1339,16 +1306,20 @@ public:
bool valid = true;
Variant::evaluate(op->op, a, b, r_ret, valid);
if (!valid) {
r_error_str = "Invalid operands to operator " + Variant::get_operator_name(op->op) + ": " + Variant::get_type_name(a.get_type()) + " and " + Variant::get_type_name(b.get_type()) + ".";
r_error_str = "Invalid operands to operator " +
Variant::get_operator_name(op->op) + ": " +
Variant::get_type_name(a.get_type()) + " and " +
Variant::get_type_name(b.get_type()) + ".";
return true;
}
} break;
case VisualScriptExpression::ENode::TYPE_INDEX: {
const VisualScriptExpression::IndexNode *index = static_cast<const VisualScriptExpression::IndexNode *>(p_node);
const VisualScriptExpression::IndexNode *index =
static_cast<const VisualScriptExpression::IndexNode *>(p_node);
Variant base;
bool ret = _execute(p_inputs, index->base, base, r_error_str, ce);
Variant expression_base;
bool ret = _execute(p_inputs, index->base, expression_base, r_error_str, ce);
if (ret) {
return true;
}
@@ -1361,32 +1332,39 @@ public:
}
bool valid;
r_ret = base.get(idx, &valid);
r_ret = expression_base.get(idx, &valid);
if (!valid) {
r_error_str = "Invalid index of type " + Variant::get_type_name(idx.get_type()) + " for base of type " + Variant::get_type_name(base.get_type()) + ".";
r_error_str = "Invalid index of type " +
Variant::get_type_name(idx.get_type()) +
" for base of type " +
Variant::get_type_name(expression_base.get_type()) + ".";
return true;
}
} break;
case VisualScriptExpression::ENode::TYPE_NAMED_INDEX: {
const VisualScriptExpression::NamedIndexNode *index = static_cast<const VisualScriptExpression::NamedIndexNode *>(p_node);
const VisualScriptExpression::NamedIndexNode *index =
static_cast<const VisualScriptExpression::NamedIndexNode *>(p_node);
Variant base;
bool ret = _execute(p_inputs, index->base, base, r_error_str, ce);
Variant typed_named_expression_base;
bool ret = _execute(p_inputs, index->base, typed_named_expression_base, r_error_str, ce);
if (ret) {
return true;
}
bool valid;
r_ret = base.get_named(index->name, valid);
r_ret = typed_named_expression_base.get_named(index->name, valid);
if (!valid) {
r_error_str = "Invalid index '" + String(index->name) + "' for base of type " + Variant::get_type_name(base.get_type()) + ".";
r_error_str = "Invalid index '" + String(index->name) +
"' for base of type " +
Variant::get_type_name(typed_named_expression_base.get_type()) + ".";
return true;
}
} break;
case VisualScriptExpression::ENode::TYPE_ARRAY: {
const VisualScriptExpression::ArrayNode *array = static_cast<const VisualScriptExpression::ArrayNode *>(p_node);
const VisualScriptExpression::ArrayNode *array =
static_cast<const VisualScriptExpression::ArrayNode *>(p_node);
Array arr;
arr.resize(array->array.size());
@@ -1403,18 +1381,21 @@ public:
} break;
case VisualScriptExpression::ENode::TYPE_DICTIONARY: {
const VisualScriptExpression::DictionaryNode *dictionary = static_cast<const VisualScriptExpression::DictionaryNode *>(p_node);
const VisualScriptExpression::DictionaryNode *dictionary =
static_cast<const VisualScriptExpression::DictionaryNode *>(p_node);
Dictionary d;
for (int i = 0; i < dictionary->dict.size(); i += 2) {
Variant key;
bool ret = _execute(p_inputs, dictionary->dict[i + 0], key, r_error_str, ce);
bool ret =
_execute(p_inputs, dictionary->dict[i + 0], key, r_error_str, ce);
if (ret) {
return true;
}
Variant value;
ret = _execute(p_inputs, dictionary->dict[i + 1], value, r_error_str, ce);
ret =
_execute(p_inputs, dictionary->dict[i + 1], value, r_error_str, ce);
if (ret) {
return true;
}
@@ -1425,7 +1406,8 @@ public:
r_ret = d;
} break;
case VisualScriptExpression::ENode::TYPE_CONSTRUCTOR: {
const VisualScriptExpression::ConstructorNode *constructor = static_cast<const VisualScriptExpression::ConstructorNode *>(p_node);
const VisualScriptExpression::ConstructorNode *constructor =
static_cast<const VisualScriptExpression::ConstructorNode *>(p_node);
Vector<Variant> arr;
Vector<const Variant *> argp;
@@ -1434,7 +1416,8 @@ public:
for (int i = 0; i < constructor->arguments.size(); i++) {
Variant value;
bool ret = _execute(p_inputs, constructor->arguments[i], value, r_error_str, ce);
bool ret = _execute(p_inputs, constructor->arguments[i], value,
r_error_str, ce);
if (ret) {
return true;
}
@@ -1442,45 +1425,22 @@ public:
argp.write[i] = &arr[i];
}
Variant::construct(constructor->data_type, r_ret, (const Variant **)argp.ptr(), argp.size(), ce);
Variant::construct(constructor->data_type, r_ret,
(const Variant **)argp.ptr(), argp.size(), ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = "Invalid arguments to construct '" + Variant::get_type_name(constructor->data_type) + "'.";
return true;
}
} break;
case VisualScriptExpression::ENode::TYPE_BUILTIN_FUNC: {
const VisualScriptExpression::BuiltinFuncNode *bifunc = static_cast<const VisualScriptExpression::BuiltinFuncNode *>(p_node);
Vector<Variant> arr;
Vector<const Variant *> argp;
arr.resize(bifunc->arguments.size());
argp.resize(bifunc->arguments.size());
for (int i = 0; i < bifunc->arguments.size(); i++) {
Variant value;
bool ret = _execute(p_inputs, bifunc->arguments[i], value, r_error_str, ce);
if (ret) {
return true;
}
arr.write[i] = value;
argp.write[i] = &arr[i];
}
VisualScriptBuiltinFunc::exec_func(bifunc->func, (const Variant **)argp.ptr(), &r_ret, ce, r_error_str);
if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = "Builtin Call Failed. " + r_error_str;
r_error_str = "Invalid arguments to construct '" +
Variant::get_type_name(constructor->data_type) + "'.";
return true;
}
} break;
case VisualScriptExpression::ENode::TYPE_CALL: {
const VisualScriptExpression::CallNode *call = static_cast<const VisualScriptExpression::CallNode *>(p_node);
const VisualScriptExpression::CallNode *call =
static_cast<const VisualScriptExpression::CallNode *>(p_node);
Variant base;
bool ret = _execute(p_inputs, call->base, base, r_error_str, ce);
Variant call_expression_base;
bool ret = _execute(p_inputs, call->base, call_expression_base, r_error_str, ce);
if (ret) {
return true;
}
@@ -1492,7 +1452,8 @@ public:
for (int i = 0; i < call->arguments.size(); i++) {
Variant value;
bool ret2 = _execute(p_inputs, call->arguments[i], value, r_error_str, ce);
bool ret2 =
_execute(p_inputs, call->arguments[i], value, r_error_str, ce);
if (ret2) {
return true;
}
@@ -1500,7 +1461,8 @@ public:
argp.write[i] = &arr[i];
}
base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
call_expression_base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret,
ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = "On call to '" + String(call->method) + "':";
@@ -1512,21 +1474,28 @@ public:
return false;
}
virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
virtual int step(const Variant **p_inputs, Variant **p_outputs,
StartMode p_start_mode, Variant *p_working_mem,
Callable::CallError &r_error, String &r_error_str) override {
if (!expression->root || expression->error_set) {
r_error_str = expression->error_str;
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return 0;
}
bool error = _execute(p_inputs, expression->root, *p_outputs[0], r_error_str, r_error);
bool error = _execute(p_inputs, expression->root, *p_outputs[0],
r_error_str, r_error);
if (error && r_error.error == Callable::CallError::CALL_OK) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
}
#ifdef DEBUG_ENABLED
if (!error && expression->output_type != Variant::NIL && !Variant::can_convert_strict(p_outputs[0]->get_type(), expression->output_type)) {
r_error_str += "Can't convert expression result from " + Variant::get_type_name(p_outputs[0]->get_type()) + " to " + Variant::get_type_name(expression->output_type) + ".";
if (!error && expression->output_type != Variant::NIL &&
!Variant::can_convert_strict(p_outputs[0]->get_type(),
expression->output_type)) {
r_error_str += "Can't convert expression result from " +
Variant::get_type_name(p_outputs[0]->get_type()) + " to " +
Variant::get_type_name(expression->output_type) + ".";
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
}
#endif
@@ -1535,9 +1504,11 @@ public:
}
};
VisualScriptNodeInstance *VisualScriptExpression::instantiate(VisualScriptInstance *p_instance) {
VisualScriptNodeInstance *
VisualScriptExpression::instantiate(VisualScriptInstance *p_instance) {
_compile_expression();
VisualScriptNodeInstanceExpression *instance = memnew(VisualScriptNodeInstanceExpression);
VisualScriptNodeInstanceExpression *instance =
memnew(VisualScriptNodeInstanceExpression);
instance->instance = p_instance;
instance->expression = this;
return instance;
@@ -1556,8 +1527,7 @@ void VisualScriptExpression::reset_state() {
inputs.clear();
}
VisualScriptExpression::VisualScriptExpression() {
}
VisualScriptExpression::VisualScriptExpression() {}
VisualScriptExpression::~VisualScriptExpression() {
if (nodes) {
@@ -1566,5 +1536,6 @@ VisualScriptExpression::~VisualScriptExpression() {
}
void register_visual_script_expression_node() {
VisualScriptLanguage::singleton->add_register_func("operators/expression", create_node_generic<VisualScriptExpression>);
VisualScriptLanguage::singleton->add_register_func(
"operators/expression", create_node_generic<VisualScriptExpression>);
}