From 38613328e17aeda0eca78788f28211b1f66cd2d5 Mon Sep 17 00:00:00 2001 From: chloro <13125187405@163.com> Date: Thu, 13 Jun 2024 12:52:41 +0800 Subject: [PATCH] supporting enum --- include/wamon/enum_def.h | 34 ++++++++++++++++++++++++++++++++++ include/wamon/package_unit.h | 14 ++++++++++++-- include/wamon/parser.h | 4 ++++ include/wamon/token.h | 4 ++++ src/key_words.cc | 1 + src/package_unit.cc | 6 ++++++ src/parser.cc | 31 +++++++++++++++++++++++++++++-- test/parser_test.cc | 21 +++++++++++++++++++++ 8 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 include/wamon/enum_def.h diff --git a/include/wamon/enum_def.h b/include/wamon/enum_def.h new file mode 100644 index 0000000..1c97d69 --- /dev/null +++ b/include/wamon/enum_def.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +#include "wamon/exception.h" + +namespace wamon { + +class EnumDef { + public: + EnumDef(const std::string& enum_name) : enum_name_(enum_name) {} + + void AddEnumItem(const std::string& enum_id) { + auto it = std::find(enum_items_.begin(), enum_items_.end(), enum_id); + if (it != enum_items_.end()) { + throw WamonException("EnumDef.AddEnumItem error, duplicate enum id {}", enum_id); + } + enum_items_.push_back(enum_id); + } + + const std::string& GetEnumName() const { return enum_name_; } + + void SetEnumName(const std::string& name) { enum_name_ = name; } + + const std::vector& GetEnumItems() const { return enum_items_; } + + private: + std::string enum_name_; + std::vector enum_items_; +}; + +} // namespace wamon \ No newline at end of file diff --git a/include/wamon/package_unit.h b/include/wamon/package_unit.h index 831e104..dbfa0a9 100644 --- a/include/wamon/package_unit.h +++ b/include/wamon/package_unit.h @@ -9,6 +9,7 @@ #include "wamon/ast.h" #include "wamon/builtin_functions.h" +#include "wamon/enum_def.h" #include "wamon/exception.h" #include "wamon/function_def.h" #include "wamon/method_def.h" @@ -56,7 +57,7 @@ class PackageUnit { void AddFuncDef(std::unique_ptr&& func_def) { auto name = func_def->GetFunctionName(); if (funcs_.find(name) != funcs_.end()) { - throw WamonException("duplicate func {}", func_def->GetFunctionName()); + throw WamonException("duplicate func {}", name); } funcs_[name] = std::move(func_def); } @@ -64,11 +65,19 @@ class PackageUnit { void AddStructDef(std::unique_ptr&& struct_def) { auto name = struct_def->GetStructName(); if (structs_.find(name) != structs_.end()) { - throw WamonException("duplicate struct {}", struct_def->GetStructName()); + throw WamonException("duplicate struct {}", name); } structs_[name] = std::move(struct_def); } + void AddEnumDef(std::unique_ptr&& enum_def) { + auto name = enum_def->GetEnumName(); + if (enums_.find(name) != enums_.end()) { + throw WamonException("duplicate enum {}", name); + } + enums_[name] = std::move(enum_def); + } + void AddMethod(const std::string& type_name, std::unique_ptr&& methods) { assert(type_name.empty() == false); if (structs_.find(type_name) == structs_.end()) { @@ -171,6 +180,7 @@ class PackageUnit { std::vector> var_define_; std::unordered_map> funcs_; std::unordered_map> structs_; + std::unordered_map> enums_; BuiltinFunctions builtin_functions_; size_t lambda_count_{0}; // 只有通过Merge生成的PackageUnit才使用这项 diff --git a/include/wamon/parser.h b/include/wamon/parser.h index 04d7149..a86f15e 100644 --- a/include/wamon/parser.h +++ b/include/wamon/parser.h @@ -5,6 +5,7 @@ #include #include "wamon/ast.h" +#include "wamon/enum_def.h" #include "wamon/exception.h" #include "wamon/function_def.h" #include "wamon/parameter_list_item.h" @@ -116,6 +117,9 @@ std::unique_ptr TryToParseOperatorOverride(PackageUnit &pu, const s std::unique_ptr TryToParseStructDeclaration(PackageUnit &pu, const std::vector &tokens, size_t &begin); +std::unique_ptr TryToParseEnumDeclaration(PackageUnit &pu, const std::vector &tokens, + size_t &begin); + std::unique_ptr TryToParseVariableDeclaration(PackageUnit &pu, const std::vector &tokens, size_t &begin); diff --git a/include/wamon/token.h b/include/wamon/token.h index 3f9b15b..9f62bf0 100644 --- a/include/wamon/token.h +++ b/include/wamon/token.h @@ -87,6 +87,8 @@ enum class Token { STRUCT, TRAIT, DESTRUCTOR, + // 枚举定义 + ENUM, // 变量定义 LET, // 变量引用 @@ -242,6 +244,8 @@ inline const char *GetTokenStr(Token token) { return "trait"; case Token::DESTRUCTOR: return "destructor"; + case Token::ENUM: + return "enum"; case Token::LET: return "let"; case Token::REF: diff --git a/src/key_words.cc b/src/key_words.cc index d8d3c9e..7938430 100644 --- a/src/key_words.cc +++ b/src/key_words.cc @@ -24,6 +24,7 @@ static void register_buildin_keywords(std::unordered_map &kw kws["operator"] = Token::OPERATOR; kws["struct"] = Token::STRUCT; kws["destructor"] = Token::DESTRUCTOR; + kws["enum"] = Token::ENUM; kws["trait"] = Token::TRAIT; kws["let"] = Token::LET; kws["ref"] = Token::REF; diff --git a/src/package_unit.cc b/src/package_unit.cc index 0478073..db21200 100644 --- a/src/package_unit.cc +++ b/src/package_unit.cc @@ -26,6 +26,12 @@ PackageUnit PackageUnit::_MergePackageUnits(std::vector&& packages) result.AddFuncDef(std::move(func_define->second)); } + for (auto enum_define = it->enums_.begin(); enum_define != it->enums_.end(); ++enum_define) { + auto enum_name = enum_define->first; + enum_define->second->SetEnumName(it->GetName() + "$" + enum_name); + result.AddEnumDef(std::move(enum_define->second)); + } + for (auto struct_define = it->structs_.begin(); struct_define != it->structs_.end(); ++struct_define) { auto struct_name = struct_define->first; struct_define->second->SetStructName(it->GetName() + "$" + struct_name); diff --git a/src/parser.cc b/src/parser.cc index 51d1cef..ad284bf 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -38,6 +38,7 @@ void AssertTokenOrThrow(const std::vector &tokens, size_t &begin, To } // package_name, var_name +template std::pair ParseIdentifier(PackageUnit &pu, const std::vector &tokens, size_t &begin) { if (tokens.size() <= begin || tokens[begin].token != Token::ID || tokens[begin].type != WamonToken::ValueType::STR) { @@ -48,6 +49,9 @@ std::pair ParseIdentifier(PackageUnit &pu, const std:: if (tokens.size() <= begin || tokens[begin].token != Token::SCOPE) { return {pu.GetCurrentParsingPackage(), v1}; } + if constexpr (without_packagename) { + throw WamonException("ParseIdentifier error, without_packagename == true but still parse package_name {}", v1); + } begin += 1; if (tokens[begin].token != Token::ID || tokens[begin].type != WamonToken::ValueType::STR) { throw WamonException("parse identifier error : {}", GetTokenStr(tokens[begin].token)); @@ -938,18 +942,36 @@ std::unique_ptr TryToParseStructDeclaration(PackageUnit &pu, const st if (AssertToken(tokens, begin, Token::TRAIT)) { is_trait = true; } - auto [package_name, struct_name] = ParseIdentifier(pu, tokens, begin); + auto [package_name, struct_name] = ParseIdentifier(pu, tokens, begin); ret.reset(new StructDef(struct_name, is_trait)); AssertTokenOrThrow(tokens, begin, Token::LEFT_BRACE, __FILE__, __LINE__); while (AssertToken(tokens, begin, Token::RIGHT_BRACE) == false) { auto type = ParseType(pu, tokens, begin); - auto [pack_name, field_name] = ParseIdentifier(pu, tokens, begin); + auto [pack_name, field_name] = ParseIdentifier(pu, tokens, begin); AssertTokenOrThrow(tokens, begin, Token::SEMICOLON, __FILE__, __LINE__); ret->AddDataMember(field_name, std::move(type)); } return ret; } +std::unique_ptr TryToParseEnumDeclaration(PackageUnit &pu, const std::vector &tokens, + size_t &begin) { + std::unique_ptr ret(nullptr); + bool succ = AssertToken(tokens, begin, Token::ENUM); + if (succ == false) { + return ret; + } + auto [package_name, enum_name] = ParseIdentifier(pu, tokens, begin); + ret.reset(new EnumDef(enum_name)); + AssertTokenOrThrow(tokens, begin, Token::LEFT_BRACE, __FILE__, __LINE__); + while (AssertToken(tokens, begin, Token::RIGHT_BRACE) == false) { + auto [pn, fn] = ParseIdentifier(pu, tokens, begin); + AssertTokenOrThrow(tokens, begin, Token::SEMICOLON, __FILE__, __LINE__); + ret->AddEnumItem(fn); + } + return ret; +} + // let var_name : type = (expr_list); or // let var_name : type = expr; std::unique_ptr TryToParseVariableDeclaration(PackageUnit &pu, @@ -1047,6 +1069,11 @@ PackageUnit Parse(const std::vector &tokens) { package_unit.AddStructDef(std::move(struct_def)); continue; } + auto enum_def = TryToParseEnumDeclaration(package_unit, tokens, current_index); + if (enum_def != nullptr) { + package_unit.AddEnumDef(std::move(enum_def)); + continue; + } auto var_declaration = TryToParseVariableDeclaration(package_unit, tokens, current_index); if (var_declaration != nullptr) { package_unit.AddVarDef(std::move(var_declaration)); diff --git a/test/parser_test.cc b/test/parser_test.cc index 32e48c8..e2d5754 100644 --- a/test/parser_test.cc +++ b/test/parser_test.cc @@ -1,6 +1,7 @@ #include "wamon/parser.h" #include "gtest/gtest.h" +#include "wamon/enum_def.h" #include "wamon/exception.h" #include "wamon/package_unit.h" #include "wamon/scanner.h" @@ -368,3 +369,23 @@ TEST(parse, parse_type) { EXPECT_EQ(begin, tokens.size() - 1); EXPECT_EQ(type->IsBasicType(), false); } + +TEST(parse, parse_enum) { + wamon::Scanner scan; + std::string str = R"( + enum Animal { + cat; + dog; + bird; + } + )"; + auto tokens = scan.Scan(str); + size_t begin = 0; + wamon::PackageUnit pu; + auto enum_def = wamon::TryToParseEnumDeclaration(pu, tokens, begin); + EXPECT_NE(enum_def, nullptr); + EXPECT_EQ(enum_def->GetEnumName(), "Animal"); + EXPECT_EQ(enum_def->GetEnumItems().size(), 3); + EXPECT_EQ(enum_def->GetEnumItems()[0], "cat"); + EXPECT_EQ(begin, tokens.size() - 1); +} \ No newline at end of file