From 329848d9d5d8c230091aeccad8f1b1bc6a6172c3 Mon Sep 17 00:00:00 2001
From: Deukhoofd <Deukhoofd@gmail.com>
Date: Fri, 1 Jan 2021 23:41:37 +0100
Subject: [PATCH] Parse class attributes (shared, abstract, final, external),
 cleanup some parser code.

---
 src/CoreData/ClassAttr.hpp                | 25 +++++++++++++++++++++++
 src/Parser/Parser.cpp                     | 22 +++++++++++---------
 src/Parser/Statements/ParsedStatement.hpp | 20 ++++++++++--------
 3 files changed, 49 insertions(+), 18 deletions(-)
 create mode 100644 src/CoreData/ClassAttr.hpp

diff --git a/src/CoreData/ClassAttr.hpp b/src/CoreData/ClassAttr.hpp
new file mode 100644
index 0000000..5906eee
--- /dev/null
+++ b/src/CoreData/ClassAttr.hpp
@@ -0,0 +1,25 @@
+#ifndef MALACHSCRIPT_CLASSATTR_HPP
+#define MALACHSCRIPT_CLASSATTR_HPP
+
+namespace MalachScript {
+    enum class ClassAttr : uint8_t {
+        None = 0,
+        Shared = 1 << 1,
+        Abstract = 1 << 2,
+        Final = 1 << 3,
+        External = 1 << 4,
+    };
+
+    class ClassAttrHelpers {
+    public:
+        constexpr inline static bool Contains(ClassAttr set, ClassAttr flag) {
+            return (static_cast<uint8_t>(set) & static_cast<uint8_t>(flag)) != 0;
+        }
+        constexpr inline static ClassAttr Set(ClassAttr set, ClassAttr flag) {
+            return static_cast<ClassAttr>(static_cast<uint8_t>(set) | static_cast<uint8_t>(flag));
+        }
+    };
+
+}
+
+#endif // MALACHSCRIPT_CLASSATTR_HPP
diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp
index b83fff0..6cb0bec 100644
--- a/src/Parser/Parser.cpp
+++ b/src/Parser/Parser.cpp
@@ -9,8 +9,8 @@
     }
 
 #define EXPECT_TOKEN(token, kind)                                                                                      \
