diff options
Diffstat (limited to 'modules/gdscript/gdscript_parser.cpp')
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 140 |
1 files changed, 80 insertions, 60 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 6ef3ab67ae..112569a8d6 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 */ @@ -3349,7 +3349,12 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } p_block->statements.push_back(expression); if (!_end_statement()) { - _set_error("Expected end of statement after expression."); + // Attempt to guess a better error message if the user "retypes" a variable + if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON && tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { + _set_error("Unexpected ':=', use '=' instead. Expected end of statement after expression."); + } else { + _set_error(String() + "Expected end of statement after expression, got " + tokenizer->get_token_name(tokenizer->get_token()) + " instead"); + } return; } @@ -4040,7 +4045,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN) { - tokenizer->advance(); +#define _ADVANCE_AND_CONSUME_NEWLINES \ + do { \ + tokenizer->advance(); \ + } while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE) + + _ADVANCE_AND_CONSUME_NEWLINES; + parenthesis++; String hint_prefix = ""; bool is_arrayed = false; @@ -4070,11 +4081,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } current_export.type = type; current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { // hint expected next! - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; switch (type) { @@ -4082,7 +4093,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "FLAGS") { - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { WARN_DEPRECATED_MSG("Exporting bit flags hint requires string constants."); @@ -4094,7 +4105,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } current_export.hint = PROPERTY_HINT_FLAGS; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; bool first = true; while (true) { @@ -4113,7 +4124,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { current_export.hint_string += c.xml_escape(); - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) break; @@ -4122,7 +4133,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { _set_error("Expected \")\" or \",\" in the named bit flags hint."); return; } - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; } break; @@ -4130,7 +4141,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_2D_RENDER") { - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" in the layers 2D render hint."); return; @@ -4141,7 +4152,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_2D_PHYSICS") { - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" in the layers 2D physics hint."); return; @@ -4152,7 +4163,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_3D_RENDER") { - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" in the layers 3D render hint."); return; @@ -4163,7 +4174,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "LAYERS_3D_PHYSICS") { - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" in the layers 3D physics hint."); return; @@ -4193,7 +4204,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { current_export.hint_string += c.xml_escape(); - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) break; @@ -4203,7 +4214,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; } break; @@ -4215,7 +4226,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "EASE") { current_export.hint = PROPERTY_HINT_EXP_EASING; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" in the hint."); return; @@ -4227,7 +4238,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "EXP") { current_export.hint = PROPERTY_HINT_EXP_RANGE; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) break; @@ -4235,7 +4246,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { _set_error("Expected \")\" or \",\" in the exponential range hint."); return; } - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; } else current_export.hint = PROPERTY_HINT_RANGE; @@ -4243,7 +4254,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_SUB) { sign = -1; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; } if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) { @@ -4253,7 +4264,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } current_export.hint_string = rtos(sign * double(tokenizer->get_token_constant())); - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { current_export.hint_string = "0," + current_export.hint_string; @@ -4267,12 +4278,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; sign = 1.0; if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_SUB) { sign = -1; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; } if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) { @@ -4283,7 +4294,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } current_export.hint_string += "," + rtos(sign * double(tokenizer->get_token_constant())); - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) break; @@ -4295,11 +4306,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; sign = 1.0; if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_SUB) { sign = -1; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; } if (tokenizer->get_token() != GDScriptTokenizer::TK_CONSTANT || !tokenizer->get_token_constant().is_num()) { @@ -4310,7 +4321,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } current_export.hint_string += "," + rtos(sign * double(tokenizer->get_token_constant())); - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; } break; case Variant::STRING: { @@ -4335,7 +4346,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { first = false; current_export.hint_string += c.xml_escape(); - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) break; @@ -4344,7 +4355,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { _set_error("Expected \")\" or \",\" in the enumeration hint."); return; } - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; } break; @@ -4352,13 +4363,13 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "DIR") { - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) current_export.hint = PROPERTY_HINT_DIR; else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_IDENTIFIER || !(tokenizer->get_token_identifier() == "GLOBAL")) { _set_error("Expected \"GLOBAL\" after comma in the directory hint."); @@ -4369,7 +4380,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } current_export.hint = PROPERTY_HINT_GLOBAL_DIR; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" in the hint."); @@ -4385,11 +4396,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "FILE") { current_export.hint = PROPERTY_HINT_FILE; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "GLOBAL") { @@ -4398,12 +4409,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } current_export.hint = PROPERTY_HINT_GLOBAL_FILE; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_CLOSE) break; else if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; else { _set_error("Expected \")\" or \",\" in the hint."); return; @@ -4419,7 +4430,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } current_export.hint_string = tokenizer->get_token_constant(); - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; } if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { @@ -4432,7 +4443,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "MULTILINE") { current_export.hint = PROPERTY_HINT_MULTILINE_TEXT; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_CLOSE) { _set_error("Expected \")\" in the hint."); return; @@ -4459,7 +4470,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { _set_error("Color type hint expects RGB or RGBA as hints."); return; } - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; } break; default: { @@ -4510,11 +4521,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { bool is_flags = false; if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "FLAGS") { is_flags = true; - tokenizer->advance(); + _ADVANCE_AND_CONSUME_NEWLINES; } else { current_export = PropertyInfo(); _set_error("Expected \"FLAGS\" after comma."); @@ -4558,6 +4569,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } + tokenizer->advance(); + parenthesis--; + if (is_arrayed) { hint_prefix += itos(current_export.type); if (current_export.hint) { @@ -4567,8 +4581,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { current_export.hint = PROPERTY_HINT_TYPE_STRING; current_export.type = Variant::ARRAY; } - - tokenizer->advance(); +#undef _ADVANCE_AND_CONSUME_NEWLINES } if (tokenizer->get_token() != GDScriptTokenizer::TK_PR_VAR && tokenizer->get_token() != GDScriptTokenizer::TK_PR_ONREADY && tokenizer->get_token() != GDScriptTokenizer::TK_PR_REMOTE && tokenizer->get_token() != GDScriptTokenizer::TK_PR_MASTER && tokenizer->get_token() != GDScriptTokenizer::TK_PR_PUPPET && tokenizer->get_token() != GDScriptTokenizer::TK_PR_SYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_REMOTESYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_MASTERSYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_PUPPETSYNC && tokenizer->get_token() != GDScriptTokenizer::TK_PR_SLAVE) { @@ -8180,7 +8193,9 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { } #endif // DEBUG_ENABLED + bool type_match = check_types; if (check_types && !_is_type_compatible(lh_type, rh_type)) { + type_match = false; // Try supertype test if (_is_type_compatible(rh_type, lh_type)) { _mark_line_as_unsafe(op->line); @@ -8192,23 +8207,27 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { op->line); return; } - // Replace assignment with implicit conversion - BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); - convert->line = op->line; - convert->function = GDScriptFunctions::TYPE_CONVERT; - - ConstantNode *tgt_type = alloc_node<ConstantNode>(); - tgt_type->line = op->line; - tgt_type->value = (int)lh_type.builtin_type; - - OperatorNode *convert_call = alloc_node<OperatorNode>(); - convert_call->line = op->line; - convert_call->op = OperatorNode::OP_CALL; - convert_call->arguments.push_back(convert); - convert_call->arguments.push_back(op->arguments[1]); - convert_call->arguments.push_back(tgt_type); - - op->arguments.write[1] = convert_call; + if (op->op == OperatorNode::OP_ASSIGN) { + // Replace assignment with implicit conversion + BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); + convert->line = op->line; + convert->function = GDScriptFunctions::TYPE_CONVERT; + + ConstantNode *tgt_type = alloc_node<ConstantNode>(); + tgt_type->line = op->line; + tgt_type->value = (int)lh_type.builtin_type; + + OperatorNode *convert_call = alloc_node<OperatorNode>(); + convert_call->line = op->line; + convert_call->op = OperatorNode::OP_CALL; + convert_call->arguments.push_back(convert); + convert_call->arguments.push_back(op->arguments[1]); + convert_call->arguments.push_back(tgt_type); + + op->arguments.write[1] = convert_call; + + type_match = true; // Since we are converting, the type is matching + } #ifdef DEBUG_ENABLED if (lh_type.builtin_type == Variant::INT && rh_type.builtin_type == Variant::REAL) { _add_warning(GDScriptWarning::NARROWING_CONVERSION, op->line); @@ -8221,6 +8240,7 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { _mark_line_as_unsafe(op->line); } #endif // DEBUG_ENABLED + op->datatype.has_type = type_match; } break; case OperatorNode::OP_CALL: case OperatorNode::OP_PARENT_CALL: { |