From d4650ef055992adc3a70fb62176eb92c17029f32 Mon Sep 17 00:00:00 2001 From: starg Date: Wed, 7 Sep 2016 04:23:22 +0900 Subject: [PATCH 1/1] =?utf8?q?composition=20=E3=81=AE=E4=BE=9D=E5=AD=98?= =?utf8?q?=E9=96=A2=E4=BF=82=E3=81=AE=E5=BE=AA=E7=92=B0=E3=81=AE=E3=83=81?= =?utf8?q?=E3=82=A7=E3=83=83=E3=82=AF=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- include/ir2midi/context.hpp | 3 +- include/ir2midi/ir2midi.hpp | 13 +++++++- include/message/id.hpp | 3 ++ src/driver/msgcallback.cpp | 3 ++ src/ir2midi/command_insert.cpp | 13 +------- src/ir2midi/ir2midi.cpp | 74 +++++++++++++++++++++++++++++++++++++----- src/ir2midi/pch.hpp | 1 + 7 files changed, 87 insertions(+), 23 deletions(-) diff --git a/include/ir2midi/context.hpp b/include/ir2midi/context.hpp index bc19119..2eb3548 100644 --- a/include/ir2midi/context.hpp +++ b/include/ir2midi/context.hpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace YAMML @@ -50,7 +51,7 @@ public: virtual std::string GetSourceName() const = 0; virtual TrackCompilerContext& GetTrackContext(int trackNumber) = 0; - virtual bool CompileTrackBlock(const std::string& trackBlockName) = 0; + virtual void CompileTrackBlock(const std::string& trackBlockName, const AST::SourceLocation& location) = 0; virtual bool HasTrackBlock(const std::string& trackBlockName) const = 0; }; diff --git a/include/ir2midi/ir2midi.hpp b/include/ir2midi/ir2midi.hpp index b6c4e7d..2703bcc 100644 --- a/include/ir2midi/ir2midi.hpp +++ b/include/ir2midi/ir2midi.hpp @@ -1,6 +1,7 @@ #pragma once +#include #include #include #include @@ -9,6 +10,7 @@ #include #include +#include #include #include #include @@ -21,6 +23,13 @@ namespace YAMML namespace IR2MIDI { +class NameAndLocation +{ +public: + std::string Name; + AST::SourceLocation Location; +}; + class IR2MIDICompiler final : public Compiler::CompilerBase, public IIR2MIDICompiler, public boost::static_visitor<> { public: @@ -53,15 +62,16 @@ public: virtual std::string GetSourceName() const override; virtual TrackCompilerContext& GetTrackContext(int trackNumber) override; + virtual void CompileTrackBlock(const std::string& trackBlockName, const AST::SourceLocation& location) override; virtual bool HasTrackBlock(const std::string& trackBlockName) const override; private: void AddCommandProcessor(std::unique_ptr pProcessor); void InitializeCommandProcessors(); - virtual bool CompileTrackBlock(const std::string& trackBlockName) override; void CompileBlock(int trackNumber, IR::BlockReference blockRef); void Finalize(); + void CheckForRecursion(const std::string& trackBlockName, const AST::SourceLocation& location); void CheckForUnprocessedAttributes(const std::vector& attributes); void EnsureTrackInitialized(int number); @@ -73,6 +83,7 @@ private: MIDI::MIDIFile m_MIDI; std::vector m_Contexts; std::unordered_map> m_CommandProcessors; + std::deque m_TrackBlockCompilationStack; int m_LastEventTime = 0; }; diff --git a/include/message/id.hpp b/include/message/id.hpp index de21be8..7c7749a 100644 --- a/include/message/id.hpp +++ b/include/message/id.hpp @@ -82,6 +82,9 @@ enum class MessageID : int // IR2MIDI InvalidCommandName, + TrackBlockCompilationRecursion, + TrackBlockCompilationBackTrace, + TrackBlockCompilationBackTraceEntryPoint, WrongNumberOfCommandArguments, WrongTypeOfCommandArgument, diff --git a/src/driver/msgcallback.cpp b/src/driver/msgcallback.cpp index dda7af8..59a5071 100644 --- a/src/driver/msgcallback.cpp +++ b/src/driver/msgcallback.cpp @@ -103,6 +103,9 @@ MessagePrinter::MessagePrinter(IStdErrWriter* pStdErrWriter) // IR2MIDI {Message::MessageID::InvalidCommandName, "invalid command '{0}'"}, + {Message::MessageID::TrackBlockCompilationRecursion, "composition '{0}': circular dependency detected"}, + {Message::MessageID::TrackBlockCompilationBackTrace, "composition '{0}' was inserted from here"}, + {Message::MessageID::TrackBlockCompilationBackTraceEntryPoint, "compilation started from composition '{0}'"}, {Message::MessageID::WrongNumberOfCommandArguments, "wrong number of arguments passed to command '{0}'; {2} expected, {1} found"}, {Message::MessageID::WrongTypeOfCommandArgument, "command argument {1} has a wrong type; expecting '{2}' here"}, diff --git a/src/ir2midi/command_insert.cpp b/src/ir2midi/command_insert.cpp index 365aa1c..c77a7c4 100644 --- a/src/ir2midi/command_insert.cpp +++ b/src/ir2midi/command_insert.cpp @@ -39,24 +39,13 @@ public: virtual void Process(const AST::Command& ast) override { ValidateArguments(ast); - GetCompiler()->CompileTrackBlock(boost::get(ast.Arguments[0].Value)); + GetCompiler()->CompileTrackBlock(boost::get(ast.Arguments[0].Value), ast.Location); } void ValidateArguments(const AST::Command& ast) { ValidateArgCount(ast, 1); ValidateArgType(ast, 0, typeid(std::string)); - - auto name = boost::get(ast.Arguments[0].Value); - - if (!GetCompiler()->HasTrackBlock(name)) - { - ThrowMessage( - Message::MessageID::NoSuchCompositionName, - ast.Location, - {name} - ); - } } private: diff --git a/src/ir2midi/ir2midi.cpp b/src/ir2midi/ir2midi.cpp index 11a4802..a31d565 100644 --- a/src/ir2midi/ir2midi.cpp +++ b/src/ir2midi/ir2midi.cpp @@ -6,6 +6,8 @@ #include +#include +#include #include #include #include @@ -87,11 +89,7 @@ bool IR2MIDICompiler::Compile(const std::string& entryPoint) { try { - if (!CompileTrackBlock(entryPoint)) - { - return false; - } - + CompileTrackBlock(entryPoint, {}); Finalize(); return !HasErrors(); } @@ -211,7 +209,7 @@ void IR2MIDICompiler::InitializeCommandProcessors() AddCommandProcessor(CreateVolumeCommandProcessor(this)); } -bool IR2MIDICompiler::CompileTrackBlock(const std::string& trackBlockName) +void IR2MIDICompiler::CompileTrackBlock(const std::string& trackBlockName, const AST::SourceLocation& location) { auto itTrack = m_IR.TrackBlockNameMap.find(trackBlockName); @@ -222,12 +220,17 @@ bool IR2MIDICompiler::CompileTrackBlock(const std::string& trackBlockName) Message::MessageKind::Error, Message::MessageID::NoSuchCompositionName, m_IR.Name, - {0, 0}, + location, {trackBlockName} } ); } + CheckForRecursion(trackBlockName, location); + + m_TrackBlockCompilationStack.push_back(NameAndLocation{trackBlockName, location}); + Common::AutoPop autoPop(m_TrackBlockCompilationStack); + // with bounds checking CheckForUnprocessedAttributes(m_IR.TrackBlocks.at(itTrack->second.ID).Attributes); @@ -235,8 +238,6 @@ bool IR2MIDICompiler::CompileTrackBlock(const std::string& trackBlockName) { i.apply_visitor(*this); } - - return true; } void IR2MIDICompiler::CompileBlock(int trackNumber, IR::BlockReference blockRef) @@ -273,6 +274,61 @@ void IR2MIDICompiler::Finalize() } } +void IR2MIDICompiler::CheckForRecursion(const std::string& trackBlockName, const AST::SourceLocation& location) +{ + auto it = std::find_if( + m_TrackBlockCompilationStack.begin(), + m_TrackBlockCompilationStack.end(), + [&trackBlockName] (auto&& x) + { + return x.Name == trackBlockName; + } + ); + + if (it != m_TrackBlockCompilationStack.end()) + { + AddMessage( + Message::MessageItem{ + Message::MessageKind::Error, + Message::MessageID::TrackBlockCompilationRecursion, + GetSourceName(), + location, + {trackBlockName} + } + ); + + if (m_TrackBlockCompilationStack.size() > 1) + { + std::for_each( + m_TrackBlockCompilationStack.rbegin(), + m_TrackBlockCompilationStack.rend() - 1, + [this] (auto&& x) + { + this->AddMessage( + Message::MessageItem{ + Message::MessageKind::Note, + Message::MessageID::TrackBlockCompilationBackTrace, + this->GetSourceName(), + x.Location, + {x.Name} + } + ); + } + ); + } + + throw Exceptions::MessageException( + Message::MessageItem{ + Message::MessageKind::Note, + Message::MessageID::TrackBlockCompilationBackTraceEntryPoint, + GetSourceName(), + {}, + {m_TrackBlockCompilationStack.at(0).Name} + } + ); + } +} + void IR2MIDICompiler::CheckForUnprocessedAttributes(const std::vector& attributes) { if (!attributes.empty()) diff --git a/src/ir2midi/pch.hpp b/src/ir2midi/pch.hpp index 81af478..a1bdf58 100644 --- a/src/ir2midi/pch.hpp +++ b/src/ir2midi/pch.hpp @@ -2,6 +2,7 @@ #pragma once #include +#include #include #include #include -- 2.11.0