16[[nodiscard]] FormattableError make_duplicate_error(
17 const std::string &header_message,
18 SourcePosition duplicate_pos,
19 const std::string ¬e_message,
20 SourcePosition original_pos,
21 const std::vector<std::string> &file_lines,
22 const TextFormatter *format)
24 std::vector<std::string> lines;
25 FileHighlightPrinter printer{format};
28 lines.push_back(header_message);
31 assert_or_panic(duplicate_pos.line > 0,
"duplicate_pos.line must be positive (1-based)");
32 assert_or_panic(duplicate_pos.line <= file_lines.size(),
"duplicate_pos.line exceeds file bounds");
33 assert_or_panic(duplicate_pos.column > 0,
"duplicate_pos.column must be positive (1-based)");
34 auto dup_context = printer.print(file_lines, duplicate_pos.line - 1, duplicate_pos.column - 1);
35 for (
auto &line : dup_context) {
36 lines.push_back(std::move(line));
40 lines.emplace_back(
"");
43 lines.push_back(note_message);
46 assert_or_panic(original_pos.line > 0,
"original_pos.line must be positive (1-based)");
47 assert_or_panic(original_pos.line <= file_lines.size(),
"original_pos.line exceeds file bounds");
48 assert_or_panic(original_pos.column > 0,
"original_pos.column must be positive (1-based)");
49 auto orig_context = printer.print(file_lines, original_pos.line - 1, original_pos.column - 1);
50 for (
auto &line : orig_context) {
51 lines.push_back(std::move(line));
54 return FormattableError{std::move(lines)};
59template <
typename Entry>
60ChainableResult<void> HeaderBehaviorMapProvider::try_add_behavior_entry(
const Entry &entry)
const
62 const auto &name = entry.name();
65 if (!name.starts_with(
"MB_")) {
69 auto raw_value = entry.int_value();
72 if (raw_value < 0 || raw_value > std::numeric_limits<std::uint16_t>::max()) {
76 auto value =
static_cast<std::uint16_t
>(raw_value);
77 const auto &new_pos = entry.position();
80 if (name_to_value_.contains(name)) {
82 const auto &orig_pos = name_to_position_.at(name);
83 return make_duplicate_error(
85 "{}:{}:{}: duplicate behavior name '{}'.",
86 FormatParam{header_path_, Style::bold},
89 FormatParam{name, Style::bold}),
92 "{} originally defined at line {}:", FormatParam{
"note:", Style::cyan | Style::bold}, orig_pos.line),
94 driver_->file_lines(),
99 if (value_to_name_.contains(value)) {
101 const auto &orig_name = value_to_name_.at(value);
102 const auto &orig_pos = value_to_position_.at(value);
103 return make_duplicate_error(
105 "{}:{}:{}: duplicate behavior value '{}': both '{}' and '{}' have this value.",
106 FormatParam{header_path_, Style::bold},
109 FormatParam{value, Style::bold},
110 FormatParam{orig_name, Style::bold},
111 FormatParam{name, Style::bold}),
114 "{} '{}' originally defined at line {}:",
115 FormatParam{
"note:", Style::cyan | Style::bold},
116 FormatParam{orig_name, Style::bold},
119 driver_->file_lines(),
124 name_to_value_[name] = value;
125 value_to_name_[value] = name;
126 name_to_position_[name] = new_pos;
127 value_to_position_[value] = new_pos;
134 if (!behavior_name.starts_with(
"MB_")) {
136 "Invalid behavior name '{}': expected prefix '{}'.",
141 auto load_result = ensure_loaded();
142 if (!load_result.has_value()) {
144 FormattableError{
"Metatile behavior provider lookup failed."}, load_result};
147 const auto it = name_to_value_.find(behavior_name);
148 if (it == name_to_value_.end()) {
150 "Behavior '{}' not found in '{}'.",
159 auto load_result = ensure_loaded();
160 if (!load_result.has_value()) {
164 const auto it = value_to_name_.find(behavior_value);
165 if (it == value_to_name_.end()) {
167 "Unknown behavior value '{}' not found in '{}'.",
186 driver_ = std::make_unique<CParserFacade>(header_path_, format_);
189 auto defines_result = driver_->parse_defines();
190 if (!defines_result.has_value()) {
192 return ChainableResult<void>{defines_result};
194 for (
const auto &def : defines_result.value()) {
195 if (!def.has_int_value()) {
198 auto insert_result = try_add_behavior_entry(def);
199 if (!insert_result.has_value()) {
200 return insert_result;
205 auto enums_result = driver_->parse_enums();
206 if (!enums_result.has_value()) {
208 return ChainableResult<void>{enums_result};
210 for (
const auto &enum_decl : enums_result.value()) {
211 for (
const auto &member : enum_decl.members()) {
212 auto insert_result = try_add_behavior_entry(member);
213 if (!insert_result.has_value()) {
214 return insert_result;
219 if (name_to_value_.empty()) {
221 return FormattableError{
222 "{}: no behavior definitions exist in file.", FormatParam{header_path_.string(),
Style::bold}};
A result type that maintains a chainable sequence of errors for debugging and error reporting.
static const Style bold
Bold text 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.
void assert_or_panic(bool condition, const StringViewSourceLoc &s)
Conditionally panics if the given condition is false.