Patrick Kelley 8fd444092b initial
2025-05-07 15:35:15 -04:00

69 lines
2.0 KiB
C++

// Copyright (c) 2020-now by the Zeek Project. See LICENSE for details.
#pragma once
#include <map>
#include <string>
#include <utility>
#include <vector>
#include <hilti/base/result.h>
namespace hilti::util {
/**
* Helper to preprocess @if/@else/@endif directives in lines of input.
*
* This currently supports the following set of directives:
*
* - `@if [!] <id> ==|!=|<|<=|>|>= <integer>
* - `@if [!] <id>
* - `@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<ID, Value> constants) : _constants(std::move(std::move(constants))) {}
/**
* Process one preprocessor directive of the form `@<id> [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<State> 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<bool> _parseIf(const std::string_view& expression);
std::map<ID, Value> _constants;
std::vector<int> _stack = {1};
};
} // namespace hilti::util