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
34std::string make_source_string(const TextFormatter *format, const std::string &file_path, const DefineStatement &define)
35{
36 return format->format("{}:{}", FormatParam{file_path}, FormatParam{define.position().line});
37}
38
51std::vector<std::string> make_source_details(
52 const TextFormatter *format, const std::vector<std::string> &file_lines, const DefineStatement &define)
53{
54 if (file_lines.empty()) {
55 return {};
56 }
57
58 // Convert 1-indexed line to 0-indexed for FileHighlightPrinter
59 const std::size_t line_index = define.position().line - 1;
60 if (line_index >= file_lines.size()) {
61 return {};
62 }
63
64 const FileHighlightPrinter printer{format};
65 return printer.print(file_lines, std::vector{line_index});
66}
67
80CParserFacade &get_parser_driver(
81 std::optional<CParserFacade> &driver, const std::filesystem::path &header_path, const TextFormatter *format)
82{
83 if (!driver.has_value()) {
84 driver.emplace(header_path, format);
85 }
86 return driver.value();
87}
88
103LayerValue<std::size_t> parse_size_t(
104 const TextFormatter *format,
105 const DefineStatement &define,
106 const std::string &file_path,
107 const std::vector<std::string> &file_lines,
108 const std::string & /*key*/)
109{
110 const auto source = make_source_string(format, file_path, define);
111 const auto details = make_source_details(format, file_lines, define);
112
113 if (!define.has_int_value()) {
114 const auto error = format->format(
115 "'{}' is not an integer value (found {} define)",
116 FormatParam{define.name(), Style::bold},
117 FormatParam{define.is_flag() ? "flag" : "string"});
118 return LayerValue<std::size_t>::invalid(error, source, details);
119 }
120
121 const auto value = define.int_value();
122 if (value < 0) {
123 const auto error =
124 format->format("'{}' has negative value {}", FormatParam{define.name(), Style::bold}, FormatParam{value});
125 return LayerValue<std::size_t>::invalid(error, source, details);
126 }
127
128 return LayerValue<std::size_t>::valid(value, define.name(), source, details);
129}
130
158template <typename T, typename ParseFunc>
159LayerValue<T> search_header_define(
160 std::optional<CParserFacade> &driver,
161 const TextFormatter *format,
162 const std::filesystem::path &header_path,
163 const std::string &define_name,
164 ParseFunc parse_func,
165 const std::string &key,
166 const std::string &provider_name)
167{
168 // Get or create the parser driver
169 auto &parser = get_parser_driver(driver, header_path, format);
170
171 // Search for the define
172 auto result = parser.find_define(define_name);
173
174 if (!result.has_value()) {
175 // Parse error or file not found - check if it's a file-not-found case
176 // File not found should return not_provided, parse errors return invalid
177 if (!std::filesystem::exists(header_path)) {
179 }
180 // Parse error - return invalid with error message
181 const auto base_error_msg = format->format(
182 "failed to parse '{}' from '{}':",
183 FormatParam{define_name, Style::bold},
184 FormatParam{header_path.string(), Style::bold});
185 std::vector<std::string> details_err_msg{};
186 for (const auto &err : result.chain()) {
187 if (const auto &details = err->details(*format); !details.empty()) {
188 details_err_msg.append_range(err->details(*format));
189 details_err_msg.emplace_back();
190 }
191 }
192 return LayerValue<T>::invalid(base_error_msg, header_path.string(), details_err_msg);
193 }
194
195 if (!result.value().has_value()) {
196 // Define not found in file
198 }
199
200 // Parse the value
201 auto layer_result = parse_func(format, result.value().value(), header_path.string(), parser.file_lines(), key);
202 layer_result.source_key = provider_name;
203 return layer_result;
204}
205
206} // 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