Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typed GDScript #19264

Merged
merged 12 commits into from
Jul 21, 2018
2 changes: 1 addition & 1 deletion core/script_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class ScriptLanguage {
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0;
virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {}
virtual bool is_using_templates() { return false; }
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const = 0;
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, Set<int> *r_safe_lines = NULL) const = 0;
virtual String validate_path(const String &p_path) const { return ""; }
virtual Script *create_script() const = 0;
virtual bool has_named_classes() const = 0;
Expand Down
4 changes: 3 additions & 1 deletion editor/connections_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,9 @@ void ConnectionsDock::update_tree() {
if (i > 0)
signaldesc += ", ";
String tname = "var";
if (pi.type != Variant::NIL) {
if (pi.type == Variant::OBJECT && pi.class_name != StringName()) {
tname = pi.class_name.operator String();
} else if (pi.type != Variant::NIL) {
tname = Variant::get_type_name(pi.type);
}
signaldesc += tname + " " + (pi.name == "" ? String("arg " + itos(i)) : pi.name);
Expand Down
3 changes: 3 additions & 0 deletions editor/editor_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {

_initial_set("text_editor/highlighting/highlight_all_occurrences", true);
_initial_set("text_editor/highlighting/highlight_current_line", true);
_initial_set("text_editor/highlighting/highlight_type_safe_lines", true);
_initial_set("text_editor/cursor/scroll_past_end_of_file", false);

_initial_set("text_editor/indent/type", 0);
Expand Down Expand Up @@ -404,6 +405,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/completion/callhint_tooltip_offset", Vector2());
_initial_set("text_editor/files/restore_scripts_on_load", true);
_initial_set("text_editor/completion/complete_file_paths", true);
_initial_set("text_editor/completion/add_type_hints", false);

_initial_set("docks/scene_tree/start_create_dialog_fully_expanded", false);
_initial_set("docks/scene_tree/draw_relationship_lines", false);
Expand Down Expand Up @@ -592,6 +594,7 @@ void EditorSettings::_load_default_text_editor_theme() {
_initial_set("text_editor/highlighting/completion_font_color", Color::html("aaaaaa"));
_initial_set("text_editor/highlighting/text_color", Color::html("aaaaaa"));
_initial_set("text_editor/highlighting/line_number_color", Color::html("66aaaaaa"));
_initial_set("text_editor/highlighting/safe_line_number_color", Color::html("99aac8aa"));
_initial_set("text_editor/highlighting/caret_color", Color::html("aaaaaa"));
_initial_set("text_editor/highlighting/caret_background_color", Color::html("000000"));
_initial_set("text_editor/highlighting/text_selected_color", Color::html("000000"));
Expand Down
2 changes: 2 additions & 0 deletions editor/editor_themes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color completion_font_color = font_color;
const Color text_color = font_color;
const Color line_number_color = dim_color;
const Color safe_line_number_color = dim_color * Color(1, 1.2, 1, 1.5);
const Color caret_color = mono_color;
const Color caret_background_color = mono_color.inverted();
const Color text_selected_color = dark_color_3;
Expand Down Expand Up @@ -1123,6 +1124,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
setting->set_initial_value("text_editor/highlighting/completion_font_color", completion_font_color, true);
setting->set_initial_value("text_editor/highlighting/text_color", text_color, true);
setting->set_initial_value("text_editor/highlighting/line_number_color", line_number_color, true);
setting->set_initial_value("text_editor/highlighting/safe_line_number_color", safe_line_number_color, true);
setting->set_initial_value("text_editor/highlighting/caret_color", caret_color, true);
setting->set_initial_value("text_editor/highlighting/caret_background_color", caret_background_color, true);
setting->set_initial_value("text_editor/highlighting/text_selected_color", text_selected_color, true);
Expand Down
21 changes: 20 additions & 1 deletion editor/plugins/script_text_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ void ScriptTextEditor::_load_theme_settings() {
Color completion_font_color = EDITOR_GET("text_editor/highlighting/completion_font_color");
Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
Color line_number_color = EDITOR_GET("text_editor/highlighting/line_number_color");
Color safe_line_number_color = EDITOR_GET("text_editor/highlighting/safe_line_number_color");
Color caret_color = EDITOR_GET("text_editor/highlighting/caret_color");
Color caret_background_color = EDITOR_GET("text_editor/highlighting/caret_background_color");
Color text_selected_color = EDITOR_GET("text_editor/highlighting/text_selected_color");
Expand Down Expand Up @@ -147,6 +148,7 @@ void ScriptTextEditor::_load_theme_settings() {
text_edit->add_color_override("completion_font_color", completion_font_color);
text_edit->add_color_override("font_color", text_color);
text_edit->add_color_override("line_number_color", line_number_color);
text_edit->add_color_override("safe_line_number_color", safe_line_number_color);
text_edit->add_color_override("caret_color", caret_color);
text_edit->add_color_override("caret_background_color", caret_background_color);
text_edit->add_color_override("font_selected_color", text_selected_color);
Expand Down Expand Up @@ -589,6 +591,7 @@ void ScriptTextEditor::set_edited_script(const Ref<Script> &p_script) {

emit_signal("name_changed");
code_editor->update_line_and_column();
call_deferred("_validate_script");
}

void ScriptTextEditor::_validate_script() {
Expand All @@ -599,8 +602,9 @@ void ScriptTextEditor::_validate_script() {

String text = te->get_text();
List<String> fnc;
Set<int> safe_lines;

if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc)) {
if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc, &safe_lines)) {
String error_text = "error(" + itos(line) + "," + itos(col) + "): " + errortxt;
code_editor->set_error(error_text);
} else {
Expand All @@ -621,8 +625,23 @@ void ScriptTextEditor::_validate_script() {
}

line--;
bool highlight_safe = EDITOR_DEF("text_editor/highlighting/highlight_type_safe_lines", true);
bool last_is_safe = false;
for (int i = 0; i < te->get_line_count(); i++) {
te->set_line_as_marked(i, line == i);
if (highlight_safe) {
if (safe_lines.has(i + 1)) {
te->set_line_as_safe(i, true);
last_is_safe = true;
} else if (last_is_safe && (te->is_line_comment(i) || te->get_line(i).strip_edges().empty())) {
te->set_line_as_safe(i, true);
} else {
te->set_line_as_safe(i, false);
last_is_safe = false;
}
} else {
te->set_line_as_safe(i, false);
}
}

emit_signal("name_changed");
Expand Down
15 changes: 3 additions & 12 deletions main/tests/test_gdscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,6 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) {
case GDScriptParser::OperatorNode::OP_BIT_INVERT: {
txt = "~" + _parser_expr(c_node->arguments[0]);
} break;
case GDScriptParser::OperatorNode::OP_PREINC: {
} break;
case GDScriptParser::OperatorNode::OP_PREDEC: {
} break;
case GDScriptParser::OperatorNode::OP_INC: {
} break;
case GDScriptParser::OperatorNode::OP_DEC: {
} break;
case GDScriptParser::OperatorNode::OP_IN: {
txt = _parser_expr(c_node->arguments[0]) + " in " + _parser_expr(c_node->arguments[1]);
} break;
Expand Down Expand Up @@ -455,10 +447,9 @@ static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_i
print_line("\n");
}

for (int i = 0; i < p_class->constant_expressions.size(); i++) {

const GDScriptParser::ClassNode::Constant &constant = p_class->constant_expressions[i];
_print_indent(p_indent, "const " + String(constant.identifier) + "=" + _parser_expr(constant.expression));
for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_class->constant_expressions.front(); E; E = E->next()) {
const GDScriptParser::ClassNode::Constant &constant = E->get();
_print_indent(p_indent, "const " + String(E->key()) + "=" + _parser_expr(constant.expression));
}

for (int i = 0; i < p_class->variables.size(); i++) {
Expand Down
2 changes: 1 addition & 1 deletion modules/gdnative/nativescript/nativescript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,7 @@ Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const
s->set_class_name(p_class_name);
return Ref<NativeScript>(s);
}
bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const {
bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines) const {
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion modules/gdnative/nativescript/nativescript.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ class NativeScriptLanguage : public ScriptLanguage {
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const;
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
Expand Down
2 changes: 1 addition & 1 deletion modules/gdnative/pluginscript/pluginscript_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ Ref<Script> PluginScriptLanguage::get_template(const String &p_class_name, const
return script;
}

bool PluginScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const {
bool PluginScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines) const {
PoolStringArray functions;
if (_desc.validate) {
bool ret = _desc.validate(
Expand Down
2 changes: 1 addition & 1 deletion modules/gdnative/pluginscript/pluginscript_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class PluginScriptLanguage : public ScriptLanguage {
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const;
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, Set<int> *r_safe_lines = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
Expand Down
30 changes: 30 additions & 0 deletions modules/gdscript/editor/gdscript_highlighter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,11 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
bool in_keyword = false;
bool in_word = false;
bool in_function_name = false;
bool in_variable_declaration = false;
bool in_member_variable = false;
bool in_node_path = false;
bool is_hex_notation = false;
bool expect_type = false;
Color keyword_color;
Color color;

Expand Down Expand Up @@ -205,6 +207,8 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_

if (str[k] == '(') {
in_function_name = true;
} else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::TK_PR_VAR)) {
in_variable_declaration = true;
}
}

Expand All @@ -222,6 +226,28 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
if (is_symbol) {
in_function_name = false;
in_member_variable = false;

if (expect_type && str[j] != ' ' && str[j] != '\t' && str[j] != ':') {
expect_type = false;
}
if (j > 0 && str[j] == '>' && str[j - 1] == '-') {
expect_type = true;
}

if (in_variable_declaration || previous_text == "(" || previous_text == ",") {
int k = j;
// Skip space
while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) {
k++;
}

if (str[k] == ':') {
// has type hint
expect_type = true;
}
}

in_variable_declaration = false;
}

if (!in_node_path && in_region == -1 && str[j] == '$') {
Expand Down Expand Up @@ -256,6 +282,9 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
} else if (is_number) {
next_type = NUMBER;
color = number_color;
} else if (expect_type) {
next_type = TYPE;
color = type_color;
} else {
next_type = IDENTIFIER;
}
Expand Down Expand Up @@ -330,6 +359,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {

function_definition_color = EDITOR_GET("text_editor/highlighting/gdscript/function_definition_color");
node_path_color = EDITOR_GET("text_editor/highlighting/gdscript/node_path_color");
type_color = EDITOR_GET("text_editor/highlighting/base_type_color");
}

SyntaxHighlighter *GDScriptSyntaxHighlighter::create() {
Expand Down
4 changes: 3 additions & 1 deletion modules/gdscript/editor/gdscript_highlighter.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ class GDScriptSyntaxHighlighter : public SyntaxHighlighter {
FUNCTION,
KEYWORD,
MEMBER,
IDENTIFIER
IDENTIFIER,
TYPE,
};

// colours
Expand All @@ -56,6 +57,7 @@ class GDScriptSyntaxHighlighter : public SyntaxHighlighter {
Color number_color;
Color member_color;
Color node_path_color;
Color type_color;

public:
static SyntaxHighlighter *create();
Expand Down
64 changes: 49 additions & 15 deletions modules/gdscript/gdscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,16 +220,14 @@ void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
void GDScript::get_script_method_list(List<MethodInfo> *p_list) const {

for (const Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
GDScriptFunction *func = E->get();
MethodInfo mi;
mi.name = E->key();
for (int i = 0; i < E->get()->get_argument_count(); i++) {
PropertyInfo arg;
arg.type = Variant::NIL; //variant
arg.name = E->get()->get_argument_name(i);
mi.arguments.push_back(arg);
for (int i = 0; i < func->get_argument_count(); i++) {
mi.arguments.push_back(func->get_argument_type(i));
}

mi.return_val.name = "Variant";
mi.return_val = func->get_return_type();
p_list->push_back(mi);
}
}
Expand Down Expand Up @@ -277,16 +275,14 @@ MethodInfo GDScript::get_method_info(const StringName &p_method) const {
if (!E)
return MethodInfo();

GDScriptFunction *func = E->get();
MethodInfo mi;
mi.name = E->key();
for (int i = 0; i < E->get()->get_argument_count(); i++) {
PropertyInfo arg;
arg.type = Variant::NIL; //variant
arg.name = E->get()->get_argument_name(i);
mi.arguments.push_back(arg);
for (int i = 0; i < func->get_argument_count(); i++) {
mi.arguments.push_back(func->get_argument_type(i));
}

mi.return_val.name = "Variant";
mi.return_val = func->get_return_type();
return mi;
}

Expand Down Expand Up @@ -941,8 +937,12 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
if (err.error == Variant::CallError::CALL_OK) {
return true; //function exists, call was successful
}
} else
} else {
if (!E->get().data_type.is_type(p_value)) {
return false; // Type mismatch
}
members[E->get().index] = p_value;
}
return true;
}
}
Expand Down Expand Up @@ -1735,7 +1735,9 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"NAN",
"self",
"true",
"void",
// functions
"as",
"assert",
"breakpoint",
"class",
Expand Down Expand Up @@ -1824,8 +1826,40 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
if (parser.get_parse_tree() && parser.get_parse_tree()->type == GDScriptParser::Node::TYPE_CLASS) {

const GDScriptParser::ClassNode *c = static_cast<const GDScriptParser::ClassNode *>(parser.get_parse_tree());
if (r_base_type && c->extends_used && c->extends_class.size() == 1) {
*r_base_type = c->extends_class[0]; //todo, should work much better
if (r_base_type) {
GDScriptParser::DataType base_type;
if (c->base_type.has_type) {
base_type = c->base_type;
while (base_type.has_type && base_type.kind != GDScriptParser::DataType::NATIVE) {
switch (base_type.kind) {
case GDScriptParser::DataType::CLASS: {
base_type = base_type.class_type->base_type;
} break;
case GDScriptParser::DataType::GDSCRIPT: {
Ref<GDScript> gds = base_type.script_type;
if (gds.is_valid()) {
base_type.kind = GDScriptParser::DataType::NATIVE;
base_type.native_type = gds->get_instance_base_type();
} else {
base_type = GDScriptParser::DataType();
}
} break;
default: {
base_type = GDScriptParser::DataType();
} break;
}
}
}
if (base_type.has_type) {
*r_base_type = base_type.native_type;
} else {
// Fallback
if (c->extends_used && c->extends_class.size() == 1) {
*r_base_type = c->extends_class[0];
} else if (!c->extends_used) {
*r_base_type = "Reference";
}
}
}
return c->name;
}
Expand Down
Loading