@ -913,6 +913,7 @@ void ShaderLanguage::clear() {
char_idx = 0 ;
error_set = false ;
error_str = " " ;
last_const = false ;
while ( nodes ) {
Node * n = nodes ;
nodes = nodes - > next ;
@ -3252,6 +3253,137 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
ERR_FAIL_V ( false ) ; //bug? function not found
}
ShaderLanguage : : Node * ShaderLanguage : : _parse_array_constructor ( BlockNode * p_block , const FunctionInfo & p_function_info , DataType p_type , const StringName & p_struct_name , int p_array_size ) {
DataType type = TYPE_VOID ;
String struct_name = " " ;
int array_size = 0 ;
bool auto_size = false ;
Token tk = _get_token ( ) ;
if ( tk . type = = TK_CURLY_BRACKET_OPEN ) {
auto_size = true ;
} else {
if ( shader - > structs . has ( tk . text ) ) {
type = TYPE_STRUCT ;
struct_name = tk . text ;
} else {
if ( ! is_token_variable_datatype ( tk . type ) ) {
_set_error ( " Invalid data type for array " ) ;
return nullptr ;
}
type = get_token_datatype ( tk . type ) ;
}
tk = _get_token ( ) ;
if ( tk . type = = TK_BRACKET_OPEN ) {
TkPos pos = _get_tkpos ( ) ;
tk = _get_token ( ) ;
if ( tk . type = = TK_BRACKET_CLOSE ) {
array_size = p_array_size ;
tk = _get_token ( ) ;
} else {
_set_tkpos ( pos ) ;
Node * n = _parse_and_reduce_expression ( p_block , p_function_info ) ;
if ( ! n | | n - > type ! = Node : : TYPE_CONSTANT | | n - > get_datatype ( ) ! = TYPE_INT ) {
_set_error ( " Expected single integer constant > 0 " ) ;
return nullptr ;
}
ConstantNode * cnode = ( ConstantNode * ) n ;
if ( cnode - > values . size ( ) = = 1 ) {
array_size = cnode - > values [ 0 ] . sint ;
if ( array_size < = 0 ) {
_set_error ( " Expected single integer constant > 0 " ) ;
return nullptr ;
}
} else {
_set_error ( " Expected single integer constant > 0 " ) ;
return nullptr ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_BRACKET_CLOSE ) {
_set_error ( " Expected ']' " ) ;
return nullptr ;
} else {
tk = _get_token ( ) ;
}
}
} else {
_set_error ( " Expected '[' " ) ;
return nullptr ;
}
if ( type ! = p_type | | struct_name ! = p_struct_name | | array_size ! = p_array_size ) {
String error_str = " Cannot convert from ' " ;
if ( type = = TYPE_STRUCT ) {
error_str + = struct_name ;
} else {
error_str + = get_datatype_name ( type ) ;
}
error_str + = " [ " ;
error_str + = itos ( array_size ) ;
error_str + = " ]' " ;
error_str + = " to ' " ;
if ( type = = TYPE_STRUCT ) {
error_str + = p_struct_name ;
} else {
error_str + = get_datatype_name ( p_type ) ;
}
error_str + = " [ " ;
error_str + = itos ( p_array_size ) ;
error_str + = " ]' " ;
_set_error ( error_str ) ;
return nullptr ;
}
}
ArrayConstructNode * an = alloc_node < ArrayConstructNode > ( ) ;
an - > datatype = p_type ;
an - > struct_name = p_struct_name ;
if ( tk . type = = TK_PARENTHESIS_OPEN | | auto_size ) { // initialization
while ( true ) {
Node * n = _parse_and_reduce_expression ( p_block , p_function_info ) ;
if ( ! n ) {
return nullptr ;
}
if ( p_type ! = n - > get_datatype ( ) | | p_struct_name ! = n - > get_datatype_name ( ) ) {
_set_error ( " Invalid assignment of ' " + ( n - > get_datatype ( ) = = TYPE_STRUCT ? n - > get_datatype_name ( ) : get_datatype_name ( n - > get_datatype ( ) ) ) + " ' to ' " + ( type = = TYPE_STRUCT ? struct_name : get_datatype_name ( type ) ) + " ' " ) ;
return nullptr ;
}
tk = _get_token ( ) ;
if ( tk . type = = TK_COMMA ) {
an - > initializer . push_back ( n ) ;
} else if ( ! auto_size & & tk . type = = TK_PARENTHESIS_CLOSE ) {
an - > initializer . push_back ( n ) ;
break ;
} else if ( auto_size & & tk . type = = TK_CURLY_BRACKET_CLOSE ) {
an - > initializer . push_back ( n ) ;
break ;
} else {
if ( auto_size ) {
_set_error ( " Expected '}' or ',' " ) ;
} else {
_set_error ( " Expected ')' or ',' " ) ;
}
return nullptr ;
}
}
if ( an - > initializer . size ( ) ! = p_array_size ) {
_set_error ( " Array size mismatch " ) ;
return nullptr ;
}
} else {
_set_error ( " Expected array initialization! " ) ;
return nullptr ;
}
return an ;
}
ShaderLanguage : : Node * ShaderLanguage : : _parse_expression ( BlockNode * p_block , const FunctionInfo & p_function_info ) {
Vector < Expression > expression ;
@ -3395,142 +3527,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
Node * nexpr ;
if ( pstruct - > members [ i ] - > array_size ! = 0 ) {
DataType type = pstruct - > members [ i ] - > get_datatype ( ) ;
String struct_name = pstruct - > members [ i ] - > struct_name ;
int array_size = pstruct - > members [ i ] - > array_size ;
DataType type2 ;
String struct_name2 = " " ;
int array_size2 = 0 ;
bool auto_size = false ;
tk = _get_token ( ) ;
if ( tk . type = = TK_CURLY_BRACKET_OPEN ) {
auto_size = true ;
} else {
if ( shader - > structs . has ( tk . text ) ) {
type2 = TYPE_STRUCT ;
struct_name2 = tk . text ;
} else {
if ( ! is_token_variable_datatype ( tk . type ) ) {
_set_error ( " Invalid data type for array " ) ;
return nullptr ;
}
type2 = get_token_datatype ( tk . type ) ;
}
tk = _get_token ( ) ;
if ( tk . type = = TK_BRACKET_OPEN ) {
TkPos pos2 = _get_tkpos ( ) ;
tk = _get_token ( ) ;
if ( tk . type = = TK_BRACKET_CLOSE ) {
array_size2 = array_size ;
tk = _get_token ( ) ;
} else {
_set_tkpos ( pos2 ) ;
Node * n = _parse_and_reduce_expression ( p_block , p_function_info ) ;
if ( ! n | | n - > type ! = Node : : TYPE_CONSTANT | | n - > get_datatype ( ) ! = TYPE_INT ) {
_set_error ( " Expected single integer constant > 0 " ) ;
return nullptr ;
}
ConstantNode * cnode = ( ConstantNode * ) n ;
if ( cnode - > values . size ( ) = = 1 ) {
array_size2 = cnode - > values [ 0 ] . sint ;
if ( array_size2 < = 0 ) {
_set_error ( " Expected single integer constant > 0 " ) ;
return nullptr ;
}
} else {
_set_error ( " Expected single integer constant > 0 " ) ;
return nullptr ;
}
tk = _get_token ( ) ;
if ( tk . type ! = TK_BRACKET_CLOSE ) {
_set_error ( " Expected ']' " ) ;
return nullptr ;
} else {
tk = _get_token ( ) ;
}
}
} else {
_set_error ( " Expected '[' " ) ;
return nullptr ;
}
if ( type ! = type2 | | struct_name ! = struct_name2 | | array_size ! = array_size2 ) {
String error_str = " Cannot convert from ' " ;
if ( type2 = = TYPE_STRUCT ) {
error_str + = struct_name2 ;
} else {
error_str + = get_datatype_name ( type2 ) ;
}
error_str + = " [ " ;
error_str + = itos ( array_size2 ) ;
error_str + = " ]' " ;
error_str + = " to ' " ;
if ( type = = TYPE_STRUCT ) {
error_str + = struct_name ;
} else {
error_str + = get_datatype_name ( type ) ;
}
error_str + = " [ " ;
error_str + = itos ( array_size ) ;
error_str + = " ]' " ;
_set_error ( error_str ) ;
return nullptr ;
}
}
ArrayConstructNode * an = alloc_node < ArrayConstructNode > ( ) ;
an - > datatype = type ;
an - > struct_name = struct_name ;
if ( tk . type = = TK_PARENTHESIS_OPEN | | auto_size ) { // initialization
while ( true ) {
Node * n = _parse_and_reduce_expression ( p_block , p_function_info ) ;
if ( ! n ) {
return nullptr ;
}
if ( type ! = n - > get_datatype ( ) | | struct_name ! = n - > get_datatype_name ( ) ) {
_set_error ( " Invalid assignment of ' " + ( n - > get_datatype ( ) = = TYPE_STRUCT ? n - > get_datatype_name ( ) : get_datatype_name ( n - > get_datatype ( ) ) ) + " ' to ' " + ( type = = TYPE_STRUCT ? struct_name : get_datatype_name ( type ) ) + " ' " ) ;
return nullptr ;
}
tk = _get_token ( ) ;
if ( tk . type = = TK_COMMA ) {
an - > initializer . push_back ( n ) ;
continue ;
} else if ( ! auto_size & & tk . type = = TK_PARENTHESIS_CLOSE ) {
an - > initializer . push_back ( n ) ;
break ;
} else if ( auto_size & & tk . type = = TK_CURLY_BRACKET_CLOSE ) {
an - > initializer . push_back ( n ) ;
break ;
} else {
if ( auto_size ) {
_set_error ( " Expected '}' or ',' " ) ;
} else {
_set_error ( " Expected ')' or ',' " ) ;
}
return nullptr ;
}
}
if ( an - > initializer . size ( ) ! = array_size ) {
_set_error ( " Array size mismatch " ) ;
return nullptr ;
}
} else {
_set_error ( " Expected array initialization! " ) ;
nexpr = _parse_array_constructor ( p_block , p_function_info , pstruct - > members [ i ] - > get_datatype ( ) , pstruct - > members [ i ] - > struct_name , pstruct - > members [ i ] - > array_size ) ;
if ( ! nexpr ) {
return nullptr ;
}
nexpr = an ;
} else {
nexpr = _parse_and_reduce_expression ( p_block , p_function_info ) ;
if ( ! nexpr ) {
@ -3733,6 +3733,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else {
//an identifier
last_const = false ;
_set_tkpos ( pos ) ;
DataType data_type ;
@ -3760,6 +3761,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
_set_error ( " Unknown identifier in expression: " + String ( identifier ) ) ;
return nullptr ;
}
last_const = is_const ;
if ( ident_type = = IDENTIFIER_FUNCTION ) {
_set_error ( " Can't use function as identifier: " + String ( identifier ) ) ;
@ -3769,16 +3771,30 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
Node * index_expression = nullptr ;
Node * call_expression = nullptr ;
Node * assign_expression = nullptr ;
if ( array_size > 0 ) {
tk = _get_token ( ) ;
if ( tk . type ! = TK_BRACKET_OPEN & & tk . type ! = TK_PERIOD ) {
_set_error ( " Expected '[' or '. '" ) ;
if ( tk . type ! = TK_BRACKET_OPEN & & tk . type ! = TK_PERIOD & & tk . type ! = TK_OP_ASSIGN ) {
_set_error ( " Expected '[' ,'.' or '= '" ) ;
return nullptr ;
}
if ( tk . type = = TK_PERIOD ) {
if ( tk . type = = TK_OP_ASSIGN ) {
if ( is_const ) {
_set_error ( " Constants cannot be modified. " ) ;
return nullptr ;
}
if ( shader - > varyings . has ( identifier ) & & current_function ! = String ( " vertex " ) ) {
_set_error ( " Varyings can only be assigned in vertex function. " ) ;
return nullptr ;
}
assign_expression = _parse_array_constructor ( p_block , p_function_info , data_type , struct_name , array_size ) ;
if ( ! assign_expression ) {
return nullptr ;
}
} else if ( tk . type = = TK_PERIOD ) {
completion_class = TAG_ARRAY ;
p_block - > block_tag = SubClassTag : : TAG_ARRAY ;
call_expression = _parse_and_reduce_expression ( p_block , p_function_info ) ;
@ -3825,6 +3841,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
arrname - > struct_name = struct_name ;
arrname - > index_expression = index_expression ;
arrname - > call_expression = call_expression ;
arrname - > assign_expression = assign_expression ;
arrname - > is_const = is_const ;
expr = arrname ;
@ -4165,7 +4182,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if ( array_size > 0 ) {
tk = _get_token ( ) ;
if ( tk . type = = TK_PERIOD ) {
if ( tk . type = = TK_OP_ASSIGN ) {
if ( last_const ) {
last_const = false ;
_set_error ( " Constants cannot be modified. " ) ;
return nullptr ;
}
Node * assign_expression = _parse_array_constructor ( p_block , p_function_info , member_type , member_struct_name , array_size ) ;
if ( ! assign_expression ) {
return nullptr ;
}
mn - > assign_expression = assign_expression ;
} else if ( tk . type = = TK_PERIOD ) {
_set_error ( " Nested array length() is not yet implemented " ) ;
return nullptr ;
} else if ( tk . type = = TK_BRACKET_OPEN ) {
@ -4200,7 +4228,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
mn - > index_expression = index_expression ;
} else {
_set_error ( " Expected '[' or '. '" ) ;
_set_error ( " Expected '[' ,'.' or '= '" ) ;
return nullptr ;
}
}