|
@@ -212,7 +212,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
|
|
|
|
|
|
String ShaderLanguage::get_token_text(Token p_token) {
|
|
String ShaderLanguage::get_token_text(Token p_token) {
|
|
String name = token_names[p_token.type];
|
|
String name = token_names[p_token.type];
|
|
- if (p_token.type == TK_INT_CONSTANT || p_token.type == TK_REAL_CONSTANT) {
|
|
|
|
|
|
+ if (p_token.is_integer_constant() || p_token.type == TK_REAL_CONSTANT) {
|
|
name += "(" + rtos(p_token.constant) + ")";
|
|
name += "(" + rtos(p_token.constant) + ")";
|
|
} else if (p_token.type == TK_IDENTIFIER) {
|
|
} else if (p_token.type == TK_IDENTIFIER) {
|
|
name += "(" + String(p_token.text) + ")";
|
|
name += "(" + String(p_token.text) + ")";
|
|
@@ -515,51 +515,100 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
|
|
|
|
|
|
if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) {
|
|
if (_is_number(GETCHAR(0)) || (GETCHAR(0) == '.' && _is_number(GETCHAR(1)))) {
|
|
// parse number
|
|
// parse number
|
|
|
|
+ bool hexa_found = false;
|
|
bool period_found = false;
|
|
bool period_found = false;
|
|
bool exponent_found = false;
|
|
bool exponent_found = false;
|
|
- bool hexa_found = false;
|
|
|
|
- bool sign_found = false;
|
|
|
|
bool float_suffix_found = false;
|
|
bool float_suffix_found = false;
|
|
|
|
+ bool uint_suffix_found = false;
|
|
|
|
+ bool end_suffix_found = false;
|
|
|
|
+
|
|
|
|
+ enum {
|
|
|
|
+ CASE_ALL,
|
|
|
|
+ CASE_HEXA_PERIOD,
|
|
|
|
+ CASE_EXPONENT,
|
|
|
|
+ CASE_SIGN_AFTER_EXPONENT,
|
|
|
|
+ CASE_NONE,
|
|
|
|
+ CASE_MAX,
|
|
|
|
+ } lut_case = CASE_ALL;
|
|
|
|
+
|
|
|
|
+ static bool suffix_lut[CASE_MAX][127];
|
|
|
|
+
|
|
|
|
+ if (!is_const_suffix_lut_initialized) {
|
|
|
|
+ is_const_suffix_lut_initialized = true;
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < 127; i++) {
|
|
|
|
+ char t = char(i);
|
|
|
|
+
|
|
|
|
+ suffix_lut[CASE_ALL][i] = t == '.' || t == 'x' || t == 'e' || t == 'f' || t == 'u' || t == '-' || t == '+';
|
|
|
|
+ suffix_lut[CASE_HEXA_PERIOD][i] = t == 'e' || t == 'f';
|
|
|
|
+ suffix_lut[CASE_EXPONENT][i] = t == 'f' || t == '-' || t == '+';
|
|
|
|
+ suffix_lut[CASE_SIGN_AFTER_EXPONENT][i] = t == 'f';
|
|
|
|
+ suffix_lut[CASE_NONE][i] = false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
String str;
|
|
String str;
|
|
int i = 0;
|
|
int i = 0;
|
|
|
|
|
|
while (true) {
|
|
while (true) {
|
|
- if (GETCHAR(i) == '.') {
|
|
|
|
- if (period_found || exponent_found || hexa_found || float_suffix_found) {
|
|
|
|
- return _make_token(TK_ERROR, "Invalid numeric constant");
|
|
|
|
- }
|
|
|
|
- period_found = true;
|
|
|
|
- } else if (GETCHAR(i) == 'x') {
|
|
|
|
- if (hexa_found || str.length() != 1 || str[0] != '0') {
|
|
|
|
- return _make_token(TK_ERROR, "Invalid numeric constant");
|
|
|
|
|
|
+ const CharType symbol = String::char_lowercase(GETCHAR(i));
|
|
|
|
+ bool error = false;
|
|
|
|
+
|
|
|
|
+ if (_is_number(symbol)) {
|
|
|
|
+ if (end_suffix_found) {
|
|
|
|
+ error = true;
|
|
}
|
|
}
|
|
- hexa_found = true;
|
|
|
|
- } else if (GETCHAR(i) == 'e' && !hexa_found) {
|
|
|
|
- if (exponent_found || float_suffix_found) {
|
|
|
|
- return _make_token(TK_ERROR, "Invalid numeric constant");
|
|
|
|
|
|
+ } else {
|
|
|
|
+ if (symbol < 0x7F && suffix_lut[lut_case][symbol]) {
|
|
|
|
+ if (symbol == 'x') {
|
|
|
|
+ hexa_found = true;
|
|
|
|
+ lut_case = CASE_HEXA_PERIOD;
|
|
|
|
+ } else if (symbol == '.') {
|
|
|
|
+ period_found = true;
|
|
|
|
+ lut_case = CASE_HEXA_PERIOD;
|
|
|
|
+ } else if (symbol == 'e' && !hexa_found) {
|
|
|
|
+ exponent_found = true;
|
|
|
|
+ lut_case = CASE_EXPONENT;
|
|
|
|
+ } else if (symbol == 'f' && !hexa_found) {
|
|
|
|
+ if (!period_found && !exponent_found) {
|
|
|
|
+ error = true;
|
|
|
|
+ }
|
|
|
|
+ float_suffix_found = true;
|
|
|
|
+ end_suffix_found = true;
|
|
|
|
+ lut_case = CASE_NONE;
|
|
|
|
+ } else if (symbol == 'u') {
|
|
|
|
+ uint_suffix_found = true;
|
|
|
|
+ end_suffix_found = true;
|
|
|
|
+ lut_case = CASE_NONE;
|
|
|
|
+ } else if (symbol == '-' || symbol == '+') {
|
|
|
|
+ if (exponent_found) {
|
|
|
|
+ lut_case = CASE_SIGN_AFTER_EXPONENT;
|
|
|
|
+ } else {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else if (!hexa_found || !_is_hex(symbol)) {
|
|
|
|
+ if (_is_text_char(symbol)) {
|
|
|
|
+ error = true;
|
|
|
|
+ } else {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- exponent_found = true;
|
|
|
|
- } else if (GETCHAR(i) == 'f' && !hexa_found) {
|
|
|
|
- if (exponent_found) {
|
|
|
|
- return _make_token(TK_ERROR, "Invalid numeric constant");
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (error) {
|
|
|
|
+ if (hexa_found) {
|
|
|
|
+ return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant");
|
|
}
|
|
}
|
|
- float_suffix_found = true;
|
|
|
|
- } else if (_is_number(GETCHAR(i))) {
|
|
|
|
- if (float_suffix_found) {
|
|
|
|
- return _make_token(TK_ERROR, "Invalid numeric constant");
|
|
|
|
|
|
+ if (period_found || exponent_found || float_suffix_found) {
|
|
|
|
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
|
|
}
|
|
}
|
|
- } else if (hexa_found && _is_hex(GETCHAR(i))) {
|
|
|
|
- } else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) {
|
|
|
|
- if (sign_found) {
|
|
|
|
- return _make_token(TK_ERROR, "Invalid numeric constant");
|
|
|
|
|
|
+ if (uint_suffix_found) {
|
|
|
|
+ return _make_token(TK_ERROR, "Invalid (unsigned integer) numeric constant");
|
|
}
|
|
}
|
|
- sign_found = true;
|
|
|
|
- } else {
|
|
|
|
- break;
|
|
|
|
|
|
+ return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
|
|
}
|
|
}
|
|
-
|
|
|
|
- str += CharType(GETCHAR(i));
|
|
|
|
|
|
+ str += symbol;
|
|
i++;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -572,6 +621,9 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
|
|
}
|
|
}
|
|
} else if (period_found || exponent_found || float_suffix_found) {
|
|
} else if (period_found || exponent_found || float_suffix_found) {
|
|
//floats
|
|
//floats
|
|
|
|
+ if (exponent_found && (!_is_number(last_char) && last_char != 'f')) { // checks for eg: "2E", "2E-", "2E+"
|
|
|
|
+ return _make_token(TK_ERROR, "Invalid (float) numeric constant");
|
|
|
|
+ }
|
|
if (period_found) {
|
|
if (period_found) {
|
|
if (float_suffix_found) {
|
|
if (float_suffix_found) {
|
|
//checks for eg "1.f" or "1.99f" notations
|
|
//checks for eg "1.f" or "1.99f" notations
|
|
@@ -603,11 +655,18 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
//integers
|
|
//integers
|
|
- if (!_is_number(last_char)) {
|
|
|
|
- return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
|
|
|
|
|
|
+ if (uint_suffix_found) {
|
|
|
|
+ // Strip the suffix.
|
|
|
|
+ str = str.left(str.length() - 1);
|
|
|
|
+ // Compensate reading cursor position.
|
|
|
|
+ char_idx += 1;
|
|
}
|
|
}
|
|
if (!str.is_valid_integer()) {
|
|
if (!str.is_valid_integer()) {
|
|
- return _make_token(TK_ERROR, "Invalid numeric constant");
|
|
|
|
|
|
+ if (uint_suffix_found) {
|
|
|
|
+ return _make_token(TK_ERROR, "Invalid (usigned integer) numeric constant");
|
|
|
|
+ } else {
|
|
|
|
+ return _make_token(TK_ERROR, "Invalid (integer) numeric constant");
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -615,6 +674,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
|
|
Token tk;
|
|
Token tk;
|
|
if (period_found || exponent_found || float_suffix_found) {
|
|
if (period_found || exponent_found || float_suffix_found) {
|
|
tk.type = TK_REAL_CONSTANT;
|
|
tk.type = TK_REAL_CONSTANT;
|
|
|
|
+ } else if (uint_suffix_found) {
|
|
|
|
+ tk.type = TK_UINT_CONSTANT;
|
|
} else {
|
|
} else {
|
|
tk.type = TK_INT_CONSTANT;
|
|
tk.type = TK_INT_CONSTANT;
|
|
}
|
|
}
|
|
@@ -880,8 +941,9 @@ void ShaderLanguage::clear() {
|
|
completion_type = COMPLETION_NONE;
|
|
completion_type = COMPLETION_NONE;
|
|
completion_block = nullptr;
|
|
completion_block = nullptr;
|
|
completion_function = StringName();
|
|
completion_function = StringName();
|
|
- completion_class = SubClassTag::TAG_GLOBAL;
|
|
|
|
|
|
+ completion_class = TAG_GLOBAL;
|
|
completion_struct = StringName();
|
|
completion_struct = StringName();
|
|
|
|
+ completion_base = TYPE_VOID;
|
|
|
|
|
|
error_line = 0;
|
|
error_line = 0;
|
|
tk_line = 1;
|
|
tk_line = 1;
|
|
@@ -896,7 +958,7 @@ void ShaderLanguage::clear() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) {
|
|
|
|
|
|
+bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name, ConstantNode::Value *r_constant_value) {
|
|
if (p_builtin_types.has(p_identifier)) {
|
|
if (p_builtin_types.has(p_identifier)) {
|
|
if (r_data_type) {
|
|
if (r_data_type) {
|
|
*r_data_type = p_builtin_types[p_identifier].type;
|
|
*r_data_type = p_builtin_types[p_identifier].type;
|
|
@@ -993,12 +1055,17 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<String
|
|
if (r_array_size) {
|
|
if (r_array_size) {
|
|
*r_array_size = shader->constants[p_identifier].array_size;
|
|
*r_array_size = shader->constants[p_identifier].array_size;
|
|
}
|
|
}
|
|
- if (r_type) {
|
|
|
|
- *r_type = IDENTIFIER_CONSTANT;
|
|
|
|
- }
|
|
|
|
if (r_struct_name) {
|
|
if (r_struct_name) {
|
|
*r_struct_name = shader->constants[p_identifier].type_str;
|
|
*r_struct_name = shader->constants[p_identifier].type_str;
|
|
}
|
|
}
|
|
|
|
+ if (r_constant_value) {
|
|
|
|
+ if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->values.size() == 1) {
|
|
|
|
+ *r_constant_value = shader->constants[p_identifier].initializer->values[0];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (r_type) {
|
|
|
|
+ *r_type = IDENTIFIER_CONSTANT;
|
|
|
|
+ }
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2119,6 +2186,8 @@ const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[]
|
|
{ nullptr, 0 }
|
|
{ nullptr, 0 }
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+bool ShaderLanguage::is_const_suffix_lut_initialized = false;
|
|
|
|
+
|
|
bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
|
|
bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
|
|
ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false);
|
|
ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false);
|
|
|
|
|
|
@@ -2471,6 +2540,10 @@ bool ShaderLanguage::is_token_operator_assign(TokenType p_type) {
|
|
p_type == TK_OP_ASSIGN_BIT_XOR);
|
|
p_type == TK_OP_ASSIGN_BIT_XOR);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+bool ShaderLanguage::is_token_hint(TokenType p_type) {
|
|
|
|
+ return int(p_type) > int(TK_RENDER_MODE) && int(p_type) < int(TK_SHADER_TYPE);
|
|
|
|
+}
|
|
|
|
+
|
|
bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) {
|
|
bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) {
|
|
if (p_constant->datatype == p_to_type) {
|
|
if (p_constant->datatype == p_to_type) {
|
|
if (p_value) {
|
|
if (p_value) {
|
|
@@ -2898,6 +2971,69 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+Error ShaderLanguage::_parse_array_size(BlockNode *p_block, int *r_array_size) {
|
|
|
|
+ if (r_array_size != nullptr && *r_array_size > 0) {
|
|
|
|
+ _set_error("Array size is already defined!");
|
|
|
|
+ return ERR_PARSE_ERROR;
|
|
|
|
+ }
|
|
|
|
+ TkPos pos = _get_tkpos();
|
|
|
|
+ Token tk = _get_token();
|
|
|
|
+
|
|
|
|
+ int array_size = 0;
|
|
|
|
+
|
|
|
|
+ if (!tk.is_integer_constant() || ((int)tk.constant) <= 0) {
|
|
|
|
+ _set_tkpos(pos);
|
|
|
|
+ Node *n = _parse_and_reduce_expression(p_block, Map<StringName, BuiltInInfo>());
|
|
|
|
+ if (n) {
|
|
|
|
+ if (n->type == Node::TYPE_VARIABLE) {
|
|
|
|
+ VariableNode *vn = static_cast<VariableNode *>(n);
|
|
|
|
+ if (vn) {
|
|
|
|
+ ConstantNode::Value v;
|
|
|
|
+ DataType data_type;
|
|
|
|
+ bool is_const = false;
|
|
|
|
+
|
|
|
|
+ _find_identifier(p_block, Map<StringName, BuiltInInfo>(), vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v);
|
|
|
|
+
|
|
|
|
+ if (is_const) {
|
|
|
|
+ if (data_type == TYPE_INT) {
|
|
|
|
+ int32_t value = v.sint;
|
|
|
|
+ if (value > 0) {
|
|
|
|
+ array_size = value;
|
|
|
|
+ }
|
|
|
|
+ } else if (data_type == TYPE_UINT) {
|
|
|
|
+ uint32_t value = v.uint;
|
|
|
|
+ if (value > 0U) {
|
|
|
|
+ array_size = value;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else if (n->type == Node::TYPE_OPERATOR) {
|
|
|
|
+ _set_error("Array size expressions are not yet implemented.");
|
|
|
|
+ return ERR_PARSE_ERROR;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else if (((int)tk.constant) > 0) {
|
|
|
|
+ array_size = (uint32_t)tk.constant;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (array_size <= 0) {
|
|
|
|
+ _set_error("Expected single integer constant > 0");
|
|
|
|
+ return ERR_PARSE_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ tk = _get_token();
|
|
|
|
+ if (tk.type != TK_BRACKET_CLOSE) {
|
|
|
|
+ _set_error("Expected ']'");
|
|
|
|
+ return ERR_PARSE_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (r_array_size) {
|
|
|
|
+ *r_array_size = array_size;
|
|
|
|
+ }
|
|
|
|
+ return OK;
|
|
|
|
+}
|
|
|
|
+
|
|
ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, DataType p_type, const StringName &p_struct_name, int p_array_size) {
|
|
ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, DataType p_type, const StringName &p_struct_name, int p_array_size) {
|
|
DataType type = TYPE_VOID;
|
|
DataType type = TYPE_VOID;
|
|
String struct_name = "";
|
|
String struct_name = "";
|
|
@@ -3071,6 +3207,14 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|
constant->datatype = TYPE_INT;
|
|
constant->datatype = TYPE_INT;
|
|
expr = constant;
|
|
expr = constant;
|
|
|
|
|
|
|
|
+ } else if (tk.type == TK_UINT_CONSTANT) {
|
|
|
|
+ ConstantNode *constant = alloc_node<ConstantNode>();
|
|
|
|
+ ConstantNode::Value v;
|
|
|
|
+ v.uint = tk.constant;
|
|
|
|
+ constant->values.push_back(v);
|
|
|
|
+ constant->datatype = TYPE_UINT;
|
|
|
|
+ expr = constant;
|
|
|
|
+
|
|
} else if (tk.type == TK_TRUE) {
|
|
} else if (tk.type == TK_TRUE) {
|
|
//handle true constant
|
|
//handle true constant
|
|
ConstantNode *constant = alloc_node<ConstantNode>();
|
|
ConstantNode *constant = alloc_node<ConstantNode>();
|
|
@@ -3174,141 +3318,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|
if (!nexpr) {
|
|
if (!nexpr) {
|
|
return nullptr;
|
|
return nullptr;
|
|
}
|
|
}
|
|
-
|
|
|
|
- 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_builtin_types);
|
|
|
|
- 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_builtin_types);
|
|
|
|
- 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!");
|
|
|
|
- return nullptr;
|
|
|
|
- }
|
|
|
|
} else {
|
|
} else {
|
|
nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
|
|
nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
|
|
if (!nexpr) {
|
|
if (!nexpr) {
|
|
@@ -4771,7 +4780,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
|
if (tk.type == TK_BRACKET_CLOSE) {
|
|
if (tk.type == TK_BRACKET_CLOSE) {
|
|
unknown_size = true;
|
|
unknown_size = true;
|
|
} else {
|
|
} else {
|
|
- if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) {
|
|
|
|
|
|
+ if (!tk.is_integer_constant() || ((int)tk.constant) <= 0) {
|
|
_set_error("Expected integer constant > 0 or ']'");
|
|
_set_error("Expected integer constant > 0 or ']'");
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
@@ -5219,7 +5228,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
|
tk = _get_token();
|
|
tk = _get_token();
|
|
}
|
|
}
|
|
|
|
|
|
- if (tk.type != TK_INT_CONSTANT) {
|
|
|
|
|
|
+ if (!tk.is_integer_constant()) {
|
|
_set_error("Expected integer constant");
|
|
_set_error("Expected integer constant");
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
@@ -5638,17 +5647,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
- tk = _get_token();
|
|
|
|
|
|
+ StringName shader_type_identifier;
|
|
|
|
+ _get_completable_identifier(nullptr, COMPLETION_SHADER_TYPE, shader_type_identifier);
|
|
|
|
|
|
- if (tk.type != TK_IDENTIFIER) {
|
|
|
|
|
|
+ if (shader_type_identifier == StringName()) {
|
|
_set_error("Expected identifier after 'shader_type', indicating type of shader. Valid types are: " + _get_shader_type_list(p_shader_types));
|
|
_set_error("Expected identifier after 'shader_type', indicating type of shader. Valid types are: " + _get_shader_type_list(p_shader_types));
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
-
|
|
|
|
- String shader_type_identifier;
|
|
|
|
-
|
|
|
|
- shader_type_identifier = tk.text;
|
|
|
|
-
|
|
|
|
if (!p_shader_types.has(shader_type_identifier)) {
|
|
if (!p_shader_types.has(shader_type_identifier)) {
|
|
_set_error("Invalid shader type. Valid types are: " + _get_shader_type_list(p_shader_types));
|
|
_set_error("Invalid shader type. Valid types are: " + _get_shader_type_list(p_shader_types));
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
@@ -5770,53 +5775,70 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
- tk = _get_token();
|
|
|
|
- if (tk.type != TK_IDENTIFIER) {
|
|
|
|
- _set_error("Expected identifier!");
|
|
|
|
- return ERR_PARSE_ERROR;
|
|
|
|
- }
|
|
|
|
|
|
+ bool first = true;
|
|
|
|
+ bool fixed_array_size = false;
|
|
|
|
+ int array_size = 0;
|
|
|
|
|
|
- MemberNode *member = alloc_node<MemberNode>();
|
|
|
|
- member->precision = precision;
|
|
|
|
- member->datatype = type;
|
|
|
|
- member->struct_name = struct_name;
|
|
|
|
- member->name = tk.text;
|
|
|
|
|
|
+ do {
|
|
|
|
+ tk = _get_token();
|
|
|
|
|
|
- if (member_names.has(member->name)) {
|
|
|
|
- _set_error("Redefinition of '" + String(member->name) + "'");
|
|
|
|
- return ERR_PARSE_ERROR;
|
|
|
|
- }
|
|
|
|
- member_names.insert(member->name);
|
|
|
|
|
|
+ if (first) {
|
|
|
|
+ first = false;
|
|
|
|
|
|
- tk = _get_token();
|
|
|
|
- if (tk.type == TK_BRACKET_OPEN) {
|
|
|
|
- tk = _get_token();
|
|
|
|
- if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
|
|
|
|
- member->array_size = (int)tk.constant;
|
|
|
|
|
|
+ if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) {
|
|
|
|
+ _set_error("Expected identifier or '['.");
|
|
|
|
+ return ERR_PARSE_ERROR;
|
|
|
|
+ }
|
|
|
|
|
|
- tk = _get_token();
|
|
|
|
- if (tk.type == TK_BRACKET_CLOSE) {
|
|
|
|
- tk = _get_token();
|
|
|
|
- if (tk.type != TK_SEMICOLON) {
|
|
|
|
- _set_error("Expected ';'");
|
|
|
|
- return ERR_PARSE_ERROR;
|
|
|
|
|
|
+ if (tk.type == TK_BRACKET_OPEN) {
|
|
|
|
+ Error error = _parse_array_size(nullptr, &array_size);
|
|
|
|
+ if (error != OK) {
|
|
|
|
+ return error;
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- _set_error("Expected ']'");
|
|
|
|
- return ERR_PARSE_ERROR;
|
|
|
|
|
|
+ fixed_array_size = true;
|
|
|
|
+ tk = _get_token();
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- _set_error("Expected single integer constant > 0");
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (tk.type != TK_IDENTIFIER) {
|
|
|
|
+ _set_error("Expected identifier!");
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
- }
|
|
|
|
- st_node->members.push_back(member);
|
|
|
|
|
|
|
|
- if (tk.type != TK_SEMICOLON) {
|
|
|
|
- _set_error("Expected ']' or ';'");
|
|
|
|
- return ERR_PARSE_ERROR;
|
|
|
|
- }
|
|
|
|
- member_count++;
|
|
|
|
|
|
+ MemberNode *member = alloc_node<MemberNode>();
|
|
|
|
+ member->precision = precision;
|
|
|
|
+ member->datatype = type;
|
|
|
|
+ member->struct_name = struct_name;
|
|
|
|
+ member->name = tk.text;
|
|
|
|
+ member->array_size = array_size;
|
|
|
|
+
|
|
|
|
+ if (member_names.has(member->name)) {
|
|
|
|
+ _set_error("Redefinition of '" + String(member->name) + "'");
|
|
|
|
+ return ERR_PARSE_ERROR;
|
|
|
|
+ }
|
|
|
|
+ member_names.insert(member->name);
|
|
|
|
+ tk = _get_token();
|
|
|
|
+
|
|
|
|
+ if (tk.type == TK_BRACKET_OPEN) {
|
|
|
|
+ Error error = _parse_array_size(nullptr, &member->array_size);
|
|
|
|
+ if (error != OK) {
|
|
|
|
+ return error;
|
|
|
|
+ }
|
|
|
|
+ tk = _get_token();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!fixed_array_size) {
|
|
|
|
+ array_size = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (tk.type != TK_SEMICOLON && tk.type != TK_COMMA) {
|
|
|
|
+ _set_error("Expected ',' or ';' after struct member.");
|
|
|
|
+ return ERR_PARSE_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ st_node->members.push_back(member);
|
|
|
|
+ member_count++;
|
|
|
|
+ } while (tk.type == TK_COMMA); // another member
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (member_count == 0) {
|
|
if (member_count == 0) {
|
|
@@ -5934,9 +5956,19 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
tk = _get_token();
|
|
tk = _get_token();
|
|
|
|
|
|
if (tk.type == TK_COLON) {
|
|
if (tk.type == TK_COLON) {
|
|
|
|
+ completion_type = COMPLETION_HINT;
|
|
|
|
+ completion_base = type;
|
|
|
|
+
|
|
//hint
|
|
//hint
|
|
|
|
|
|
tk = _get_token();
|
|
tk = _get_token();
|
|
|
|
+ completion_line = tk.line;
|
|
|
|
+
|
|
|
|
+ if (!is_token_hint(tk.type)) {
|
|
|
|
+ _set_error("Expected valid type hint after ':'.");
|
|
|
|
+ return ERR_PARSE_ERROR;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (tk.type == TK_HINT_WHITE_TEXTURE) {
|
|
if (tk.type == TK_HINT_WHITE_TEXTURE) {
|
|
uniform2.hint = ShaderNode::Uniform::HINT_WHITE;
|
|
uniform2.hint = ShaderNode::Uniform::HINT_WHITE;
|
|
} else if (tk.type == TK_HINT_BLACK_TEXTURE) {
|
|
} else if (tk.type == TK_HINT_BLACK_TEXTURE) {
|
|
@@ -5977,7 +6009,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
tk = _get_token();
|
|
tk = _get_token();
|
|
}
|
|
}
|
|
|
|
|
|
- if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
|
|
|
|
|
|
+ if (tk.type != TK_REAL_CONSTANT && !tk.is_integer_constant()) {
|
|
_set_error("Expected integer constant");
|
|
_set_error("Expected integer constant");
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
@@ -6001,7 +6033,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
tk = _get_token();
|
|
tk = _get_token();
|
|
}
|
|
}
|
|
|
|
|
|
- if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
|
|
|
|
|
|
+ if (tk.type != TK_REAL_CONSTANT && !tk.is_integer_constant()) {
|
|
_set_error("Expected integer constant after ','");
|
|
_set_error("Expected integer constant after ','");
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
@@ -6014,7 +6046,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
if (tk.type == TK_COMMA) {
|
|
if (tk.type == TK_COMMA) {
|
|
tk = _get_token();
|
|
tk = _get_token();
|
|
|
|
|
|
- if (tk.type != TK_REAL_CONSTANT && tk.type != TK_INT_CONSTANT) {
|
|
|
|
|
|
+ if (tk.type != TK_REAL_CONSTANT && !tk.is_integer_constant()) {
|
|
_set_error("Expected integer constant after ','");
|
|
_set_error("Expected integer constant after ','");
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
@@ -6033,10 +6065,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
_set_error("Expected ','");
|
|
_set_error("Expected ','");
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
-
|
|
|
|
- } else {
|
|
|
|
- _set_error("Expected valid type hint after ':'.");
|
|
|
|
- return ERR_PARSE_ERROR;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && uniform2.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) {
|
|
if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && uniform2.hint != ShaderNode::Uniform::HINT_COLOR && type <= TYPE_MAT4) {
|
|
@@ -6074,6 +6102,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
_set_error("Expected ';'");
|
|
_set_error("Expected ';'");
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ completion_type = COMPLETION_NONE;
|
|
} else { // varying
|
|
} else { // varying
|
|
ShaderNode::Varying varying;
|
|
ShaderNode::Varying varying;
|
|
varying.type = type;
|
|
varying.type = type;
|
|
@@ -6094,7 +6124,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|
|
}
|
|
}
|
|
tk = _get_token();
|
|
tk = _get_token();
|
|
- if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
|
|
|
|
|
|
+ if (tk.is_integer_constant() && tk.constant > 0) {
|
|
varying.array_size = (int)tk.constant;
|
|
varying.array_size = (int)tk.constant;
|
|
|
|
|
|
tk = _get_token();
|
|
tk = _get_token();
|
|
@@ -6118,6 +6148,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
}
|
|
}
|
|
|
|
|
|
} break;
|
|
} break;
|
|
|
|
+ case TK_SHADER_TYPE: {
|
|
|
|
+ _set_error("Shader type is already defined.");
|
|
|
|
+ return ERR_PARSE_ERROR;
|
|
|
|
+ } break;
|
|
default: {
|
|
default: {
|
|
//function or constant variable
|
|
//function or constant variable
|
|
|
|
|
|
@@ -6216,7 +6250,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
if (tk.type == TK_BRACKET_CLOSE) {
|
|
if (tk.type == TK_BRACKET_CLOSE) {
|
|
unknown_size = true;
|
|
unknown_size = true;
|
|
tk = _get_token();
|
|
tk = _get_token();
|
|
- } else if (tk.type == TK_INT_CONSTANT && ((int)tk.constant) > 0) {
|
|
|
|
|
|
+ } else if (tk.is_integer_constant() && ((int)tk.constant) > 0) {
|
|
constant.array_size = (int)tk.constant;
|
|
constant.array_size = (int)tk.constant;
|
|
tk = _get_token();
|
|
tk = _get_token();
|
|
if (tk.type != TK_BRACKET_CLOSE) {
|
|
if (tk.type != TK_BRACKET_CLOSE) {
|
|
@@ -6493,6 +6527,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ for (int i = 0; i < shader->functions.size(); i++) {
|
|
|
|
+ if (!shader->functions[i].callable && shader->functions[i].name == name) {
|
|
|
|
+ _set_error("Redefinition of '" + String(name) + "'");
|
|
|
|
+ return ERR_PARSE_ERROR;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
ShaderNode::Function function;
|
|
ShaderNode::Function function;
|
|
|
|
|
|
function.callable = !p_functions.has(name);
|
|
function.callable = !p_functions.has(name);
|
|
@@ -6865,9 +6906,17 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
|
|
//do nothing
|
|
//do nothing
|
|
return OK;
|
|
return OK;
|
|
} break;
|
|
} break;
|
|
|
|
+ case COMPLETION_SHADER_TYPE: {
|
|
|
|
+ for (const Set<String>::Element *E = p_shader_types.front(); E; E = E->next()) {
|
|
|
|
+ ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
|
|
|
|
+ r_options->push_back(option);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return OK;
|
|
|
|
+ } break;
|
|
case COMPLETION_RENDER_MODE: {
|
|
case COMPLETION_RENDER_MODE: {
|
|
for (int i = 0; i < p_render_modes.size(); i++) {
|
|
for (int i = 0; i < p_render_modes.size(); i++) {
|
|
- ScriptCodeCompletionOption option(p_render_modes[i], ScriptCodeCompletionOption::KIND_ENUM);
|
|
|
|
|
|
+ ScriptCodeCompletionOption option(p_render_modes[i], ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
|
|
r_options->push_back(option);
|
|
r_options->push_back(option);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -6886,6 +6935,19 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
|
|
} break;
|
|
} break;
|
|
case COMPLETION_MAIN_FUNCTION: {
|
|
case COMPLETION_MAIN_FUNCTION: {
|
|
for (const Map<StringName, FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) {
|
|
for (const Map<StringName, FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) {
|
|
|
|
+ if (!E->get().main_function) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ bool found = false;
|
|
|
|
+ for (int i = 0; i < shader->functions.size(); i++) {
|
|
|
|
+ if (shader->functions[i].name == E->key()) {
|
|
|
|
+ found = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (found) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION);
|
|
ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION);
|
|
r_options->push_back(option);
|
|
r_options->push_back(option);
|
|
}
|
|
}
|
|
@@ -6940,7 +7002,9 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
|
|
matches.insert(E->key(), kind);
|
|
matches.insert(E->key(), kind);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+ for (Map<StringName, ShaderNode::Constant>::Element *E = shader->constants.front(); E; E = E->next()) {
|
|
|
|
+ matches.insert(E->key(), ScriptCodeCompletionOption::KIND_CONSTANT);
|
|
|
|
+ }
|
|
for (OrderedHashMap<StringName, ShaderNode::Varying>::Element E = shader->varyings.front(); E; E = E.next()) {
|
|
for (OrderedHashMap<StringName, ShaderNode::Varying>::Element E = shader->varyings.front(); E; E = E.next()) {
|
|
matches.insert(E.key(), ScriptCodeCompletionOption::KIND_VARIABLE);
|
|
matches.insert(E.key(), ScriptCodeCompletionOption::KIND_VARIABLE);
|
|
}
|
|
}
|
|
@@ -7143,6 +7207,38 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
|
|
}
|
|
}
|
|
|
|
|
|
} break;
|
|
} break;
|
|
|
|
+ case COMPLETION_HINT: {
|
|
|
|
+ if (completion_base == DataType::TYPE_VEC4) {
|
|
|
|
+ ScriptCodeCompletionOption option("hint_color", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
|
|
|
|
+ r_options->push_back(option);
|
|
|
|
+ } else if ((completion_base == DataType::TYPE_INT || completion_base == DataType::TYPE_FLOAT)) {
|
|
|
|
+ ScriptCodeCompletionOption option("hint_range", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
|
|
|
|
+
|
|
|
|
+ if (completion_base == DataType::TYPE_INT) {
|
|
|
|
+ option.insert_text = "hint_range(0, 100, 1)";
|
|
|
|
+ } else {
|
|
|
|
+ option.insert_text = "hint_range(0.0, 1.0, 0.1)";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ r_options->push_back(option);
|
|
|
|
+ } else if ((int(completion_base) > int(TYPE_MAT4) && int(completion_base) < int(TYPE_STRUCT))) {
|
|
|
|
+ static Vector<String> options;
|
|
|
|
+
|
|
|
|
+ if (options.empty()) {
|
|
|
|
+ options.push_back("hint_albedo");
|
|
|
|
+ options.push_back("hint_aniso");
|
|
|
|
+ options.push_back("hint_black");
|
|
|
|
+ options.push_back("hint_black_albedo");
|
|
|
|
+ options.push_back("hint_normal");
|
|
|
|
+ options.push_back("hint_white");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < options.size(); i++) {
|
|
|
|
+ ScriptCodeCompletionOption option(options[i], ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
|
|
|
|
+ r_options->push_back(option);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } break;
|
|
}
|
|
}
|
|
|
|
|
|
return ERR_PARSE_ERROR;
|
|
return ERR_PARSE_ERROR;
|