diff options
Diffstat (limited to 'modules/gdscript')
| -rw-r--r-- | modules/gdscript/gd_compiler.cpp | 9 | ||||
| -rw-r--r-- | modules/gdscript/gd_compiler.h | 1 | ||||
| -rw-r--r-- | modules/gdscript/gd_editor.cpp | 149 | ||||
| -rw-r--r-- | modules/gdscript/gd_function.cpp | 27 | ||||
| -rw-r--r-- | modules/gdscript/gd_function.h | 3 | ||||
| -rw-r--r-- | modules/gdscript/gd_functions.cpp | 1 | ||||
| -rw-r--r-- | modules/gdscript/gd_functions.h | 1 | ||||
| -rw-r--r-- | modules/gdscript/gd_parser.cpp | 52 | ||||
| -rw-r--r-- | modules/gdscript/gd_parser.h | 4 | ||||
| -rw-r--r-- | modules/gdscript/gd_script.cpp | 16 | ||||
| -rw-r--r-- | modules/gdscript/gd_script.h | 6 | ||||
| -rw-r--r-- | modules/gdscript/gd_tokenizer.cpp | 6 | ||||
| -rw-r--r-- | modules/gdscript/gd_tokenizer.h | 2 | ||||
| -rw-r--r-- | modules/gdscript/register_types.cpp | 1 | ||||
| -rw-r--r-- | modules/gdscript/register_types.h | 1 |
15 files changed, 173 insertions, 106 deletions
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index 9591740438..d4ede4cb17 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -1013,7 +1014,7 @@ int GDCompiler::_parse_expression(CodeGen &codegen, const GDParser::Node *p_expr } } break; - case GDParser::OperatorNode::OP_EXTENDS: { + case GDParser::OperatorNode::OP_IS: { ERR_FAIL_COND_V(on->arguments.size() != 2, false); @@ -1310,6 +1311,7 @@ Error GDCompiler::_parse_block(CodeGen &codegen, const GDParser::BlockNode *p_bl } } break; case GDParser::Node::TYPE_ASSERT: { +#ifdef DEBUG_ENABLED // try subblocks const GDParser::AssertNode *as = static_cast<const GDParser::AssertNode *>(s); @@ -1320,6 +1322,7 @@ Error GDCompiler::_parse_block(CodeGen &codegen, const GDParser::BlockNode *p_bl codegen.opcodes.push_back(GDFunction::OPCODE_ASSERT); codegen.opcodes.push_back(ret); +#endif } break; case GDParser::Node::TYPE_BREAKPOINT: { #ifdef DEBUG_ENABLED @@ -1537,7 +1540,7 @@ Error GDCompiler::_parse_function(GDScript *p_script, const GDParser::ClassNode signature += "::0"; } - //funciton and class + //function and class if (p_class->name) { signature += "::" + String(p_class->name) + "." + String(func_name); @@ -1658,7 +1661,7 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa String sub = p_class->extends_class[i]; if (script->subclasses.has(sub)) { - Ref<Script> subclass = script->subclasses[sub]; //avoid reference from dissapearing + Ref<Script> subclass = script->subclasses[sub]; //avoid reference from disappearing script = subclass; } else { diff --git a/modules/gdscript/gd_compiler.h b/modules/gdscript/gd_compiler.h index c84bd97246..b7ff092eba 100644 --- a/modules/gdscript/gd_compiler.h +++ b/modules/gdscript/gd_compiler.h @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index bd428941e0..adf3c8edc4 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -26,10 +27,15 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "editor/editor_settings.h" #include "gd_compiler.h" #include "gd_script.h" #include "global_config.h" #include "os/file_access.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_file_system.h" +#include "editor/editor_settings.h" +#endif void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { @@ -49,11 +55,12 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str "# var a = 2\n" + "# var b = \"textvar\"\n\n" + "func _ready():\n" + - "\t# Called every time the node is added to the scene.\n" + - "\t# Initialization here\n" + - "\tpass\n"; + "%TS%# Called every time the node is added to the scene.\n" + + "%TS%# Initialization here\n" + + "%TS%pass\n"; _template = _template.replace("%BASE%", p_base_class_name); + _template = _template.replace("%TS%", _get_indentation()); Ref<GDScript> script; script.instance(); @@ -62,6 +69,19 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str return script; } +bool GDScriptLanguage::is_using_templates() { + + return true; +} + +void GDScriptLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) { + + String src = p_script->get_source_code(); + src = src.replace("%BASE%", p_base_class_name); + src = src.replace("%TS%", _get_indentation()); + p_script->set_source_code(src); +} + bool GDScriptLanguage::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 { GDParser parser; @@ -405,7 +425,7 @@ static Ref<Reference> _get_parent_class(GDCompletionContext &context) { if (script.is_null()) { return REF(); } - if (script->is_valid()) { + if (!script->is_valid()) { return REF(); } @@ -1070,7 +1090,7 @@ static bool _guess_identifier_type(GDCompletionContext &context, int p_line, con //return _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type); } - //try to guess from assignment in construtor or _ready + //try to guess from assignment in constructor or _ready if (_guess_identifier_from_assignment_in_function(context, p_line + 1, p_identifier, "_ready", r_type)) return true; if (_guess_identifier_from_assignment_in_function(context, p_line + 1, p_identifier, "_enter_tree", r_type)) @@ -1256,7 +1276,7 @@ static void _find_identifiers_in_class(GDCompletionContext &context, bool p_stat } } List<MethodInfo> methods; - ClassDB::get_method_list(type, &methods); + ClassDB::get_method_list(type, &methods, false, true); for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { if (E->get().name.begins_with("_")) continue; @@ -1314,7 +1334,7 @@ static void _find_identifiers(GDCompletionContext &context, int p_line, bool p_o static const char *_type_names[Variant::VARIANT_MAX] = { "null", "bool", "int", "float", "String", "Vector2", "Rect2", "Vector3", "Transform2D", "Plane", "Quat", "AABB", "Basis", "Transform", - "Color", "Image", "NodePath", "RID", "Object", "InputEvent", "Dictionary", "Array", "RawArray", "IntArray", "FloatArray", "StringArray", + "Color", "NodePath", "RID", "Object", "Dictionary", "Array", "RawArray", "IntArray", "FloatArray", "StringArray", "Vector2Array", "Vector3Array", "ColorArray" }; @@ -1404,25 +1424,21 @@ static void _make_function_hint(const GDParser::FunctionNode *p_func, int p_argi arghint += ")"; } -static void _find_type_arguments(GDCompletionContext &context, const GDParser::Node *p_node, int p_line, const StringName &p_method, const GDCompletionIdentifier &id, int p_argidx, Set<String> &result, String &arghint) { - - //print_line("find type arguments?"); - if (id.type == Variant::INPUT_EVENT && String(p_method) == "is_action" && p_argidx == 0) { - - List<PropertyInfo> pinfo; - GlobalConfig::get_singleton()->get_property_list(&pinfo); +void get_directory_contents(EditorFileSystemDirectory *p_dir, Set<String> &r_list) { - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - const PropertyInfo &pi = E->get(); + for (int i = 0; i < p_dir->get_subdir_count(); i++) { + get_directory_contents(p_dir->get_subdir(i), r_list); + } - if (!pi.name.begins_with("input/")) - continue; + for (int i = 0; i < p_dir->get_file_count(); i++) { + r_list.insert("\"" + p_dir->get_file_path(i) + "\""); + } +} - String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length()); - result.insert("\"" + name + "\""); - } +static void _find_type_arguments(GDCompletionContext &context, const GDParser::Node *p_node, int p_line, const StringName &p_method, const GDCompletionIdentifier &id, int p_argidx, Set<String> &result, String &arghint) { - } else if (id.type == Variant::OBJECT && id.obj_type != StringName()) { + //print_line("find type arguments?"); + if (id.type == Variant::OBJECT && id.obj_type != StringName()) { MethodBind *m = ClassDB::get_method(id.obj_type, p_method); if (!m) { @@ -1627,7 +1643,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N } else { //regular method - if (p_method.operator String() == "connect") { + if (p_method.operator String() == "connect" || (p_method.operator String() == "emit_signal" && p_argidx == 0)) { if (p_argidx == 0) { List<MethodInfo> sigs; @@ -1752,6 +1768,10 @@ static void _find_call_arguments(GDCompletionContext &context, const GDParser::N const GDParser::BuiltInFunctionNode *fn = static_cast<const GDParser::BuiltInFunctionNode *>(op->arguments[0]); MethodInfo mi = GDFunctions::get_info(fn->function); + if (mi.name == "load" && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) { + get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), result); + } + arghint = _get_visual_datatype(mi.return_val, false) + " " + GDFunctions::get_func_name(fn->function) + String("("); for (int i = 0; i < mi.arguments.size(); i++) { if (i > 0) @@ -2231,7 +2251,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } List<MethodInfo> mi; - ClassDB::get_method_list(t.obj_type, &mi); + ClassDB::get_method_list(t.obj_type, &mi, false, true); for (List<MethodInfo>::Element *E = mi.front(); E; E = E->next()) { if (E->get().name.begins_with("_")) @@ -2244,54 +2264,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } } else { - if (t.type == Variant::INPUT_EVENT) { - - //this is hardcoded otherwise it's not obvious - Set<String> exclude; - - for (int i = 0; i < InputEvent::TYPE_MAX; i++) { - - InputEvent ie; - ie.type = InputEvent::Type(i); - static const char *evnames[] = { - "# Common", - "# Key", - "# MouseMotion", - "# MouseButton", - "# JoypadMotion", - "# JoypadButton", - "# ScreenTouch", - "# ScreenDrag", - "# Action" - }; - - r_options->push_back(evnames[i]); - - Variant v = ie; - - if (i == 0) { - List<MethodInfo> mi; - v.get_method_list(&mi); - for (List<MethodInfo>::Element *E = mi.front(); E; E = E->next()) { - r_options->push_back(E->get().name + "("); - } - } - - List<PropertyInfo> pi; - v.get_property_list(&pi); - - for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) { - - if (i == 0) - exclude.insert(E->get().name); - else if (exclude.has(E->get().name)) - continue; - - r_options->push_back(E->get().name); - } - } - return OK; - } else { + //check InputEvent hint + { if (t.value.get_type() == Variant::NIL) { Variant::CallError ce; t.value = Variant::construct(t.type, NULL, 0, ce); @@ -2373,6 +2347,11 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } } break; + case GDParser::COMPLETION_RESOURCE_PATH: { + + if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths")) + get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options); + } break; } for (Set<String>::Element *E = options.front(); E; E = E->next()) { @@ -2390,8 +2369,29 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base #endif +String GDScriptLanguage::_get_indentation() const { +#ifdef TOOLS_ENABLED + if (SceneTree::get_singleton()->is_editor_hint()) { + bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", 0); + + if (use_space_indentation) { + int indent_size = EDITOR_DEF("text_editor/indent/size", 4); + + String space_indent = ""; + for (int i = 0; i < indent_size; i++) { + space_indent += " "; + } + return space_indent; + } + } +#endif + return "\t"; +} + void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const { + String indent = _get_indentation(); + Vector<String> lines = p_code.split("\n"); List<int> indent_stack; @@ -2431,8 +2431,9 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t if (i >= p_from_line) { l = ""; - for (int j = 0; j < indent_stack.size(); j++) - l += "\t"; + for (int j = 0; j < indent_stack.size(); j++) { + l += indent; + } l += st; } else if (i > p_to_line) { diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp index aaf97001e9..e8a8e20927 100644 --- a/modules/gdscript/gd_function.cpp +++ b/modules/gdscript/gd_function.cpp @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -189,7 +190,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a if (p_state) { //use existing (supplied) state (yielded) stack = (Variant *)p_state->stack.ptr(); - call_args = (Variant **)stack + sizeof(Variant) * p_state->stack_size; + call_args = (Variant **)&p_state->stack.ptr()[sizeof(Variant) * p_state->stack_size]; //ptr() to avoid bounds check line = p_state->line; ip = p_state->ip; alloca_size = p_state->stack.size(); @@ -357,12 +358,12 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a if (a->get_type() != Variant::OBJECT || a->operator Object *() == NULL) { - err_text = "Left operand of 'extends' is not an instance of anything."; + err_text = "Left operand of 'is' is not an instance of anything."; break; } if (b->get_type() != Variant::OBJECT || b->operator Object *() == NULL) { - err_text = "Right operand of 'extends' is not a class."; + err_text = "Right operand of 'is' is not a class."; break; } #endif @@ -400,7 +401,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a if (!nc) { - err_text = "Right operand of 'extends' is not a class (type: '" + obj_B->get_class() + "')."; + err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "')."; break; } @@ -1432,9 +1433,21 @@ Variant GDFunctionState::_signal_callback(const Variant **p_args, int p_argcount return ret; } -bool GDFunctionState::is_valid() const { +bool GDFunctionState::is_valid(bool p_extended_check) const { - return function != NULL; + if (function == NULL) + return false; + + if (p_extended_check) { + //class instance gone? + if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) + return false; + //script gone? + if (state.script_id && !ObjectDB::get_instance(state.script_id)) + return false; + } + + return true; } Variant GDFunctionState::resume(const Variant &p_arg) { @@ -1463,7 +1476,7 @@ Variant GDFunctionState::resume(const Variant &p_arg) { void GDFunctionState::_bind_methods() { ClassDB::bind_method(D_METHOD("resume:Variant", "arg"), &GDFunctionState::resume, DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("is_valid"), &GDFunctionState::is_valid); + ClassDB::bind_method(D_METHOD("is_valid", "extended_check"), &GDFunctionState::is_valid, DEFVAL(false)); ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &GDFunctionState::_signal_callback, MethodInfo("_signal_callback")); } diff --git a/modules/gdscript/gd_function.h b/modules/gdscript/gd_function.h index 321b3b6cfa..6d20b19777 100644 --- a/modules/gdscript/gd_function.h +++ b/modules/gdscript/gd_function.h @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -236,7 +237,7 @@ protected: static void _bind_methods(); public: - bool is_valid() const; + bool is_valid(bool p_extended_check = false) const; Variant resume(const Variant &p_arg = Variant()); GDFunctionState(); ~GDFunctionState(); diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index fa92f0a194..a361971ef4 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h index cde1a9210d..4d52abaeab 100644 --- a/modules/gdscript/gd_functions.h +++ b/modules/gdscript/gd_functions.h @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 86b97e27a9..75029a020b 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -76,7 +77,7 @@ bool GDParser::_enter_indent_block(BlockNode *p_block) { // be more python-like int current = tab_level.back()->get(); - tab_level.push_back(current + 1); + tab_level.push_back(current); return true; //_set_error("newline expected after ':'."); //return false; @@ -388,6 +389,19 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool } tokenizer->advance(); + if (tokenizer->get_token() == GDTokenizer::TK_CURSOR) { + completion_cursor = StringName(); + completion_node = p_parent; + completion_type = COMPLETION_RESOURCE_PATH; + completion_class = current_class; + completion_function = current_function; + completion_line = tokenizer->get_token_line(); + completion_block = current_block; + completion_argument = 0; + completion_found = true; + tokenizer->advance(); + } + String path; bool found_constant = false; bool valid = false; @@ -459,10 +473,10 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool _set_error("Expected ')' after 'preload' path"); return NULL; } + tokenizer->advance(); ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = res; - tokenizer->advance(); expr = constant; } else if (tokenizer->get_token() == GDTokenizer::TK_PR_YIELD) { @@ -1021,7 +1035,7 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool OperatorNode::Operator op; bool valid = true; -//assign, if allowed is only alowed on the first operator +//assign, if allowed is only allowed on the first operator #define _VALIDATE_ASSIGN \ if (!p_allow_assign) { \ _set_error("Unexpected assign."); \ @@ -1063,7 +1077,7 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool case GDTokenizer::TK_OP_BIT_AND: op = OperatorNode::OP_BIT_AND; break; case GDTokenizer::TK_OP_BIT_OR: op = OperatorNode::OP_BIT_OR; break; case GDTokenizer::TK_OP_BIT_XOR: op = OperatorNode::OP_BIT_XOR; break; - case GDTokenizer::TK_PR_EXTENDS: op = OperatorNode::OP_EXTENDS; break; + case GDTokenizer::TK_PR_IS: op = OperatorNode::OP_IS; break; case GDTokenizer::TK_CF_IF: op = OperatorNode::OP_TERNARY_IF; break; case GDTokenizer::TK_CF_ELSE: op = OperatorNode::OP_TERNARY_ELSE; break; default: valid = false; break; @@ -1103,7 +1117,7 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool switch (expression[i].op) { - case OperatorNode::OP_EXTENDS: + case OperatorNode::OP_IS: priority = -1; break; //before anything @@ -1253,7 +1267,7 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool // this is not invalid and can really appear // but it becomes invalid anyway because no binary op // can be followed by an unary op in a valid combination, - // due to how precedence works, unaries will always dissapear first + // due to how precedence works, unaries will always disappear first _set_error("Unexpected two consecutive operators after ternary if."); return NULL; @@ -1263,7 +1277,7 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool // this is not invalid and can really appear // but it becomes invalid anyway because no binary op // can be followed by an unary op in a valid combination, - // due to how precedence works, unaries will always dissapear first + // due to how precedence works, unaries will always disappear first _set_error("Unexpected two consecutive operators after ternary else."); return NULL; @@ -1300,7 +1314,7 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool // this is not invalid and can really appear // but it becomes invalid anyway because no binary op // can be followed by an unary op in a valid combination, - // due to how precedence works, unaries will always dissapear first + // due to how precedence works, unaries will always disappear first _set_error("Unexpected two consecutive operators."); return NULL; @@ -1406,7 +1420,7 @@ GDParser::Node *GDParser::_reduce_expression(Node *p_node, bool p_to_const) { } } - if (op->op == OperatorNode::OP_EXTENDS) { + if (op->op == OperatorNode::OP_IS) { //nothing much return op; } @@ -2258,7 +2272,16 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { p_block->statements.push_back(nl); #endif + bool is_first_line = true; + while (true) { + if (!is_first_line && tab_level.back()->prev() && tab_level.back()->prev()->get() == indent_level) { + // pythonic single-line expression, don't parse future lines + tab_level.pop_back(); + p_block->end_line = tokenizer->get_token_line(); + return; + } + is_first_line = false; GDTokenizer::Token token = tokenizer->get_token(); if (error_set) @@ -2412,7 +2435,7 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { p_block->sub_blocks.push_back(cf_if->body); if (!_enter_indent_block(cf_if->body)) { - _set_error("Expected intended block after 'if'"); + _set_error("Expected indented block after 'if'"); p_block->end_line = tokenizer->get_token_line(); return; } @@ -2427,9 +2450,8 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { while (true) { - while (tokenizer->get_token() == GDTokenizer::TK_NEWLINE) { - tokenizer->advance(); - } + while (tokenizer->get_token() == GDTokenizer::TK_NEWLINE && _parse_newline()) + ; if (tab_level.back()->get() < indent_level) { //not at current indent level p_block->end_line = tokenizer->get_token_line(); @@ -2604,7 +2626,7 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { ConstantNode *cn = alloc_node<ConstantNode>(); switch (args.size()) { - case 1: cn->value = constants[0]; break; + case 1: cn->value = (int)constants[0]; break; case 2: cn->value = Vector2(constants[0], constants[1]); break; case 3: cn->value = Vector3(constants[0], constants[1], constants[2]); break; } @@ -2617,7 +2639,7 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { on->arguments.push_back(tn); switch (args.size()) { - case 1: tn->vtype = Variant::REAL; break; + case 1: tn->vtype = Variant::INT; break; case 2: tn->vtype = Variant::VECTOR2; break; case 3: tn->vtype = Variant::VECTOR3; break; } diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index 8d2c136818..3ad3466624 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -215,7 +216,7 @@ public: OP_CALL, OP_PARENT_CALL, OP_YIELD, - OP_EXTENDS, + OP_IS, //indexing operator OP_INDEX, OP_INDEX_NAMED, @@ -436,6 +437,7 @@ public: COMPLETION_PARENT_FUNCTION, COMPLETION_METHOD, COMPLETION_CALL_ARGUMENTS, + COMPLETION_RESOURCE_PATH, COMPLETION_INDEX, COMPLETION_VIRTUAL_FUNC, COMPLETION_YIELD, diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index e1cc75acfc..1dcc442234 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -532,7 +533,7 @@ bool GDScript::_update_exports() { } } } else { - //print_line("unchaged is "+get_path()); + //print_line("unchanged is "+get_path()); } if (base_cache.is_valid()) { @@ -614,6 +615,11 @@ Error GDScript::reload(bool p_keep_state) { if (basedir != "") basedir = basedir.get_base_dir(); + if (basedir.find("res://") == -1 && basedir.find("user://") == -1) { + //loading a template, don't parse + return OK; + } + valid = false; GDParser parser; Error err = parser.parse(source, basedir, false, path); @@ -1271,7 +1277,7 @@ void GDInstance::call_multilevel_reversed(const StringName &p_method, const Vari void GDInstance::notification(int p_notification) { - //notification is not virutal, it gets called at ALL levels just like in C. + //notification is not virtual, it gets called at ALL levels just like in C. Variant value = p_notification; const Variant *args[1] = { &value }; @@ -1696,8 +1702,8 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so #ifdef TOOLS_ENABLED while (E->get()->placeholders.size()) { - Object *obj = E->get()->placeholders.front()->get()->get_owner(); + //save instance info List<Pair<StringName, Variant> > state; if (obj->get_script_instance()) { @@ -1705,6 +1711,9 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so obj->get_script_instance()->get_property_state(state); map[obj->get_instance_ID()] = state; obj->set_script(RefPtr()); + } else { + // no instance found. Let's remove it so we don't loop forever + E->get()->placeholders.erase(E->get()->placeholders.front()->get()); } } #endif @@ -1808,6 +1817,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "breakpoint", "class", "extends", + "is", "func", "preload", "setget", diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index d64cc9798d..0add348ca9 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -380,15 +381,20 @@ public: 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 is_using_templates(); + virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); 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 Script *create_script() const; virtual bool has_named_classes() const; + virtual bool can_inherit_from_file() { return true; } virtual int find_function(const String &p_function, const String &p_code) const; virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const; + virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return OK; } virtual Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint); #ifdef TOOLS_ENABLED virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_base_path, Object *p_owner, LookupResult &r_result); #endif + virtual String _get_indentation() const; virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const; virtual void add_global_constant(const StringName &p_variable, const Variant &p_value); diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index 981924191f..f4e0cc8e29 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -89,6 +90,7 @@ const char *GDTokenizer::token_names[TK_MAX] = { "func", "class", "extends", + "is", "onready", "tool", "static", @@ -117,6 +119,7 @@ const char *GDTokenizer::token_names[TK_MAX] = { "'.'", "'?'", "':'", + "'$'", "'\\n'", "PI", "_", @@ -798,10 +801,8 @@ void GDTokenizerText::_advance() { { Variant::BASIS, "Basis" }, { Variant::TRANSFORM, "Transform" }, { Variant::COLOR, "Color" }, - { Variant::IMAGE, "Image" }, { Variant::_RID, "RID" }, { Variant::OBJECT, "Object" }, - { Variant::INPUT_EVENT, "InputEvent" }, { Variant::NODE_PATH, "NodePath" }, { Variant::DICTIONARY, "Dictionary" }, { Variant::ARRAY, "Array" }, @@ -864,6 +865,7 @@ void GDTokenizerText::_advance() { { TK_PR_FUNCTION, "func" }, { TK_PR_CLASS, "class" }, { TK_PR_EXTENDS, "extends" }, + { TK_PR_IS, "is" }, { TK_PR_ONREADY, "onready" }, { TK_PR_TOOL, "tool" }, { TK_PR_STATIC, "static" }, diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index c1ed8ad92e..c051176097 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -95,6 +96,7 @@ public: TK_PR_FUNCTION, TK_PR_CLASS, TK_PR_EXTENDS, + TK_PR_IS, TK_PR_ONREADY, TK_PR_TOOL, TK_PR_STATIC, diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 5acd412f7e..41ea0c2a26 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h index 5778dfcadc..4e969f5bd4 100644 --- a/modules/gdscript/register_types.h +++ b/modules/gdscript/register_types.h @@ -6,6 +6,7 @@ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ |