diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 74a3d5e9e97..009100cb345 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -3152,6 +3152,110 @@ void GDParser::_parse_class(ClassNode *p_class) { return; } + } break; + case GDTokenizer::TK_PR_ENUM: { + //mutiple constant declarations.. + + int last_assign = -1; // Incremented by 1 right before the assingment. + String enum_name; + Dictionary enum_dict; + + tokenizer->advance(); + if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { + enum_name = tokenizer->get_token_identifier(); + tokenizer->advance(); + } + if (tokenizer->get_token() != GDTokenizer::TK_CURLY_BRACKET_OPEN) { + _set_error("Expected '{' in enum declaration"); + return; + } + tokenizer->advance(); + + while (true) { + if (tokenizer->get_token() == GDTokenizer::TK_NEWLINE) { + + tokenizer->advance(); // Ignore newlines + } else if (tokenizer->get_token() == GDTokenizer::TK_CURLY_BRACKET_CLOSE) { + + tokenizer->advance(); + break; // End of enum + } else if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + + if (tokenizer->get_token() == GDTokenizer::TK_EOF) { + _set_error("Unexpected end of file."); + } else { + _set_error(String("Unexpected ") + GDTokenizer::get_token_name(tokenizer->get_token()) + ", expected identifier"); + } + + return; + } else { // tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER + ClassNode::Constant constant; + + constant.identifier = tokenizer->get_token_identifier(); + + tokenizer->advance(); + + if (tokenizer->get_token() == GDTokenizer::TK_OP_ASSIGN) { + tokenizer->advance(); + + Node *subexpr = NULL; + + subexpr = _parse_and_reduce_expression(p_class, true, true); + if (!subexpr) { + if (_recover_from_completion()) { + break; + } + return; + } + + if (subexpr->type != Node::TYPE_CONSTANT) { + _set_error("Expected constant expression"); + } + + const ConstantNode *subexpr_const = static_cast(subexpr); + + if (subexpr_const->value.get_type() != Variant::INT) { + _set_error("Expected an int value for enum"); + } + + last_assign = subexpr_const->value; + + constant.expression = subexpr; + + } else { + last_assign = last_assign + 1; + ConstantNode *cn = alloc_node(); + cn->value = last_assign; + constant.expression = cn; + } + + if (tokenizer->get_token() == GDTokenizer::TK_COMMA) { + tokenizer->advance(); + } + + if (enum_name != "") { + const ConstantNode *cn = static_cast(constant.expression); + enum_dict[constant.identifier] = cn->value; + } + + p_class->constant_expressions.push_back(constant); + } + } + + if (enum_name != "") { + ClassNode::Constant enum_constant; + enum_constant.identifier = enum_name; + ConstantNode *cn = alloc_node(); + cn->value = enum_dict; + enum_constant.expression = cn; + p_class->constant_expressions.push_back(enum_constant); + } + + if (!_end_statement()) { + _set_error("Expected end of statement (enum)"); + return; + } + } break; default: { diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index 3d9d49303ad..65156f0a94b 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -95,6 +95,7 @@ const char *GDTokenizer::token_names[TK_MAX] = { "setget", "const", "var", + "enum", "preload", "assert", "yield", @@ -861,6 +862,7 @@ void GDTokenizerText::_advance() { { TK_PR_SIGNAL, "signal" }, { TK_PR_BREAKPOINT, "breakpoint" }, { TK_PR_CONST, "const" }, + { TK_PR_ENUM, "enum" }, //controlflow { TK_CF_IF, "if" }, { TK_CF_ELIF, "elif" }, diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index 1fe0910c372..84d15a56e0c 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -101,6 +101,7 @@ public: TK_PR_SETGET, TK_PR_CONST, TK_PR_VAR, + TK_PR_ENUM, TK_PR_PRELOAD, TK_PR_ASSERT, TK_PR_YIELD,