25const std::filesystem::path headers_rel_path = std::filesystem::path{
"src"} /
"data" /
"tilesets" /
"headers.h";
28const std::filesystem::path graphics_rel_path = std::filesystem::path{
"src"} /
"data" /
"tilesets" /
"graphics.h";
29const std::filesystem::path metatiles_rel_path = std::filesystem::path{
"src"} /
"data" /
"tilesets" /
"metatiles.h";
30const std::filesystem::path src_graphics_rel_path = std::filesystem::path{
"src"} /
"graphics.c";
33[[nodiscard]] std::optional<IncbinResolutionFailure>
34classify_incbin_lookup(
const std::map<std::string, IncbinDeclaration> &incbin_vars,
const std::string &variable_name)
36 if (!incbin_vars.contains(variable_name)) {
37 return IncbinResolutionFailure::not_found;
39 if (incbin_vars.at(variable_name).paths().empty()) {
40 return IncbinResolutionFailure::empty_paths;
51 const std::string &tileset_name,
const std::vector<UnresolvedIncbinVar> &unresolved,
const TextFormatter *format)
53 std::vector<std::string> lines;
56 format->
format(
"Could not resolve artifact paths for tileset '{}'.",
FormatParam{tileset_name, Style::bold}));
57 lines.emplace_back(
"");
58 lines.emplace_back(
"The following INCBIN variable(s) could not be resolved:");
60 for (
const auto &var : unresolved) {
61 if (var.reason == IncbinResolutionFailure::not_found) {
62 lines.push_back(format->
format(
63 " '{}' (field '{}') was not found in any scanned file.",
68 lines.push_back(format->
format(
69 " '{}' (field '{}') was found but declared no INCBIN path.",
75 lines.emplace_back(
"");
76 lines.push_back(format->
format(
77 "Scanned files: '{}', '{}', '{}'.",
78 FormatParam{graphics_rel_path.string(), Style::bold},
79 FormatParam{metatiles_rel_path.string(), Style::bold},
80 FormatParam{src_graphics_rel_path.string(), Style::bold}));
98 const std::filesystem::path &project_root,
99 bool &metadata_parsed,
100 std::map<std::string, ProjectTilesetMetadata> &tileset_metadata,
103 if (metadata_parsed) {
107 const auto headers_path = project_root / headers_rel_path;
112 parser.parse_struct_initializers(
"gTileset_"),
114 format->
format(
"Failed to parse tileset headers from '{}'.",
FormatParam{headers_path.string(), Style::bold}));
116 for (
auto &struct_decl : struct_decls) {
117 const auto &tileset_name = struct_decl.variable_name();
119 auto is_secondary_opt = struct_decl.field_value(
"isSecondary");
120 bool is_secondary = is_secondary_opt.has_value() && is_secondary_opt.value() ==
"TRUE";
122 auto tiles_var = struct_decl.field_value(
"tiles");
123 auto palettes_var = struct_decl.field_value(
"palettes");
124 auto metatiles_var = struct_decl.field_value(
"metatiles");
125 auto metatile_attributes_var = struct_decl.field_value(
"metatileAttributes");
126 auto callback_var = struct_decl.field_value(
"callback");
128 if (!tiles_var.has_value() || !palettes_var.has_value() || !metatiles_var.has_value() ||
129 !metatile_attributes_var.has_value()) {
133 std::optional<std::string> callback_func = std::nullopt;
134 if (callback_var.has_value() && callback_var.value() !=
"NULL") {
135 callback_func = callback_var.value();
138 tileset_metadata.emplace(
144 palettes_var.value(),
145 metatiles_var.value(),
146 metatile_attributes_var.value(),
150 metadata_parsed =
true;
170 const std::filesystem::path &project_root,
171 bool &metadata_parsed,
172 std::map<std::string, ProjectTilesetMetadata> &tileset_metadata,
173 bool &artifact_paths_parsed,
174 std::map<std::string, ProjectTilesetArtifactPaths> &tileset_artifact_paths,
175 std::map<std::string, std::vector<UnresolvedIncbinVar>> &tileset_unresolved_vars,
178 if (artifact_paths_parsed) {
183 ensure_metadata_parsed(project_root, metadata_parsed, tileset_metadata, format),
185 "Failed to resolve artifact paths.");
188 std::map<std::string, IncbinDeclaration> incbin_vars;
190 const auto graphics_path = project_root / graphics_rel_path;
194 graphics_parser.parse_incbin_arrays(),
197 "Failed to parse graphics INCBINs from '{}'.",
FormatParam{graphics_path.string(), Style::bold}));
198 for (
auto &incbin : graphics_incbins) {
199 incbin_vars.emplace(incbin.variable_name(), std::move(incbin));
202 const auto metatiles_path = project_root / metatiles_rel_path;
206 metatiles_parser.parse_incbin_arrays(),
209 "Failed to parse metatiles INCBINs from '{}'.",
FormatParam{metatiles_path.string(), Style::bold}));
210 for (
auto &incbin : metatiles_incbins) {
211 incbin_vars.emplace(incbin.variable_name(), std::move(incbin));
214 const auto src_graphics_path = project_root / src_graphics_rel_path;
215 CParserFacade src_graphics_parser{src_graphics_path, format};
217 src_graphics_incbins,
218 src_graphics_parser.parse_incbin_arrays(),
221 "Failed to parse graphics INCBINs from '{}'.",
FormatParam{src_graphics_path.string(), Style::bold}));
222 for (
auto &incbin : src_graphics_incbins) {
223 incbin_vars.emplace(incbin.variable_name(), std::move(incbin));
228 for (
const auto &[tileset_name, metadata] : tileset_metadata) {
229 const std::array<std::pair<std::string, std::string>, 4> fields{{
230 {
"tiles", metadata.tiles_var()},
231 {
"palettes", metadata.palettes_var()},
232 {
"metatiles", metadata.metatiles_var()},
233 {
"metatileAttributes", metadata.metatile_attributes_var()},
236 std::vector<UnresolvedIncbinVar> unresolved;
237 for (
const auto &[field_label, variable_name] : fields) {
238 auto failure = classify_incbin_lookup(incbin_vars, variable_name);
239 if (failure.has_value()) {
244 if (!unresolved.empty()) {
245 tileset_unresolved_vars.emplace(tileset_name, std::move(unresolved));
249 const auto &tiles_incbin = incbin_vars.at(metadata.tiles_var());
250 const auto &palettes_incbin = incbin_vars.at(metadata.palettes_var());
251 const auto &metatiles_incbin = incbin_vars.at(metadata.metatiles_var());
252 const auto &attributes_incbin = incbin_vars.at(metadata.metatile_attributes_var());
254 std::vector<std::filesystem::path> palette_paths;
255 palette_paths.reserve(palettes_incbin.paths().size());
256 for (
const auto &path_str : palettes_incbin.paths()) {
257 palette_paths.emplace_back(path_str);
260 tileset_artifact_paths.emplace(
263 std::filesystem::path{tiles_incbin.paths().front()},
264 std::move(palette_paths),
265 std::filesystem::path{metatiles_incbin.paths().front()},
266 std::filesystem::path{attributes_incbin.paths().front()}});
269 artifact_paths_parsed =
true;
279 const auto metadata_result =
metadata_for(tileset_name);
280 return metadata_result.has_value();
286 return metadata.is_secondary();
292 return metadata.has_animations();
298 ensure_metadata_parsed(project_root_, metadata_parsed_, tileset_metadata_, format_),
299 std::set<std::string>,
300 "Failed to enumerate tilesets.");
302 std::set<std::string> names;
303 for (
const auto &[tileset_name, metadata] : tileset_metadata_) {
304 names.insert(tileset_name);
313 ensure_metadata_parsed(project_root_, metadata_parsed_, tileset_metadata_, format_),
315 format_->
format(
"Failed to get metadata for tileset '{}'.",
FormatParam{tileset_name, Style::bold}));
317 if (!tileset_metadata_.contains(tileset_name)) {
322 return tileset_metadata_.at(tileset_name);
329 ensure_artifact_paths_parsed(
333 artifact_paths_parsed_,
334 tileset_artifact_paths_,
335 tileset_unresolved_vars_,
338 format_->
format(
"Failed to get artifact paths for tileset '{}'.",
FormatParam{tileset_name, Style::bold}));
340 if (!tileset_artifact_paths_.contains(tileset_name)) {
341 if (tileset_unresolved_vars_.contains(tileset_name)) {
342 return build_unresolved_artifact_paths_error(
343 tileset_name, tileset_unresolved_vars_.at(tileset_name), format_);
349 return tileset_artifact_paths_.at(tileset_name);
354 metadata_parsed_ =
false;
355 tileset_metadata_.clear();
356 artifact_paths_parsed_ =
false;
357 tileset_artifact_paths_.clear();
358 tileset_unresolved_vars_.clear();
#define PT_TRY_ASSIGN_CHAIN_ERR(var, expr, return_type,...)
Unwraps a ChainableResult, chaining a new error message on failure.
#define PT_TRY_ASSIGN_PASS_ERR(var, expr, return_type)
Unwraps a ChainableResult, passing through the error chain with an empty FormattableError when types ...
#define PT_TRY_CALL_CHAIN_ERR(expr, return_type,...)
Unwraps a void ChainableResult, chaining a new error message on failure.
High-level facade for parsing C/C++ source files.
A result type that maintains a chainable sequence of errors for debugging and error reporting.
Represents resolved filesystem paths for tileset artifacts from INCBIN declarations.
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 > ¶ms) const
Formats a string with styled parameters using fmtlib syntax.