/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * 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