OSDN Git Service

Phrase2IRCompiler の NoteRepeatExpression と NoteRepeatEachExpression 部分を実装
authorstarg <starg@users.osdn.me>
Sun, 24 Jul 2016 10:23:52 +0000 (19:23 +0900)
committerstarg <starg@users.osdn.me>
Sun, 24 Jul 2016 10:23:52 +0000 (19:23 +0900)
include/exceptions/messageexception.hpp [new file with mode: 0644]
include/message/id.hpp
src/ast2ir/phrase2ir.cpp
src/ast2ir/phrase2ir.hpp

diff --git a/include/exceptions/messageexception.hpp b/include/exceptions/messageexception.hpp
new file mode 100644 (file)
index 0000000..0c2dada
--- /dev/null
@@ -0,0 +1,28 @@
+
+#pragma once
+
+#include <string>
+
+#include <exceptions/exception.hpp>
+#include <message/message.hpp>
+
+namespace YAMML
+{
+
+namespace Exceptions
+{
+
+class MessageException : public Exception
+{
+public:
+    MessageException(const Message::MessageItem& item)
+        : Exception("MessageException: MessageID=" + std::to_string(static_cast<int>(item.ID))), Item(item)
+    {
+    }
+
+    Message::MessageItem Item;
+};
+
+} // namespace Exceptions
+
+} // namespace YAMML
index ae13013..3e5e1d3 100644 (file)
@@ -12,7 +12,8 @@ enum class MessageID
     Unknown,
     UnknownInPhrase2IR,
     DuplicatedCompositionName,
-    DuplicatedPhraseName
+    DuplicatedPhraseName,
+    TooLargeRepeatCount
 };
 
 } // namespace Message
index 64a1388..0d866d2 100644 (file)
@@ -1,6 +1,7 @@
 
 #include <cassert>
 
+#include <algorithm>
 #include <deque>
 #include <exception>
 #include <string>
@@ -12,6 +13,7 @@
 #include <ast/attribute.hpp>
 #include <ast/phrase.hpp>
 #include <compiler/nested.hpp>
+#include <exceptions/messageexception.hpp>
 #include <message/message.hpp>
 #include <ir/block.hpp>
 #include <ir/module.hpp>
@@ -85,7 +87,8 @@ IR::BlockReference Phrase2IRCompiler::operator()(const AST::NoteSequenceBlock& a
     m_AttributeStack.push_back(ast.Attributes);
     AutoPop<decltype(m_AttributeStack)> autoPop(m_AttributeStack);
 
-    return {};
+    Compile(ast.Block, newIndex);
+    return newIndex;
 }
 
 IR::BlockReference Phrase2IRCompiler::operator()(const AST::NoteSequence& ast)
@@ -93,12 +96,70 @@ IR::BlockReference Phrase2IRCompiler::operator()(const AST::NoteSequence& ast)
     auto newIndex = IR::BlockReference{m_IR.Blocks.size()};
     m_IR.Blocks.emplace_back();
 
-    // bounds checking
-    m_IR.Blocks.at(newIndex.ID);
+    // with bounds checking
+    m_IR.Blocks.at(newIndex.ID).Attributes = Concat(m_AttributeStack);
 
     for (auto&& i : ast.Notes)
     {
-        m_IR.Blocks[newIndex.ID].Events.emplace_back((*this)(i));
+        for (auto&& j : i.Notes)
+        {
+            m_IR.Blocks[newIndex.ID].Events.emplace_back(j.apply_visitor(*this));
+        }
+    }
+
+    return newIndex;
+}
+
+IR::BlockReference Phrase2IRCompiler::operator()(const AST::NoteAndDuration& ast)
+{
+    return {};
+}
+
+IR::BlockReference Phrase2IRCompiler::operator()(const AST::NoteRepeatExpression& ast)
+{
+    auto newIndex = IR::BlockReference{m_IR.Blocks.size()};
+    m_IR.Blocks.emplace_back();
+
+    // with bounds checking
+    m_IR.Blocks.at(newIndex.ID).Attributes = Concat(m_AttributeStack);
+
+    LimitRepeatCount(ast.Count, ast.Location);
+
+    std::vector<IR::BlockReference> childBlockRefArray(ast.Notes.size());
+    std::transform(
+        ast.Notes.begin(),
+        ast.Notes.end(),
+        childBlockRefArray.begin(),
+        [this] (auto&& x) { return x.apply_visitor(*this); }
+    );
+
+    for (std::size_t i = 0; i < ast.Count; i++)
+    {
+        auto& events = m_IR.Blocks[newIndex.ID].Events;
+        events.insert(events.end(), childBlockRefArray.begin(), childBlockRefArray.end());
+    }
+
+    return newIndex;
+}
+
+IR::BlockReference Phrase2IRCompiler::operator()(const AST::NoteRepeatEachExpression& ast)
+{
+    auto newIndex = IR::BlockReference{m_IR.Blocks.size()};
+    m_IR.Blocks.emplace_back();
+
+    // with bounds checking
+    m_IR.Blocks.at(newIndex.ID).Attributes = Concat(m_AttributeStack);
+
+    LimitRepeatCount(ast.Count, ast.Location);
+
+    for (auto&& i : ast.Notes)
+    {
+        auto childBlockRef = i.apply_visitor(*this);
+
+        for (std::size_t j = 0; j < ast.Count; j++)
+        {
+            m_IR.Blocks[newIndex.ID].Events.emplace_back(childBlockRef);
+        }
     }
 
     return newIndex;
@@ -115,6 +176,24 @@ void Phrase2IRCompiler::Compile(const AST::NoteSequenceBlockWithoutAttributes& a
     }
 }
 
+void Phrase2IRCompiler::LimitRepeatCount(std::size_t count, const AST::SourceLocation& location)
+{
+    constexpr std::size_t MaxRepeatCount = 1024;
+
+    if (count > MaxRepeatCount)
+    {
+        throw Exceptions::MessageException(
+            Message::MessageItem{
+            Message::MessageKind::Error,
+            Message::MessageID::TooLargeRepeatCount,
+            m_IR.Name,
+            location,
+            {std::to_string(count), std::to_string(MaxRepeatCount)}
+        }
+        );
+    }
+}
+
 } // namespace AST2IR
 
 } // namespace YAMML
index 9fb63ef..2df80c6 100644 (file)
@@ -31,10 +31,14 @@ public:
     IR::BlockReference operator()(const AST::NoteSequenceBlock& ast);
 
     IR::BlockReference operator()(const AST::NoteSequence& ast);
-    IR::BlockReference operator()(const AST::NoteAndExpression& ast);
+
+    IR::BlockReference operator()(const AST::NoteAndDuration& ast);
+    IR::BlockReference operator()(const AST::NoteRepeatExpression& ast);
+    IR::BlockReference operator()(const AST::NoteRepeatEachExpression& ast);
 
 private:
     void Compile(const AST::NoteSequenceBlockWithoutAttributes& ast, IR::BlockReference index);
+    void LimitRepeatCount(std::size_t count, const AST::SourceLocation& location);
 
     IR::Module& m_IR;
     std::deque<std::vector<AST::Attribute>> m_AttributeStack;