From 8aab9a06d4db1106dc733022f951db979e39f97b Mon Sep 17 00:00:00 2001 From: George Marques Date: Tue, 29 May 2018 23:16:51 -0300 Subject: Add typing syntax --- modules/gdscript/gdscript_parser.cpp | 89 +++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) (limited to 'modules/gdscript/gdscript_parser.cpp') diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index d62112d3f1..37781cb934 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -1087,6 +1087,27 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s break; } + /*****************/ + /* Parse Casting */ + /*****************/ + + bool has_casting = expr->type == Node::TYPE_CAST; + if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_AS) { + if (has_casting) { + _set_error("Unexpected 'as'."); + return NULL; + } + CastNode *cn = alloc_node(); + DataType casttype; + if (!_parse_type(casttype)) { + _set_error("Expected type after 'as'."); + return NULL; + } + has_casting = true; + cn->source_node = expr; + expr = cn; + } + /******************/ /* Parse Operator */ /******************/ @@ -1110,7 +1131,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s //assign, if allowed is only allowed on the first operator #define _VALIDATE_ASSIGN \ - if (!p_allow_assign) { \ + if (!p_allow_assign || has_casting) { \ _set_error("Unexpected assign."); \ return NULL; \ } \ @@ -2488,6 +2509,14 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { Node *assigned = NULL; + if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { + DataType vartype; + if (!_parse_type(vartype)) { + _set_error("Expected type for variable."); + return; + } + } + if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) { tokenizer->advance(); @@ -3150,7 +3179,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { //class inside class :D StringName name; - StringName extends; if (tokenizer->get_token(1) != GDScriptTokenizer::TK_IDENTIFIER) { @@ -3279,6 +3307,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); + if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { + DataType argtype; + if (!_parse_type(argtype)) { + _set_error("Expected type for argument."); + return; + } + } + if (defaulting && tokenizer->get_token() != GDScriptTokenizer::TK_OP_ASSIGN) { _set_error("Default parameter expected."); @@ -3386,6 +3422,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } + if (tokenizer->get_token() == GDScriptTokenizer::TK_FORWARD_ARROW) { + DataType rettype; + if (!_parse_type(rettype, true)) { + _set_error("Expected return type for function."); + return; + } + } + if (!_enter_indent_block(block)) { _set_error("Indented block expected."); @@ -4113,6 +4157,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; + if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { + DataType vartype; + if (!_parse_type(vartype)) { + _set_error("Expected type for class variable."); + return; + } + } + if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) { #ifdef DEBUG_ENABLED @@ -4272,6 +4324,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { constant.identifier = tokenizer->get_token_literal(); tokenizer->advance(); + if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { + DataType consttype; + if (!_parse_type(consttype)) { + _set_error("Expected type for class constant."); + return; + } + } + if (tokenizer->get_token() != GDScriptTokenizer::TK_OP_ASSIGN) { _set_error("Constant expects assignment."); return; @@ -4423,6 +4483,31 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } +bool GDScriptParser::_parse_type(DataType &r_type, bool p_can_be_void) { + tokenizer->advance(); + + r_type.has_type = true; + + switch (tokenizer->get_token()) { + case GDScriptTokenizer::TK_IDENTIFIER: { + StringName id = tokenizer->get_token_identifier(); + } break; + case GDScriptTokenizer::TK_BUILT_IN_TYPE: { + } break; + case GDScriptTokenizer::TK_PR_VOID: { + if (!p_can_be_void) { + return false; + } + } break; + default: { + return false; + } + } + + tokenizer->advance(); + return true; +} + void GDScriptParser::_set_error(const String &p_error, int p_line, int p_column) { if (error_set) -- cgit v1.2.3 From b7a00aead039a988f9e224ef5ad19688a17c971c Mon Sep 17 00:00:00 2001 From: George Marques Date: Tue, 29 May 2018 23:16:52 -0300 Subject: Move inheritance resolution to the parser --- modules/gdscript/gdscript_parser.cpp | 241 ++++++++++++++++++++++++++++++++++- 1 file changed, 237 insertions(+), 4 deletions(-) (limited to 'modules/gdscript/gdscript_parser.cpp') diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 37781cb934..69f71c6759 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3188,10 +3188,25 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { name = tokenizer->get_token_identifier(1); tokenizer->advance(2); + // Check if name is shadowing something else + if (ClassDB::class_exists(name)) { + _set_error("Class '" + String(name) + "' shadows a native class."); + return; + } 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; } + if (class_map.has(name)) { + _set_error("Class '" + String(name) + "' shadows another class in the file."); + return; + } + for (int i = 0; i < p_class->constant_expressions.size(); i++) { + if (p_class->constant_expressions[i].identifier == name) { + _set_error("Class '" + String(name) + "' shadows a constant of the outer class."); + return; + } + } ClassNode *newclass = alloc_node(); newclass->initializer = alloc_node(); @@ -3202,6 +3217,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { newclass->owner = p_class; p_class->subclasses.push_back(newclass); + class_map.insert(name, newclass); if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_EXTENDS) { @@ -4337,6 +4353,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } + int line = tokenizer->get_token_line(); + tokenizer->advance(); Node *subexpr = _parse_and_reduce_expression(p_class, true, true); @@ -4348,14 +4366,15 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (subexpr->type != Node::TYPE_CONSTANT) { - _set_error("Expected constant expression"); + _set_error("Expected constant expression", line); + return; } constant.expression = subexpr; p_class->constant_expressions.push_back(constant); if (!_end_statement()) { - _set_error("Expected end of statement (constant)"); + _set_error("Expected end of statement (constant)", line); return; } @@ -4415,17 +4434,19 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (subexpr->type != Node::TYPE_CONSTANT) { _set_error("Expected constant expression"); + return; } - const ConstantNode *subexpr_const = static_cast(subexpr); + ConstantNode *subexpr_const = static_cast(subexpr); if (subexpr_const->value.get_type() != Variant::INT) { _set_error("Expected an int value for enum"); + return; } last_assign = subexpr_const->value; - constant.expression = subexpr; + constant.expression = subexpr_const; } else { last_assign = last_assign + 1; @@ -4483,6 +4504,212 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } +void GDScriptParser::_determine_inheritance(ClassNode *p_class) { + + if (p_class->extends_used) { + //do inheritance + String path = p_class->extends_file; + + Ref script; + StringName native; + ClassNode *base_class = NULL; + + if (path != "") { + //path (and optionally subclasses) + + if (path.is_rel_path()) { + + String base = self_path; + + if (base == "" || base.is_rel_path()) { + _set_error("Could not resolve relative path for parent class: " + path, p_class->line); + return; + } + path = base.get_base_dir().plus_file(path).simplify_path(); + } + script = ResourceLoader::load(path); + if (script.is_null()) { + _set_error("Could not load base class: " + path, p_class->line); + return; + } + if (!script->is_valid()) { + + _set_error("Script not fully loaded (cyclic preload?): " + path, p_class->line); + return; + } + + if (p_class->extends_class.size()) { + + for (int i = 0; i < p_class->extends_class.size(); i++) { + + String sub = p_class->extends_class[i]; + if (script->get_subclasses().has(sub)) { + + Ref