2018-08-29 20:38:13 +00:00
/*************************************************************************/
/* expression.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
2021-01-01 19:13:46 +00:00
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
2018-08-29 20:38:13 +00:00
/* */
/* 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. */
/*************************************************************************/
2018-08-08 20:34:24 +00:00
# include "expression.h"
2018-09-11 16:13:45 +00:00
# include "core/io/marshalls.h"
# include "core/math/math_funcs.h"
2020-11-07 22:33:38 +00:00
# include "core/object/class_db.h"
2021-06-04 16:03:15 +00:00
# include "core/object/ref_counted.h"
2018-09-11 16:13:45 +00:00
# include "core/os/os.h"
2020-11-07 22:33:38 +00:00
# include "core/variant/variant_parser.h"
2018-08-08 20:34:24 +00:00
2020-07-27 10:43:20 +00:00
static bool _is_number ( char32_t c ) {
2018-10-01 14:06:21 +00:00
return ( c > = ' 0 ' & & c < = ' 9 ' ) ;
}
2018-08-08 20:34:24 +00:00
Error Expression : : _get_token ( Token & r_token ) {
while ( true ) {
# define GET_CHAR() (str_ofs >= expression.length() ? 0 : expression[str_ofs++])
2020-07-27 10:43:20 +00:00
char32_t cchar = GET_CHAR ( ) ;
2018-08-08 20:34:24 +00:00
switch ( cchar ) {
case 0 : {
r_token . type = TK_EOF ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' { ' : {
r_token . type = TK_CURLY_BRACKET_OPEN ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' } ' : {
r_token . type = TK_CURLY_BRACKET_CLOSE ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' [ ' : {
r_token . type = TK_BRACKET_OPEN ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' ] ' : {
r_token . type = TK_BRACKET_CLOSE ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' ( ' : {
r_token . type = TK_PARENTHESIS_OPEN ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' ) ' : {
r_token . type = TK_PARENTHESIS_CLOSE ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' , ' : {
r_token . type = TK_COMMA ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' : ' : {
r_token . type = TK_COLON ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' $ ' : {
r_token . type = TK_INPUT ;
int index = 0 ;
do {
2018-10-01 14:06:21 +00:00
if ( ! _is_number ( expression [ str_ofs ] ) ) {
2018-08-08 20:34:24 +00:00
_set_error ( " Expected number after '$' " ) ;
r_token . type = TK_ERROR ;
return ERR_PARSE_ERROR ;
}
index * = 10 ;
index + = expression [ str_ofs ] - ' 0 ' ;
str_ofs + + ;
2018-10-01 14:06:21 +00:00
} while ( _is_number ( expression [ str_ofs ] ) ) ;
2018-08-08 20:34:24 +00:00
r_token . value = index ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' = ' : {
cchar = GET_CHAR ( ) ;
if ( cchar = = ' = ' ) {
r_token . type = TK_OP_EQUAL ;
} else {
_set_error ( " Expected '=' " ) ;
r_token . type = TK_ERROR ;
return ERR_PARSE_ERROR ;
}
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' ! ' : {
if ( expression [ str_ofs ] = = ' = ' ) {
r_token . type = TK_OP_NOT_EQUAL ;
str_ofs + + ;
} else {
r_token . type = TK_OP_NOT ;
}
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' > ' : {
if ( expression [ str_ofs ] = = ' = ' ) {
r_token . type = TK_OP_GREATER_EQUAL ;
str_ofs + + ;
} else if ( expression [ str_ofs ] = = ' > ' ) {
r_token . type = TK_OP_SHIFT_RIGHT ;
str_ofs + + ;
} else {
r_token . type = TK_OP_GREATER ;
}
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' < ' : {
if ( expression [ str_ofs ] = = ' = ' ) {
r_token . type = TK_OP_LESS_EQUAL ;
str_ofs + + ;
} else if ( expression [ str_ofs ] = = ' < ' ) {
r_token . type = TK_OP_SHIFT_LEFT ;
str_ofs + + ;
} else {
r_token . type = TK_OP_LESS ;
}
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' + ' : {
r_token . type = TK_OP_ADD ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' - ' : {
r_token . type = TK_OP_SUB ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' / ' : {
r_token . type = TK_OP_DIV ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' * ' : {
r_token . type = TK_OP_MUL ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' % ' : {
r_token . type = TK_OP_MOD ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' & ' : {
if ( expression [ str_ofs ] = = ' & ' ) {
r_token . type = TK_OP_AND ;
str_ofs + + ;
} else {
r_token . type = TK_OP_BIT_AND ;
}
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' | ' : {
if ( expression [ str_ofs ] = = ' | ' ) {
r_token . type = TK_OP_OR ;
str_ofs + + ;
} else {
r_token . type = TK_OP_BIT_OR ;
}
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' ^ ' : {
r_token . type = TK_OP_BIT_XOR ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
case ' ~ ' : {
r_token . type = TK_OP_BIT_INVERT ;
return OK ;
2020-05-19 13:46:49 +00:00
}
2020-06-01 23:02:01 +00:00
case ' \' ' :
2018-08-08 20:34:24 +00:00
case ' " ' : {
String str ;
while ( true ) {
2020-07-27 10:43:20 +00:00
char32_t ch = GET_CHAR ( ) ;
2018-08-08 20:34:24 +00:00
if ( ch = = 0 ) {
_set_error ( " Unterminated String " ) ;
r_token . type = TK_ERROR ;
return ERR_PARSE_ERROR ;
2020-06-01 23:02:01 +00:00
} else if ( ch = = cchar ) {
// cchar contain a corresponding quote symbol
2018-08-08 20:34:24 +00:00
break ;
} else if ( ch = = ' \\ ' ) {
//escaped characters...
2020-07-27 10:43:20 +00:00
char32_t next = GET_CHAR ( ) ;
2018-08-08 20:34:24 +00:00
if ( next = = 0 ) {
_set_error ( " Unterminated String " ) ;
r_token . type = TK_ERROR ;
return ERR_PARSE_ERROR ;
}
2020-07-27 10:43:20 +00:00
char32_t res = 0 ;
2018-08-08 20:34:24 +00:00
switch ( next ) {
2020-05-10 11:00:47 +00:00
case ' b ' :
res = 8 ;
break ;
case ' t ' :
res = 9 ;
break ;
case ' n ' :
res = 10 ;
break ;
case ' f ' :
res = 12 ;
break ;
case ' r ' :
res = 13 ;
break ;
2018-08-08 20:34:24 +00:00
case ' u ' : {
2020-02-13 10:37:37 +00:00
// hex number
2018-08-08 20:34:24 +00:00
for ( int j = 0 ; j < 4 ; j + + ) {
2020-07-27 10:43:20 +00:00
char32_t c = GET_CHAR ( ) ;
2018-08-08 20:34:24 +00:00
if ( c = = 0 ) {
_set_error ( " Unterminated String " ) ;
r_token . type = TK_ERROR ;
return ERR_PARSE_ERROR ;
}
2018-10-01 14:06:21 +00:00
if ( ! ( _is_number ( c ) | | ( c > = ' a ' & & c < = ' f ' ) | | ( c > = ' A ' & & c < = ' F ' ) ) ) {
2018-08-08 20:34:24 +00:00
_set_error ( " Malformed hex constant in string " ) ;
r_token . type = TK_ERROR ;
return ERR_PARSE_ERROR ;
}
2020-07-27 10:43:20 +00:00
char32_t v ;
2018-10-01 14:06:21 +00:00
if ( _is_number ( c ) ) {
2018-08-08 20:34:24 +00:00
v = c - ' 0 ' ;
} else if ( c > = ' a ' & & c < = ' f ' ) {
v = c - ' a ' ;
v + = 10 ;
} else if ( c > = ' A ' & & c < = ' F ' ) {
v = c - ' A ' ;
v + = 10 ;
} else {
2020-02-13 10:37:37 +00:00
ERR_PRINT ( " Bug parsing hex constant. " ) ;
2018-08-08 20:34:24 +00:00
v = 0 ;
}
res < < = 4 ;
res | = v ;
}
} break ;
default : {
res = next ;
} break ;
}
str + = res ;
} else {
str + = ch ;
}
}
r_token . type = TK_CONSTANT ;
r_token . value = str ;
return OK ;
} break ;
default : {
if ( cchar < = 32 ) {
break ;
}
2020-07-27 10:43:20 +00:00
char32_t next_char = ( str_ofs > = expression . length ( ) ) ? 0 : expression [ str_ofs ] ;
2018-10-01 14:06:21 +00:00
if ( _is_number ( cchar ) | | ( cchar = = ' . ' & & _is_number ( next_char ) ) ) {
2018-08-08 20:34:24 +00:00
//a number
String num ;
# define READING_SIGN 0
# define READING_INT 1
# define READING_DEC 2
# define READING_EXP 3
# define READING_DONE 4
int reading = READING_INT ;
2020-07-27 10:43:20 +00:00
char32_t c = cchar ;
2018-08-08 20:34:24 +00:00
bool exp_sign = false ;
bool exp_beg = false ;
bool is_float = false ;
while ( true ) {
switch ( reading ) {
case READING_INT : {
2018-10-01 14:06:21 +00:00
if ( _is_number ( c ) ) {
2018-08-08 20:34:24 +00:00
//pass
} else if ( c = = ' . ' ) {
reading = READING_DEC ;
is_float = true ;
} else if ( c = = ' e ' ) {
reading = READING_EXP ;
} else {
reading = READING_DONE ;
}
} break ;
case READING_DEC : {
2018-10-01 14:06:21 +00:00
if ( _is_number ( c ) ) {
2018-08-08 20:34:24 +00:00
} else if ( c = = ' e ' ) {
reading = READING_EXP ;
} else {
reading = READING_DONE ;
}
} break ;
case READING_EXP : {
2018-10-01 14:06:21 +00:00
if ( _is_number ( c ) ) {
2018-08-08 20:34:24 +00:00
exp_beg = true ;
} else if ( ( c = = ' - ' | | c = = ' + ' ) & & ! exp_sign & & ! exp_beg ) {
2020-05-14 14:41:43 +00:00
if ( c = = ' - ' ) {
2018-08-08 20:34:24 +00:00
is_float = true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
exp_sign = true ;
} else {
reading = READING_DONE ;
}
} break ;
}
2020-05-14 14:41:43 +00:00
if ( reading = = READING_DONE ) {
2018-08-08 20:34:24 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
num + = String : : chr ( c ) ;
c = GET_CHAR ( ) ;
}
str_ofs - - ;
r_token . type = TK_CONSTANT ;
2020-05-14 14:41:43 +00:00
if ( is_float ) {
2020-07-24 18:07:57 +00:00
r_token . value = num . to_float ( ) ;
2020-05-14 14:41:43 +00:00
} else {
2020-05-13 09:31:51 +00:00
r_token . value = num . to_int ( ) ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
return OK ;
} else if ( ( cchar > = ' A ' & & cchar < = ' Z ' ) | | ( cchar > = ' a ' & & cchar < = ' z ' ) | | cchar = = ' _ ' ) {
String id ;
bool first = true ;
2018-10-01 14:06:21 +00:00
while ( ( cchar > = ' A ' & & cchar < = ' Z ' ) | | ( cchar > = ' a ' & & cchar < = ' z ' ) | | cchar = = ' _ ' | | ( ! first & & _is_number ( cchar ) ) ) {
2018-08-08 20:34:24 +00:00
id + = String : : chr ( cchar ) ;
cchar = GET_CHAR ( ) ;
first = false ;
}
str_ofs - - ; //go back one
if ( id = = " in " ) {
r_token . type = TK_OP_IN ;
} else if ( id = = " null " ) {
r_token . type = TK_CONSTANT ;
r_token . value = Variant ( ) ;
} else if ( id = = " true " ) {
r_token . type = TK_CONSTANT ;
r_token . value = true ;
} else if ( id = = " false " ) {
r_token . type = TK_CONSTANT ;
r_token . value = false ;
} else if ( id = = " PI " ) {
r_token . type = TK_CONSTANT ;
r_token . value = Math_PI ;
} else if ( id = = " TAU " ) {
r_token . type = TK_CONSTANT ;
r_token . value = Math_TAU ;
} else if ( id = = " INF " ) {
r_token . type = TK_CONSTANT ;
2021-07-21 08:40:31 +00:00
r_token . value = INFINITY ;
2018-08-08 20:34:24 +00:00
} else if ( id = = " NAN " ) {
r_token . type = TK_CONSTANT ;
2021-07-21 08:40:31 +00:00
r_token . value = NAN ;
2018-08-08 20:34:24 +00:00
} else if ( id = = " not " ) {
r_token . type = TK_OP_NOT ;
} else if ( id = = " or " ) {
r_token . type = TK_OP_OR ;
} else if ( id = = " and " ) {
r_token . type = TK_OP_AND ;
} else if ( id = = " self " ) {
r_token . type = TK_SELF ;
} else {
2020-11-11 16:16:08 +00:00
if ( Variant : : has_utility_function ( id ) ) {
2018-08-08 20:34:24 +00:00
r_token . type = TK_BUILTIN_FUNC ;
2020-11-10 21:31:33 +00:00
r_token . value = id ;
2018-08-08 20:34:24 +00:00
return OK ;
}
r_token . type = TK_IDENTIFIER ;
r_token . value = id ;
}
return OK ;
2018-10-01 14:06:21 +00:00
} else if ( cchar = = ' . ' ) {
// Handled down there as we support '.[0-9]' as numbers above
r_token . type = TK_PERIOD ;
return OK ;
2018-08-08 20:34:24 +00:00
} else {
_set_error ( " Unexpected character. " ) ;
r_token . type = TK_ERROR ;
return ERR_PARSE_ERROR ;
}
}
}
2018-10-01 14:06:21 +00:00
# undef GET_CHAR
2018-08-08 20:34:24 +00:00
}
r_token . type = TK_ERROR ;
return ERR_PARSE_ERROR ;
}
const char * Expression : : token_name [ TK_MAX ] = {
" CURLY BRACKET OPEN " ,
" CURLY BRACKET CLOSE " ,
" BRACKET OPEN " ,
" BRACKET CLOSE " ,
" PARENTHESIS OPEN " ,
" PARENTHESIS CLOSE " ,
" IDENTIFIER " ,
" BUILTIN FUNC " ,
" SELF " ,
" CONSTANT " ,
" BASIC TYPE " ,
" COLON " ,
" COMMA " ,
" PERIOD " ,
" OP IN " ,
" OP EQUAL " ,
" OP NOT EQUAL " ,
" OP LESS " ,
" OP LESS EQUAL " ,
" OP GREATER " ,
" OP GREATER EQUAL " ,
" OP AND " ,
" OP OR " ,
" OP NOT " ,
" OP ADD " ,
" OP SUB " ,
" OP MUL " ,
" OP DIV " ,
" OP MOD " ,
" OP SHIFT LEFT " ,
" OP SHIFT RIGHT " ,
" OP BIT AND " ,
" OP BIT OR " ,
" OP BIT XOR " ,
" OP BIT INVERT " ,
" OP INPUT " ,
" EOF " ,
" ERROR "
} ;
Expression : : ENode * Expression : : _parse_expression ( ) {
Vector < ExpressionNode > expression ;
while ( true ) {
//keep appending stuff to expression
2020-04-01 23:20:12 +00:00
ENode * expr = nullptr ;
2018-08-08 20:34:24 +00:00
Token tk ;
_get_token ( tk ) ;
2020-05-14 14:41:43 +00:00
if ( error_set ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
switch ( tk . type ) {
case TK_CURLY_BRACKET_OPEN : {
//a dictionary
DictionaryNode * dn = alloc_node < DictionaryNode > ( ) ;
while ( true ) {
int cofs = str_ofs ;
_get_token ( tk ) ;
if ( tk . type = = TK_CURLY_BRACKET_CLOSE ) {
break ;
}
str_ofs = cofs ; //revert
//parse an expression
2019-02-12 20:10:08 +00:00
ENode * subexpr = _parse_expression ( ) ;
2020-05-14 14:41:43 +00:00
if ( ! subexpr ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2019-02-12 20:10:08 +00:00
dn - > dict . push_back ( subexpr ) ;
2018-08-08 20:34:24 +00:00
_get_token ( tk ) ;
if ( tk . type ! = TK_COLON ) {
_set_error ( " Expected ':' " ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-08-08 20:34:24 +00:00
}
2019-02-12 20:10:08 +00:00
subexpr = _parse_expression ( ) ;
2020-05-14 14:41:43 +00:00
if ( ! subexpr ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
2019-02-12 20:10:08 +00:00
dn - > dict . push_back ( subexpr ) ;
2018-08-08 20:34:24 +00:00
cofs = str_ofs ;
_get_token ( tk ) ;
if ( tk . type = = TK_COMMA ) {
//all good
} else if ( tk . type = = TK_CURLY_BRACKET_CLOSE ) {
str_ofs = cofs ;
} else {
_set_error ( " Expected ',' or '}' " ) ;
}
}
expr = dn ;
} break ;
case TK_BRACKET_OPEN : {
//an array
ArrayNode * an = alloc_node < ArrayNode > ( ) ;
while ( true ) {
int cofs = str_ofs ;
_get_token ( tk ) ;
if ( tk . type = = TK_BRACKET_CLOSE ) {
break ;
}
str_ofs = cofs ; //revert
//parse an expression
2019-02-12 20:10:08 +00:00
ENode * subexpr = _parse_expression ( ) ;
2020-05-14 14:41:43 +00:00
if ( ! subexpr ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2019-02-12 20:10:08 +00:00
an - > array . push_back ( subexpr ) ;
2018-08-08 20:34:24 +00:00
cofs = str_ofs ;
_get_token ( tk ) ;
if ( tk . type = = TK_COMMA ) {
//all good
} else if ( tk . type = = TK_BRACKET_CLOSE ) {
str_ofs = cofs ;
} else {
_set_error ( " Expected ',' or ']' " ) ;
}
}
expr = an ;
} break ;
case TK_PARENTHESIS_OPEN : {
//a suexpression
ENode * e = _parse_expression ( ) ;
2020-05-14 14:41:43 +00:00
if ( error_set ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
_get_token ( tk ) ;
if ( tk . type ! = TK_PARENTHESIS_CLOSE ) {
_set_error ( " Expected ')' " ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-08-08 20:34:24 +00:00
}
expr = e ;
} break ;
case TK_IDENTIFIER : {
String identifier = tk . value ;
int cofs = str_ofs ;
_get_token ( tk ) ;
if ( tk . type = = TK_PARENTHESIS_OPEN ) {
//function call
CallNode * func_call = alloc_node < CallNode > ( ) ;
func_call - > method = identifier ;
SelfNode * self_node = alloc_node < SelfNode > ( ) ;
func_call - > base = self_node ;
while ( true ) {
2019-02-12 20:10:08 +00:00
int cofs2 = str_ofs ;
2018-08-08 20:34:24 +00:00
_get_token ( tk ) ;
if ( tk . type = = TK_PARENTHESIS_CLOSE ) {
break ;
}
2019-02-12 20:10:08 +00:00
str_ofs = cofs2 ; //revert
2018-08-08 20:34:24 +00:00
//parse an expression
2019-02-12 20:10:08 +00:00
ENode * subexpr = _parse_expression ( ) ;
2020-05-14 14:41:43 +00:00
if ( ! subexpr ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
2019-02-12 20:10:08 +00:00
func_call - > arguments . push_back ( subexpr ) ;
2018-08-08 20:34:24 +00:00
2019-02-12 20:10:08 +00:00
cofs2 = str_ofs ;
2018-08-08 20:34:24 +00:00
_get_token ( tk ) ;
if ( tk . type = = TK_COMMA ) {
//all good
} else if ( tk . type = = TK_PARENTHESIS_CLOSE ) {
2019-02-12 20:10:08 +00:00
str_ofs = cofs2 ;
2018-08-08 20:34:24 +00:00
} else {
_set_error ( " Expected ',' or ')' " ) ;
}
}
expr = func_call ;
} else {
//named indexing
str_ofs = cofs ;
2018-08-08 20:47:51 +00:00
int input_index = - 1 ;
for ( int i = 0 ; i < input_names . size ( ) ; i + + ) {
if ( input_names [ i ] = = identifier ) {
input_index = i ;
break ;
}
}
if ( input_index ! = - 1 ) {
InputNode * input = alloc_node < InputNode > ( ) ;
input - > index = input_index ;
expr = input ;
} else {
NamedIndexNode * index = alloc_node < NamedIndexNode > ( ) ;
SelfNode * self_node = alloc_node < SelfNode > ( ) ;
index - > base = self_node ;
index - > name = identifier ;
expr = index ;
}
2018-08-08 20:34:24 +00:00
}
} break ;
case TK_INPUT : {
InputNode * input = alloc_node < InputNode > ( ) ;
input - > index = tk . value ;
expr = input ;
} break ;
case TK_SELF : {
SelfNode * self = alloc_node < SelfNode > ( ) ;
expr = self ;
} break ;
case TK_CONSTANT : {
ConstantNode * constant = alloc_node < ConstantNode > ( ) ;
constant - > value = tk . value ;
expr = constant ;
} break ;
case TK_BASIC_TYPE : {
//constructor..
Variant : : Type bt = Variant : : Type ( int ( tk . value ) ) ;
_get_token ( tk ) ;
if ( tk . type ! = TK_PARENTHESIS_OPEN ) {
_set_error ( " Expected '(' " ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-08-08 20:34:24 +00:00
}
ConstructorNode * constructor = alloc_node < ConstructorNode > ( ) ;
constructor - > data_type = bt ;
while ( true ) {
int cofs = str_ofs ;
_get_token ( tk ) ;
if ( tk . type = = TK_PARENTHESIS_CLOSE ) {
break ;
}
str_ofs = cofs ; //revert
//parse an expression
2019-02-12 20:10:08 +00:00
ENode * subexpr = _parse_expression ( ) ;
2020-05-14 14:41:43 +00:00
if ( ! subexpr ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
2019-02-12 20:10:08 +00:00
constructor - > arguments . push_back ( subexpr ) ;
2018-08-08 20:34:24 +00:00
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 ')' " ) ;
}
}
expr = constructor ;
} break ;
case TK_BUILTIN_FUNC : {
//builtin function
2020-11-10 21:31:33 +00:00
StringName func = tk . value ;
2018-08-08 20:34:24 +00:00
_get_token ( tk ) ;
if ( tk . type ! = TK_PARENTHESIS_OPEN ) {
_set_error ( " Expected '(' " ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-08-08 20:34:24 +00:00
}
BuiltinFuncNode * bifunc = alloc_node < BuiltinFuncNode > ( ) ;
2020-11-10 21:31:33 +00:00
bifunc - > func = func ;
2018-08-08 20:34:24 +00:00
while ( true ) {
int cofs = str_ofs ;
_get_token ( tk ) ;
if ( tk . type = = TK_PARENTHESIS_CLOSE ) {
break ;
}
str_ofs = cofs ; //revert
//parse an expression
2019-02-12 20:10:08 +00:00
ENode * subexpr = _parse_expression ( ) ;
2020-05-14 14:41:43 +00:00
if ( ! subexpr ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
2019-02-12 20:10:08 +00:00
bifunc - > arguments . push_back ( subexpr ) ;
2018-08-08 20:34:24 +00:00
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 ')' " ) ;
}
}
2020-11-11 16:16:08 +00:00
if ( ! Variant : : is_utility_function_vararg ( bifunc - > func ) ) {
int expected_args = Variant : : get_utility_function_argument_count ( bifunc - > func ) ;
2020-11-10 21:31:33 +00:00
if ( expected_args ! = bifunc - > arguments . size ( ) ) {
_set_error ( " Builtin func ' " + String ( bifunc - > func ) + " ' expects " + itos ( expected_args ) + " arguments. " ) ;
}
2018-08-08 20:34:24 +00:00
}
expr = bifunc ;
} break ;
case TK_OP_SUB : {
ExpressionNode e ;
e . is_op = true ;
e . op = Variant : : OP_NEGATE ;
expression . push_back ( e ) ;
continue ;
} break ;
case TK_OP_NOT : {
ExpressionNode e ;
e . is_op = true ;
e . op = Variant : : OP_NOT ;
expression . push_back ( e ) ;
continue ;
} break ;
default : {
_set_error ( " Expected expression. " ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-08-08 20:34:24 +00:00
} break ;
}
//before going to operators, must check indexing!
while ( true ) {
int cofs2 = str_ofs ;
_get_token ( tk ) ;
2020-05-14 14:41:43 +00:00
if ( error_set ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
bool done = false ;
switch ( tk . type ) {
case TK_BRACKET_OPEN : {
//value indexing
IndexNode * index = alloc_node < IndexNode > ( ) ;
index - > base = expr ;
ENode * what = _parse_expression ( ) ;
2020-05-14 14:41:43 +00:00
if ( ! what ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
index - > index = what ;
_get_token ( tk ) ;
if ( tk . type ! = TK_BRACKET_CLOSE ) {
_set_error ( " Expected ']' at end of index. " ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-08-08 20:34:24 +00:00
}
expr = index ;
} break ;
case TK_PERIOD : {
//named indexing or function call
_get_token ( tk ) ;
if ( tk . type ! = TK_IDENTIFIER ) {
_set_error ( " Expected identifier after '.' " ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-08-08 20:34:24 +00:00
}
StringName identifier = tk . value ;
int cofs = str_ofs ;
_get_token ( tk ) ;
if ( tk . type = = TK_PARENTHESIS_OPEN ) {
//function call
CallNode * func_call = alloc_node < CallNode > ( ) ;
func_call - > method = identifier ;
func_call - > base = expr ;
while ( true ) {
2019-02-12 20:10:08 +00:00
int cofs3 = str_ofs ;
2018-08-08 20:34:24 +00:00
_get_token ( tk ) ;
if ( tk . type = = TK_PARENTHESIS_CLOSE ) {
break ;
}
2019-02-12 20:10:08 +00:00
str_ofs = cofs3 ; //revert
2018-08-08 20:34:24 +00:00
//parse an expression
2019-02-12 20:10:08 +00:00
ENode * subexpr = _parse_expression ( ) ;
2020-05-14 14:41:43 +00:00
if ( ! subexpr ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
2019-02-12 20:10:08 +00:00
func_call - > arguments . push_back ( subexpr ) ;
2018-08-08 20:34:24 +00:00
2019-02-12 20:10:08 +00:00
cofs3 = str_ofs ;
2018-08-08 20:34:24 +00:00
_get_token ( tk ) ;
if ( tk . type = = TK_COMMA ) {
//all good
} else if ( tk . type = = TK_PARENTHESIS_CLOSE ) {
2019-02-12 20:10:08 +00:00
str_ofs = cofs3 ;
2018-08-08 20:34:24 +00:00
} else {
_set_error ( " Expected ',' or ')' " ) ;
}
}
expr = func_call ;
} else {
//named indexing
str_ofs = cofs ;
NamedIndexNode * index = alloc_node < NamedIndexNode > ( ) ;
index - > base = expr ;
index - > name = identifier ;
expr = index ;
}
} break ;
default : {
str_ofs = cofs2 ;
done = true ;
} break ;
}
2020-05-14 14:41:43 +00:00
if ( done ) {
2018-08-08 20:34:24 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
}
//push expression
{
ExpressionNode e ;
e . is_op = false ;
e . node = expr ;
expression . push_back ( e ) ;
}
//ok finally look for an operator
int cofs = str_ofs ;
_get_token ( tk ) ;
2020-05-14 14:41:43 +00:00
if ( error_set ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
Variant : : Operator op = Variant : : OP_MAX ;
switch ( tk . type ) {
2020-05-10 11:00:47 +00:00
case TK_OP_IN :
op = Variant : : OP_IN ;
break ;
case TK_OP_EQUAL :
op = Variant : : OP_EQUAL ;
break ;
case TK_OP_NOT_EQUAL :
op = Variant : : OP_NOT_EQUAL ;
break ;
case TK_OP_LESS :
op = Variant : : OP_LESS ;
break ;
case TK_OP_LESS_EQUAL :
op = Variant : : OP_LESS_EQUAL ;
break ;
case TK_OP_GREATER :
op = Variant : : OP_GREATER ;
break ;
case TK_OP_GREATER_EQUAL :
op = Variant : : OP_GREATER_EQUAL ;
break ;
case TK_OP_AND :
op = Variant : : OP_AND ;
break ;
case TK_OP_OR :
op = Variant : : OP_OR ;
break ;
case TK_OP_NOT :
op = Variant : : OP_NOT ;
break ;
case TK_OP_ADD :
op = Variant : : OP_ADD ;
break ;
case TK_OP_SUB :
op = Variant : : OP_SUBTRACT ;
break ;
case TK_OP_MUL :
op = Variant : : OP_MULTIPLY ;
break ;
case TK_OP_DIV :
op = Variant : : OP_DIVIDE ;
break ;
case TK_OP_MOD :
op = Variant : : OP_MODULE ;
break ;
case TK_OP_SHIFT_LEFT :
op = Variant : : OP_SHIFT_LEFT ;
break ;
case TK_OP_SHIFT_RIGHT :
op = Variant : : OP_SHIFT_RIGHT ;
break ;
case TK_OP_BIT_AND :
op = Variant : : OP_BIT_AND ;
break ;
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 ;
2019-04-09 15:08:36 +00:00
default : {
2020-05-19 13:46:49 +00:00
}
2018-08-08 20:34:24 +00:00
}
if ( op = = Variant : : OP_MAX ) { //stop appending stuff
str_ofs = cofs ;
break ;
}
//push operator and go on
{
ExpressionNode e ;
e . is_op = true ;
e . op = op ;
expression . push_back ( e ) ;
}
}
2021-03-12 13:35:16 +00:00
/* Reduce the set of expressions and place them in an operator tree, respecting precedence */
2018-08-08 20:34:24 +00:00
while ( 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 ) {
continue ;
}
int priority ;
bool unary = false ;
switch ( expression [ i ] . op ) {
case Variant : : OP_BIT_NEGATE :
priority = 0 ;
unary = true ;
break ;
case Variant : : OP_NEGATE :
priority = 1 ;
unary = true ;
break ;
2020-05-10 11:00:47 +00:00
case Variant : : OP_MULTIPLY :
case Variant : : OP_DIVIDE :
case Variant : : OP_MODULE :
priority = 2 ;
break ;
case Variant : : OP_ADD :
case Variant : : OP_SUBTRACT :
priority = 3 ;
break ;
case Variant : : OP_SHIFT_LEFT :
case Variant : : OP_SHIFT_RIGHT :
priority = 4 ;
break ;
case Variant : : OP_BIT_AND :
priority = 5 ;
break ;
case Variant : : OP_BIT_XOR :
priority = 6 ;
break ;
case Variant : : OP_BIT_OR :
priority = 7 ;
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 ;
break ;
case Variant : : OP_IN :
priority = 10 ;
break ;
2018-08-08 20:34:24 +00:00
case Variant : : OP_NOT :
priority = 11 ;
unary = true ;
break ;
2020-05-10 11:00:47 +00:00
case Variant : : OP_AND :
priority = 12 ;
break ;
case Variant : : OP_OR :
priority = 13 ;
break ;
2018-08-08 20:34:24 +00:00
default : {
_set_error ( " Parser bug, invalid operator in expression: " + itos ( expression [ i ] . op ) ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-08-08 20:34:24 +00:00
}
}
if ( priority < min_priority ) {
// < is used for left to right (default)
// <= is used for right to left
next_op = i ;
min_priority = priority ;
is_unary = unary ;
}
}
if ( next_op = = - 1 ) {
_set_error ( " Yet another parser bug.... " ) ;
2020-04-01 23:20:12 +00:00
ERR_FAIL_V ( nullptr ) ;
2018-08-08 20:34:24 +00:00
}
// OK! create operator..
if ( is_unary ) {
int expr_pos = next_op ;
while ( expression [ expr_pos ] . is_op ) {
expr_pos + + ;
if ( expr_pos = = expression . size ( ) ) {
//can happen..
_set_error ( " Unexpected end of expression... " ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-08-08 20:34:24 +00:00
}
}
2020-03-11 17:59:18 +00:00
//consecutively do unary operators
2018-08-08 20:34:24 +00:00
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 ;
2020-04-01 23:20:12 +00:00
op - > nodes [ 1 ] = nullptr ;
2018-08-08 20:34:24 +00:00
expression . write [ i ] . is_op = false ;
expression . write [ i ] . node = op ;
2021-07-03 22:17:03 +00:00
expression . remove_at ( i + 1 ) ;
2018-08-08 20:34:24 +00:00
}
} else {
if ( next_op < 1 | | next_op > = ( expression . size ( ) - 1 ) ) {
_set_error ( " Parser bug... " ) ;
2020-04-01 23:20:12 +00:00
ERR_FAIL_V ( nullptr ) ;
2018-08-08 20:34:24 +00:00
}
OperatorNode * op = alloc_node < OperatorNode > ( ) ;
op - > op = expression [ next_op ] . op ;
if ( expression [ next_op - 1 ] . is_op ) {
_set_error ( " Parser bug... " ) ;
2020-04-01 23:20:12 +00:00
ERR_FAIL_V ( nullptr ) ;
2018-08-08 20:34:24 +00:00
}
if ( 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,
// due to how precedence works, unaries will always disappear first
_set_error ( " Unexpected two consecutive operators. " ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-08-08 20:34:24 +00:00
}
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
//replace all 3 nodes by this operator and make it an expression
expression . write [ next_op - 1 ] . node = op ;
2021-07-03 22:17:03 +00:00
expression . remove_at ( next_op ) ;
expression . remove_at ( next_op ) ;
2018-08-08 20:34:24 +00:00
}
}
return expression [ 0 ] . node ;
}
bool Expression : : _compile_expression ( ) {
2020-05-14 14:41:43 +00:00
if ( ! expression_dirty ) {
2018-08-08 20:34:24 +00:00
return error_set ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
if ( nodes ) {
memdelete ( nodes ) ;
2020-04-01 23:20:12 +00:00
nodes = nullptr ;
root = nullptr ;
2018-08-08 20:34:24 +00:00
}
error_str = String ( ) ;
error_set = false ;
str_ofs = 0 ;
root = _parse_expression ( ) ;
if ( error_set ) {
2020-04-01 23:20:12 +00:00
root = nullptr ;
2018-08-08 20:34:24 +00:00
if ( nodes ) {
memdelete ( nodes ) ;
}
2020-04-01 23:20:12 +00:00
nodes = nullptr ;
2018-08-08 20:34:24 +00:00
return true ;
}
expression_dirty = false ;
return false ;
}
bool Expression : : _execute ( const Array & p_inputs , Object * p_instance , Expression : : ENode * p_node , Variant & r_ret , String & r_error_str ) {
switch ( p_node - > type ) {
case Expression : : ENode : : TYPE_INPUT : {
const Expression : : InputNode * in = static_cast < const Expression : : InputNode * > ( p_node ) ;
if ( in - > index < 0 | | in - > index > = p_inputs . size ( ) ) {
r_error_str = vformat ( RTR ( " Invalid input %i (not passed) in expression " ) , in - > index ) ;
return true ;
}
r_ret = p_inputs [ in - > index ] ;
} break ;
case Expression : : ENode : : TYPE_CONSTANT : {
const Expression : : ConstantNode * c = static_cast < const Expression : : ConstantNode * > ( p_node ) ;
r_ret = c - > value ;
} break ;
case Expression : : ENode : : TYPE_SELF : {
if ( ! p_instance ) {
r_error_str = RTR ( " self can't be used because instance is null (not passed) " ) ;
return true ;
}
r_ret = p_instance ;
} break ;
case Expression : : ENode : : TYPE_OPERATOR : {
const Expression : : OperatorNode * op = static_cast < const Expression : : OperatorNode * > ( p_node ) ;
Variant a ;
bool ret = _execute ( p_inputs , p_instance , op - > nodes [ 0 ] , a , r_error_str ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
Variant b ;
if ( op - > nodes [ 1 ] ) {
2019-02-12 20:10:08 +00:00
ret = _execute ( p_inputs , p_instance , op - > nodes [ 1 ] , b , r_error_str ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
}
bool valid = true ;
Variant : : evaluate ( op - > op , a , b , r_ret , valid ) ;
if ( ! valid ) {
r_error_str = vformat ( RTR ( " Invalid operands to operator %s, %s and %s. " ) , Variant : : get_operator_name ( op - > op ) , Variant : : get_type_name ( a . get_type ( ) ) , Variant : : get_type_name ( b . get_type ( ) ) ) ;
return true ;
}
} break ;
case Expression : : ENode : : TYPE_INDEX : {
const Expression : : IndexNode * index = static_cast < const Expression : : IndexNode * > ( p_node ) ;
Variant base ;
bool ret = _execute ( p_inputs , p_instance , index - > base , base , r_error_str ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
Variant idx ;
ret = _execute ( p_inputs , p_instance , index - > index , idx , r_error_str ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
bool valid ;
r_ret = base . get ( idx , & valid ) ;
if ( ! valid ) {
r_error_str = vformat ( RTR ( " Invalid index of type %s for base type %s " ) , Variant : : get_type_name ( idx . get_type ( ) ) , Variant : : get_type_name ( base . get_type ( ) ) ) ;
return true ;
}
} break ;
case Expression : : ENode : : TYPE_NAMED_INDEX : {
const Expression : : NamedIndexNode * index = static_cast < const Expression : : NamedIndexNode * > ( p_node ) ;
Variant base ;
bool ret = _execute ( p_inputs , p_instance , index - > base , base , r_error_str ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
bool valid ;
2020-11-07 01:29:22 +00:00
r_ret = base . get_named ( index - > name , valid ) ;
2018-08-08 20:34:24 +00:00
if ( ! valid ) {
2018-08-22 08:58:27 +00:00
r_error_str = vformat ( RTR ( " Invalid named index '%s' for base type %s " ) , String ( index - > name ) , Variant : : get_type_name ( base . get_type ( ) ) ) ;
2018-08-08 20:34:24 +00:00
return true ;
}
} break ;
case Expression : : ENode : : TYPE_ARRAY : {
const Expression : : ArrayNode * array = static_cast < const Expression : : ArrayNode * > ( p_node ) ;
Array arr ;
arr . resize ( array - > array . size ( ) ) ;
for ( int i = 0 ; i < array - > array . size ( ) ; i + + ) {
Variant value ;
bool ret = _execute ( p_inputs , p_instance , array - > array [ i ] , value , r_error_str ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
arr [ i ] = value ;
}
r_ret = arr ;
} break ;
case Expression : : ENode : : TYPE_DICTIONARY : {
const Expression : : DictionaryNode * dictionary = static_cast < const Expression : : DictionaryNode * > ( p_node ) ;
Dictionary d ;
for ( int i = 0 ; i < dictionary - > dict . size ( ) ; i + = 2 ) {
Variant key ;
bool ret = _execute ( p_inputs , p_instance , dictionary - > dict [ i + 0 ] , key , r_error_str ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
Variant value ;
ret = _execute ( p_inputs , p_instance , dictionary - > dict [ i + 1 ] , value , r_error_str ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
d [ key ] = value ;
}
r_ret = d ;
} break ;
case Expression : : ENode : : TYPE_CONSTRUCTOR : {
const Expression : : ConstructorNode * constructor = static_cast < const Expression : : ConstructorNode * > ( p_node ) ;
Vector < Variant > arr ;
Vector < const Variant * > argp ;
arr . resize ( constructor - > arguments . size ( ) ) ;
argp . resize ( constructor - > arguments . size ( ) ) ;
for ( int i = 0 ; i < constructor - > arguments . size ( ) ; i + + ) {
Variant value ;
bool ret = _execute ( p_inputs , p_instance , constructor - > arguments [ i ] , value , r_error_str ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
arr . write [ i ] = value ;
argp . write [ i ] = & arr [ i ] ;
}
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2020-11-09 03:19:09 +00:00
Variant : : construct ( constructor - > data_type , r_ret , ( const Variant * * ) argp . ptr ( ) , argp . size ( ) , ce ) ;
2018-08-08 20:34:24 +00:00
2020-02-19 19:27:19 +00:00
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
2018-08-08 20:34:24 +00:00
r_error_str = vformat ( RTR ( " Invalid arguments to construct '%s' " ) , Variant : : get_type_name ( constructor - > data_type ) ) ;
return true ;
}
} break ;
case Expression : : ENode : : TYPE_BUILTIN_FUNC : {
const Expression : : BuiltinFuncNode * bifunc = static_cast < const Expression : : 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 , p_instance , bifunc - > arguments [ i ] , value , r_error_str ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
arr . write [ i ] = value ;
argp . write [ i ] = & arr [ i ] ;
}
2020-11-10 21:31:33 +00:00
r_ret = Variant ( ) ; //may not return anything
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2020-11-11 16:16:08 +00:00
Variant : : call_utility_function ( bifunc - > func , & r_ret , ( const Variant * * ) argp . ptr ( ) , argp . size ( ) , ce ) ;
2020-02-19 19:27:19 +00:00
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
2020-11-10 21:31:33 +00:00
r_error_str = " Builtin Call Failed. " + Variant : : get_call_error_text ( bifunc - > func , ( const Variant * * ) argp . ptr ( ) , argp . size ( ) , ce ) ;
2018-08-08 20:34:24 +00:00
return true ;
}
} break ;
case Expression : : ENode : : TYPE_CALL : {
const Expression : : CallNode * call = static_cast < const Expression : : CallNode * > ( p_node ) ;
Variant base ;
bool ret = _execute ( p_inputs , p_instance , call - > base , base , r_error_str ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
Vector < Variant > arr ;
Vector < const Variant * > argp ;
arr . resize ( call - > arguments . size ( ) ) ;
argp . resize ( call - > arguments . size ( ) ) ;
for ( int i = 0 ; i < call - > arguments . size ( ) ; i + + ) {
Variant value ;
2019-02-12 20:10:08 +00:00
ret = _execute ( p_inputs , p_instance , call - > arguments [ i ] , value , r_error_str ) ;
2018-08-08 20:34:24 +00:00
2020-05-14 14:41:43 +00:00
if ( ret ) {
2018-08-08 20:34:24 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2018-08-08 20:34:24 +00:00
arr . write [ i ] = value ;
argp . write [ i ] = & arr [ i ] ;
}
2020-02-19 19:27:19 +00:00
Callable : : CallError ce ;
2020-11-11 16:16:08 +00:00
base . call ( call - > method , ( const Variant * * ) argp . ptr ( ) , argp . size ( ) , r_ret , ce ) ;
2018-08-08 20:34:24 +00:00
2020-02-19 19:27:19 +00:00
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
2018-08-08 20:34:24 +00:00
r_error_str = vformat ( RTR ( " On call to '%s': " ) , String ( call - > method ) ) ;
return true ;
}
} break ;
}
return false ;
}
2018-08-08 20:47:51 +00:00
Error Expression : : parse ( const String & p_expression , const Vector < String > & p_input_names ) {
2018-08-08 20:34:24 +00:00
if ( nodes ) {
memdelete ( nodes ) ;
2020-04-01 23:20:12 +00:00
nodes = nullptr ;
root = nullptr ;
2018-08-08 20:34:24 +00:00
}
error_str = String ( ) ;
error_set = false ;
str_ofs = 0 ;
2018-08-08 20:47:51 +00:00
input_names = p_input_names ;
2018-08-08 20:34:24 +00:00
expression = p_expression ;
root = _parse_expression ( ) ;
if ( error_set ) {
2020-04-01 23:20:12 +00:00
root = nullptr ;
2018-08-08 20:34:24 +00:00
if ( nodes ) {
memdelete ( nodes ) ;
}
2020-04-01 23:20:12 +00:00
nodes = nullptr ;
2018-08-08 20:34:24 +00:00
return ERR_INVALID_PARAMETER ;
}
return OK ;
}
Variant Expression : : execute ( Array p_inputs , Object * p_base , bool p_show_error ) {
2019-08-15 02:57:49 +00:00
ERR_FAIL_COND_V_MSG ( error_set , Variant ( ) , " There was previously a parse error: " + error_str + " . " ) ;
2018-08-08 20:34:24 +00:00
execution_error = false ;
Variant output ;
String error_txt ;
bool err = _execute ( p_inputs , p_base , root , output , error_txt ) ;
if ( err ) {
execution_error = true ;
error_str = error_txt ;
2019-08-15 02:57:49 +00:00
ERR_FAIL_COND_V_MSG ( p_show_error , Variant ( ) , error_str ) ;
2018-08-08 20:34:24 +00:00
}
return output ;
}
bool Expression : : has_execute_failed ( ) const {
return execution_error ;
}
String Expression : : get_error_text ( ) const {
return error_str ;
}
void Expression : : _bind_methods ( ) {
2018-08-08 20:47:51 +00:00
ClassDB : : bind_method ( D_METHOD ( " parse " , " expression " , " input_names " ) , & Expression : : parse , DEFVAL ( Vector < String > ( ) ) ) ;
2018-08-09 11:50:06 +00:00
ClassDB : : bind_method ( D_METHOD ( " execute " , " inputs " , " base_instance " , " show_error " ) , & Expression : : execute , DEFVAL ( Array ( ) ) , DEFVAL ( Variant ( ) ) , DEFVAL ( true ) ) ;
2018-08-08 20:34:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_execute_failed " ) , & Expression : : has_execute_failed ) ;
ClassDB : : bind_method ( D_METHOD ( " get_error_text " ) , & Expression : : get_error_text ) ;
}
Expression : : ~ Expression ( ) {
if ( nodes ) {
memdelete ( nodes ) ;
}
}