diff options
Diffstat (limited to 'modules/gdscript')
-rw-r--r-- | modules/gdscript/gdscript.cpp | 45 | ||||
-rw-r--r-- | modules/gdscript/gdscript.h | 5 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 37 | ||||
-rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 27 | ||||
-rw-r--r-- | modules/gdscript/gdscript_tokenizer.cpp | 6 | ||||
-rw-r--r-- | modules/gdscript/gdscript_tokenizer.h | 1 |
7 files changed, 119 insertions, 4 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index f23e7854a5..b3ebd4fe4b 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1739,6 +1739,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "assert", "breakpoint", "class", + "class_name", "extends", "is", "func", @@ -1788,6 +1789,50 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { } } +bool GDScriptLanguage::handles_global_class_type(const String &p_type) const { + + return p_type == "GDScript"; +} + +String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type) const { + + PoolVector<uint8_t> sourcef; + Error err; + FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + if (err) { + return String(); + } + + int len = f->get_len(); + sourcef.resize(len + 1); + PoolVector<uint8_t>::Write w = sourcef.write(); + int r = f->get_buffer(w.ptr(), len); + f->close(); + memdelete(f); + ERR_FAIL_COND_V(r != len, String()); + w[len] = 0; + + String s; + if (s.parse_utf8((const char *)w.ptr())) { + return String(); + } + + GDScriptParser parser; + + parser.parse(s, p_path.get_base_dir(), true, p_path); + + 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 + } + return c->name; + } + + return String(); +} + GDScriptLanguage::GDScriptLanguage() { calls = 0; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index a35b0a10d5..d1c57a0330 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -439,6 +439,11 @@ public: virtual void get_recognized_extensions(List<String> *p_extensions) const; + /* GLOBAL CLASSES */ + + virtual bool handles_global_class_type(const String &p_type) const; + virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL) const; + GDScriptLanguage(); ~GDScriptLanguage(); }; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 85c36647a1..70f3d704ae 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -278,6 +278,41 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: return idx | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root) } + /* TRY GLOBAL CLASSES */ + + if (ScriptServer::is_global_class(identifier)) { + + const GDScriptParser::ClassNode *class_node = codegen.class_node; + while (class_node->owner) { + class_node = class_node->owner; + } + + if (class_node->name == identifier) { + _set_error("Using own name in class file is not allowed (creates a cyclic reference)", p_expression); + return -1; + } + + RES res = ResourceLoader::load(ScriptServer::get_global_class_path(identifier)); + if (res.is_null()) { + _set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression); + return -1; + } + + Variant key = res; + int idx; + + if (!codegen.constant_map.has(key)) { + + idx = codegen.constant_map.size(); + codegen.constant_map[key] = idx; + + } else { + idx = codegen.constant_map[key]; + } + + return idx | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS); //make it a local constant (faster access) + } + #ifdef TOOLS_ENABLED if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) { @@ -828,7 +863,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: if (on->arguments[0]->type == GDScriptParser::Node::TYPE_OPERATOR && (static_cast<GDScriptParser::OperatorNode *>(on->arguments[0])->op == GDScriptParser::OperatorNode::OP_INDEX || static_cast<GDScriptParser::OperatorNode *>(on->arguments[0])->op == GDScriptParser::OperatorNode::OP_INDEX_NAMED)) { - // SET (chained) MODE! + // SET (chained) MODE! #ifdef DEBUG_ENABLED if (static_cast<GDScriptParser::OperatorNode *>(on->arguments[0])->op == GDScriptParser::OperatorNode::OP_INDEX_NAMED) { const GDScriptParser::OperatorNode *inon = static_cast<GDScriptParser::OperatorNode *>(on->arguments[0]); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index c0c3bd7b06..c8d2d2e3e8 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1820,7 +1820,7 @@ static void _find_type_arguments(GDScriptCompletionContext &context, const GDScr } else { - //regular method + //regular method #if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) if (p_argidx < m->get_argument_count()) { PropertyInfo pi = m->get_argument_info(p_argidx); diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 9650563ee6..d62112d3f1 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3112,6 +3112,28 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } break; + case GDScriptTokenizer::TK_PR_CLASS_NAME: { + + if (p_class->owner) { + _set_error("'class_name' is only valid for the main class namespace."); + return; + } + if (tokenizer->get_token(1) != GDScriptTokenizer::TK_IDENTIFIER) { + + _set_error("'class_name' syntax: 'class_name <UniqueName>'"); + return; + } + + p_class->name = tokenizer->get_token_identifier(1); + + if (self_path != String() && ScriptServer::is_global_class(p_class->name) && ScriptServer::get_global_class_path(p_class->name) != self_path) { + _set_error("Unique global class '" + p_class->name + "' already exists at path: " + ScriptServer::get_global_class_path(p_class->name)); + return; + } + + tokenizer->advance(2); + + } break; case GDScriptTokenizer::TK_PR_TOOL: { if (p_class->tool) { @@ -3138,6 +3160,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { name = tokenizer->get_token_identifier(1); tokenizer->advance(2); + if (ScriptServer::is_global_class(name)) { + _set_error("Can't override name of unique global class '" + name + "' already exists at path: " + ScriptServer::get_global_class_path(p_class->name)); + return; + } + ClassNode *newclass = alloc_node<ClassNode>(); newclass->initializer = alloc_node<BlockNode>(); newclass->initializer->parent_class = newclass; diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 3c8e1ddbe4..1d30871e3f 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -91,6 +91,7 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = { "match", "func", "class", + "class_name", "extends", "is", "onready", @@ -187,6 +188,7 @@ static const _kws _keyword_list[] = { //func { GDScriptTokenizer::TK_PR_FUNCTION, "func" }, { GDScriptTokenizer::TK_PR_CLASS, "class" }, + { GDScriptTokenizer::TK_PR_CLASS_NAME, "class_name" }, { GDScriptTokenizer::TK_PR_EXTENDS, "extends" }, { GDScriptTokenizer::TK_PR_IS, "is" }, { GDScriptTokenizer::TK_PR_ONREADY, "onready" }, @@ -1135,9 +1137,9 @@ void GDScriptTokenizerText::advance(int p_amount) { _advance(); } - ////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////// -#define BYTECODE_VERSION 12 +#define BYTECODE_VERSION 13 Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) { diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index c4f1f9fd94..c1f611fe73 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -96,6 +96,7 @@ public: TK_CF_MATCH, TK_PR_FUNCTION, TK_PR_CLASS, + TK_PR_CLASS_NAME, TK_PR_EXTENDS, TK_PR_IS, TK_PR_ONREADY, |