-    if (token->GetKind() != LexTokenKind::kind) {                                                                      \
-        logError(DiagnosticType::UnexpectedToken, token->GetSpan());                                                   \
+    if ((token)->GetKind() != LexTokenKind::kind) {                                                                    \
+        logError(DiagnosticType::UnexpectedToken, (token)->GetSpan());                                                 \
     } else {                                                                                                           \
         PROGRESS_TOKEN(token);                                                                                         \
     }
@@ -32,7 +32,8 @@ namespace MalachScript::Parser {
 
     const ParsedScriptStatement* Parser::ParseScript(const LexToken* firstToken, const log_func& log) {
         std::vector<const ParsedStatement*> statements;
-        statements.reserve(32);
+        const size_t reservedScriptSize = 32;
+        statements.reserve(reservedScriptSize);
         size_t current = 0;
         const auto* currentToken = firstToken;
         while (true) {
@@ -64,12 +65,13 @@ namespace MalachScript::Parser {
         const auto* current = currentToken;
         auto start = current->GetSpan().GetStart();
         bool lookingForClass = true;
+        ClassAttr classAttr = ClassAttr::None;
         while (lookingForClass) {
             switch (current->GetKind()) {
-                case LexTokenKind::SharedKeyword: break;
-                case LexTokenKind::AbstractKeyword: break;
-                case LexTokenKind::FinalKeyword: break;
-                case LexTokenKind::ExternalKeyword: break;
+                case LexTokenKind::SharedKeyword: ClassAttrHelpers::Set(classAttr, ClassAttr::Shared); break;
+                case LexTokenKind::AbstractKeyword: ClassAttrHelpers::Set(classAttr, ClassAttr::Abstract); break;
+                case LexTokenKind::FinalKeyword: ClassAttrHelpers::Set(classAttr, ClassAttr::Final); break;
+                case LexTokenKind::ExternalKeyword: ClassAttrHelpers::Set(classAttr, ClassAttr::External); break;
                 case LexTokenKind::ClassKeyword: lookingForClass = false; break;
                 default: return false;
             }
@@ -83,7 +85,6 @@ namespace MalachScript::Parser {
         PROGRESS_TOKEN(current);
         std::vector<Identifier> inherits;
         std::vector<const ParsedStatement*> body;
-        body.reserve(16);
 
         switch (current->GetKind()) {
             case LexTokenKind::SemicolonSymbol: {
@@ -132,7 +133,8 @@ namespace MalachScript::Parser {
             }
             default: throw;
         }
-        out = new ParsedClassStatement(TextSpan(start, current->GetSpan().GetEnd()), identifier, inherits, body);
+        out = new ParsedClassStatement(TextSpan(start, current->GetSpan().GetEnd()), classAttr, identifier, inherits,
+                                       body);
         currentToken = current;
         return true;
     }
@@ -716,7 +718,7 @@ namespace MalachScript::Parser {
     }
 
 #define EXPR_PARSER(operator, name, func)                                                                              \
-    operator name;                                                                                                     \
+    operator(name);                                                                                                    \
     if (func(name, current)) {                                                                                         \
         PROGRESS_TOKEN(current);                                                                                       \
         ScopedPtr<const ParsedStatement> rightHand = nullptr;                                                          \
diff --git a/src/Parser/Statements/ParsedStatement.hpp b/src/Parser/Statements/ParsedStatement.hpp
index f782455..270554d 100644
--- a/src/Parser/Statements/ParsedStatement.hpp
+++ b/src/Parser/Statements/ParsedStatement.hpp
@@ -4,6 +4,7 @@
 #include <utility>
 #include <vector>
 #include "../../CoreData/AccessModifier.hpp"
+#include "../../CoreData/ClassAttr.hpp"
 #include "../../CoreData/FuncAttr.hpp"
 #include "../../CoreData/TypeMod.hpp"
 #include "../../TextSpan.hpp"
@@ -41,24 +42,27 @@ namespace MalachScript::Parser {
     };
 
     class ParsedClassStatement : public ParsedStatementImpl<ParsedStatementKind::Class> {
-        Identifier _identifier;
-        std::vector<Identifier> _inherits;
-        std::vector<std::unique_ptr<const ParsedStatement>> _body;
-
     public:
-        ParsedClassStatement(TextSpan span, Identifier identifier, std::vector<Identifier> inherits,
-                             const std::vector<const ParsedStatement*>& body)
-            : ParsedStatementImpl<ParsedStatementKind::Class>(span), _identifier(identifier), _inherits(inherits),
-              _body(body.size()) {
+        ParsedClassStatement(TextSpan span, ClassAttr classAttr, Identifier identifier,
+                             std::vector<Identifier> inherits, const std::vector<const ParsedStatement*>& body)
+            : ParsedStatementImpl<ParsedStatementKind::Class>(span), _classAttr(classAttr), _identifier(identifier),
+              _inherits(inherits), _body(body.size()) {
             for (size_t i = 0; i < body.size(); i++)
                 _body[i] = std::unique_ptr<const ParsedStatement>(body[i]);
         }
 
+        [[nodiscard]] ClassAttr GetClassAttr() const noexcept { return _classAttr; }
         [[nodiscard]] const Identifier& GetIdentifier() const noexcept { return _identifier; }
         [[nodiscard]] const std::vector<Identifier>& GetInherits() const noexcept { return _inherits; }
         [[nodiscard]] const std::vector<std::unique_ptr<const ParsedStatement>>& GetBody() const noexcept {
             return _body;
         }
+
+    private:
+        ClassAttr _classAttr;
+        Identifier _identifier;
+        std::vector<Identifier> _inherits;
+        std::vector<std::unique_ptr<const ParsedStatement>> _body;
     };
 
     class ParsedTypeDefStatement : public ParsedStatementImpl<ParsedStatementKind::TypeDef> {