/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2018 Danny Robson */ #ifndef CRUFT_UTIL_CPP_HPP #define CRUFT_UTIL_CPP_HPP #include "string.hpp" #include "view.hpp" #include #include #include #include #include namespace util::cpp { /////////////////////////////////////////////////////////////////////////// struct context { std::stack source; std::map defines; }; /////////////////////////////////////////////////////////////////////////// /// an abstract base that performs processing for a directive class directive { public: virtual ~directive () = default; /// handles a preprocessor directive by: /// * perform some processing on any number of input lines, /// * optionally writes to the supplied stream, /// * and returns the line that should be consumed next /// /// \param lines is a tokenised view over all the lines of the input /// \return the next line that processing should continue from virtual util::tokeniser::iterator process (std::ostream&, context&, util::view::iterator> lines) const = 0; }; /////////////////////////////////////////////////////////////////////////// class processor { public: processor (); void add (std::string token, std::unique_ptr); void process (std::ostream&, const std::experimental::filesystem::path&) const; std::experimental::filesystem::path resolve (const std::experimental::filesystem::path&) const; util::tokeniser::iterator process (std::ostream&, context&, util::view::iterator>) const; private: std::map> m_directives; }; /////////////////////////////////////////////////////////////////////////// /// thrown when a processor encounters a directive it has not been /// configured to handle class unknown_directive : public std::runtime_error { using runtime_error::runtime_error; }; /////////////////////////////////////////////////////////////////////////// /// silently ignores configured directive by advancing the input cursor /// past the provided line without writing to the output stream. class ignore : public directive { util::tokeniser::iterator process (std::ostream&, context&, util::view::iterator> lines) const override { return lines.begin ()++; } }; ///------------------------------------------------------------------------ /// copies the supplied directive to the output stream without any /// modification class passthrough : public directive { public: passthrough (const std::string &name); virtual util::tokeniser::iterator process (std::ostream&, context&, util::view::iterator>) const override; private: const std::string m_name; }; ///------------------------------------------------------------------------ /// handles include directives by copying the contents of the referenced /// path into the input stream class include : public directive { public: include (processor &_parent); void add (const std::experimental::filesystem::path&); virtual util::tokeniser::iterator process (std::ostream&, context&, util::view::iterator>) const override; private: processor &m_parent; std::vector m_paths; }; }; #endif