Porytiles
Loading...
Searching...
No Matches
header_define_provider_impl.ipp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <filesystem>
5#include <optional>
6#include <string>
7#include <vector>
8
14
15// The anonymous namespace ensures internal linkage per translation unit
16// This file is intentionally included only in header_define_provider.cpp
17namespace {
18
19using namespace porytiles;
20
32std::string make_source_string(const TextFormatter *format, const std::string &file_path, const DefineStatement &define)
33{
34 return format->format("{}:{}", FormatParam{file_path}, FormatParam{define.position().line});
35}
36
47std::vector<std::string> make_source_details(
48 const TextFormatter *format, const std::vector<std::string> &file_lines, const DefineStatement &define)
49{
50 if (file_lines.empty()) {
51 return {};
52 }
53
54 // Convert 1-indexed line to 0-indexed for FileHighlightPrinter
55 const std::size_t line_index = define.position().line - 1;
56 if (line_index >= file_lines.size()) {
57 return {};
58 }
59
60 const FileHighlightPrinter printer{format};
61 return printer.print(file_lines, std::vector{line_index});
62}
63
74CParserFacade &get_parser_driver(
75 std::optional<CParserFacade> &driver, const std::filesystem::path &header_path, const TextFormatter *format)
76{
77 if (!driver.has_value()) {
78 driver.emplace(header_path, format);
79 }
80 return driver.value();
81}
82
95LayerValue<std::size_t> parse_size_t(
96 const TextFormatter *format,
97 const DefineStatement &define,
98 const std::string &file_path,
99 const std::vector<std::string> &file_lines,
100 const std::string & /*key*/)
101{
102 const auto source = make_source_string(format, file_path, define);
103 const auto details = make_source_details(format, file_lines, define);
104
105 if (!define.has_int_value()) {
106 const auto error = format->format(
107 "'{}' is not an integer value (found {} define)",
108 FormatParam{define.name(), Style::bold},
109 FormatParam{define.is_flag() ? "flag" : "string"});
110 return LayerValue<std::size_t>::invalid(error, source, details);
111 }
112
113 const auto value = define.int_value();
114 if (value < 0) {
115 const auto error =
116 format->format("'{}' has negative value {}", FormatParam{define.name(), Style::bold}, FormatParam{value});
117 return LayerValue<std::size_t>::invalid(error, source, details);
118 }
119
120 return LayerValue<std::size_t>::valid(value, define.name(), source, details);
121}
122
148template <typename T, typename ParseFunc>
149LayerValue<T> search_header_define(
150 std::optional<CParserFacade> &driver,
151 const TextFormatter *format,
152 const std::filesystem::path &header_path,
153 const std::string &define_name,
154 ParseFunc parse_func,
155 const std::string &key,
156 const std::string &provider_name)
157{
158 // Get or create the parser driver
159 auto &parser = get_parser_driver(driver, header_path, format);
160
161 // Search for the define
162 auto result = parser.find_define(define_name);
163
164 if (!result.has_value()) {
165 // Parse error or file not found - check if it's a file-not-found case
166 // File not found should return not_provided, parse errors return invalid
167 if (!std::filesystem::exists(header_path)) {
169 }
170 // Parse error - return invalid with error message
171 const auto base_error_msg = format->format(
172 "failed to parse '{}' from '{}':",
173 FormatParam{define_name, Style::bold},
174 FormatParam{header_path.string(), Style::bold});
175 std::vector<std::string> details_err_msg{};
176 for (const auto &err : result.chain()) {
177 if (const auto &details = err->details(*format); !details.empty()) {
178 details_err_msg.append_range(err->details(*format));
179 details_err_msg.emplace_back();
180 }
181 }
182 return LayerValue<T>::invalid(base_error_msg, header_path.string(), details_err_msg);
183 }
184
185 if (!result.value().has_value()) {
186 // Define not found in file
188 }
189
190 // Parse the value
191 auto layer_result = parse_func(format, result.value().value(), header_path.string(), parser.file_lines(), key);
192 layer_result.source_key = provider_name;
193 return layer_result;
194}
195
196} // namespace
High-level facade for parsing C/C++ source files.
Represents a parsed #define preprocessor statement.
bool is_flag() const
Checks if this define has no value (flag-like).
const std::string & name() const
Returns the macro name.
bool has_int_value() const
Checks if this define has an integer value.
const SourcePosition & position() const
Returns the source position of the #define.
std::int64_t int_value() const
Returns the integer value.
A service for printing file lines with highlighted lines and line numbers.
A text parameter with associated styling for formatted output.
static const Style bold
Bold text formatting.
Abstract base class for applying text styling with context-aware formatting.
virtual std::string format(const std::string &format_str, const std::vector< FormatParam > &params) const
Formats a string with styled parameters using fmtlib syntax.
@ error
Emit a formatted error and fail decompilation.
A small container that holds an optional-wrapped value, validation state, and metadata about the valu...
static LayerValue valid(T val, std::string source_key, std::string source_info)
Creates a LayerValue representing a valid configuration value.
static LayerValue not_provided()
Creates a LayerValue representing that the provider does not supply this configuration.
static LayerValue invalid(std::string error, std::string source_info)
Creates a LayerValue representing an invalid configuration value.
std::size_t line
1-based line number