libcruft-util/cpp.hpp

128 lines
4.0 KiB
C++

/*
* 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 <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_CPP_HPP
#define CRUFT_UTIL_CPP_HPP
#include "string.hpp"
#include "view.hpp"
#include <filesystem>
#include <string>
#include <map>
#include <stdexcept>
#include <stack>
namespace cruft::cpp {
///////////////////////////////////////////////////////////////////////////
struct context {
std::stack<std::filesystem::path> source;
std::map<std::string,std::string> 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 cruft::tokeniser<const char*>::iterator
process (std::ostream&,
context&,
cruft::view<cruft::tokeniser<const char*>::iterator> lines) const = 0;
};
///////////////////////////////////////////////////////////////////////////
class processor {
public:
processor ();
void add (std::string token, std::unique_ptr<directive>);
void process (std::ostream&, const std::filesystem::path&) const;
std::filesystem::path
resolve (const std::filesystem::path&) const;
cruft::tokeniser<const char*>::iterator
process (std::ostream&,
context&,
cruft::view<cruft::tokeniser<const char*>::iterator>) const;
private:
std::map<std::string, std::unique_ptr<directive>> 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 {
cruft::tokeniser<const char*>::iterator
process (std::ostream&,
context&,
cruft::view<cruft::tokeniser<const char*>::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 cruft::tokeniser<const char*>::iterator
process (std::ostream&,
context&,
cruft::view<cruft::tokeniser<const char*>::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::filesystem::path&);
virtual cruft::tokeniser<const char*>::iterator
process (std::ostream&,
context&,
cruft::view<cruft::tokeniser<const char*>::iterator>) const override;
private:
processor &m_parent;
std::vector<std::filesystem::path> m_paths;
};
};
#endif