// Copyright (c) 2020-now by the Zeek Project. See LICENSE for details. #pragma once #include #include #include #include #include namespace hilti::util { /** * Helper to preprocess @if/@else/@endif directives in lines of input. * * This currently supports the following set of directives: * * - `@if [!] ==|!=|<|<=|>|>= * - `@if [!] * - `@else` * - `@endif` **/ class SourceCodePreprocessor { public: using ID = std::string; //< type for identifiers using Value = int; //< type associated with integers (may expand this to a variant in the future) /** Current inclusion state while processing input. */ enum class State { Include, //< include line Skip //< skip line }; /** * Constructor. * * @param constants map of constants that preprocessor directives can work on */ SourceCodePreprocessor(std::map constants) : _constants(std::move(std::move(constants))) {} /** * Process one preprocessor directive of the form `@ [expression]`. * * This evaluates the directive and updates internal state accordingly. * * @param directive a supported directive ID, which must start with `@`. * @param expression string with expression that the directive is taking * @result the new inclusion state for subsequent input, or an error if the directive could not be processed */ Result processLine(std::string_view directive, std::string_view expression = ""); /** Returns the current inclusion state. */ State state() const { return _stack.back() == 1 ? State::Include : State::Skip; } /** * Returns true if the proprocessor expects further directives that closed * previously opened blocks */ bool expectingDirective() { return _stack.size() > 1; } private: Result _parseIf(const std::string_view& expression); std::map _constants; std::vector _stack = {1}; }; } // namespace hilti::util