16[[nodiscard]] std::unordered_map<std::string, std::int64_t> resolved_define_values(
const TolerantDefineScan &scan)
18 std::unordered_map<std::string, std::int64_t> values;
19 for (
const DefineStatement &define : scan.defines) {
20 if (define.has_int_value()) {
21 values.insert_or_assign(define.name(), define.int_value());
27[[nodiscard]] ChainableResult<TolerantDefineScan> scan_define_values_for_enums(
28 gsl::not_null<const TextFormatter *> format,
29 const std::string &content,
30 const CParserContext *context,
31 const std::unordered_map<std::string, std::int64_t> &seed_symbols)
33 Lexer lexer{format, content, context};
34 auto lex_result = lexer.lex();
35 if (!lex_result.has_value()) {
36 return ChainableResult<TolerantDefineScan>{lex_result};
39 Parser parser{format, std::move(lex_result).value(), context};
40 parser.seed_symbols(seed_symbols);
41 TolerantDefineScan scan = parser.parse_defines_tolerant();
42 scan.ambiguous_values = parser.ambiguous_defines();
49 : file_path_{std::move(file_path)}, format_{format}
54 std::filesystem::path file_path,
55 gsl::not_null<const TextFormatter *> format,
56 std::unordered_map<std::string, std::int64_t> seed_symbols)
57 : file_path_{std::move(file_path)}, format_{format}, seed_symbols_{std::move(seed_symbols)}
61Parser CParserFacade::make_seeded_parser(std::vector<Token> tokens)
63 Parser parser{format_, std::move(tokens), context_.get()};
64 if (!seed_symbols_.empty()) {
65 parser.seed_symbols(seed_symbols_);
70ChainableResult<void> CParserFacade::ensure_loaded()
81 if (!std::filesystem::exists(file_path_)) {
84 FormattableError{format_->
format(
"{}: file not found", FormatParam{file_path_.string(),
Style::bold})};
88 std::ifstream file{file_path_};
89 if (!file.is_open()) {
92 FormattableError{format_->
format(
"{}: failed to open file", FormatParam{file_path_.string(),
Style::bold})};
97 std::ostringstream buffer;
98 buffer << file.rdbuf();
99 content_ = buffer.str();
103 std::istringstream line_stream{content_};
105 while (std::getline(line_stream, line)) {
107 file_lines_.push_back(line);
111 context_ = std::make_unique<CParserContext>(&file_lines_, format_, file_path_.string());
119 auto load_result = ensure_loaded();
120 if (!load_result.has_value()) {
128 Lexer lexer{format_, content_, context_.get()};
129 auto lex_result = lexer.lex();
130 if (!lex_result.has_value()) {
138 auto parser = make_seeded_parser(std::move(lex_result).value());
139 auto parse_result = parser.parse_defines();
140 if (!parse_result.has_value()) {
147 return std::move(parse_result).value();
152 auto load_result = ensure_loaded();
153 if (!load_result.has_value()) {
162 auto defines_result = scan_define_values_for_enums(format_, content_, context_.get(), seed_symbols_);
163 if (!defines_result.has_value()) {
171 Lexer lexer{format_, content_, context_.get()};
172 auto lex_result = lexer.lex();
173 if (!lex_result.has_value()) {
181 auto parser = make_seeded_parser(std::move(lex_result).value());
182 parser.seed_values(resolved_define_values(defines_result.value()));
183 auto parse_result = parser.parse_enums();
184 if (!parse_result.has_value()) {
191 return std::move(parse_result).value();
196 auto load_result = ensure_loaded();
197 if (!load_result.has_value()) {
204 Lexer lexer{format_, content_, context_.get()};
205 auto lex_result = lexer.lex();
206 if (!lex_result.has_value()) {
213 auto parser = make_seeded_parser(std::move(lex_result).value());
216 scan_warnings_.insert(scan_warnings_.end(), parser.scan_warnings().begin(), parser.scan_warnings().end());
222 auto load_result = ensure_loaded();
223 if (!load_result.has_value()) {
230 auto defines_result = scan_define_values_for_enums(format_, content_, context_.get(), seed_symbols_);
231 if (!defines_result.has_value()) {
238 Lexer lexer{format_, content_, context_.get()};
239 auto lex_result = lexer.lex();
240 if (!lex_result.has_value()) {
247 auto parser = make_seeded_parser(std::move(lex_result).value());
248 parser.seed_values(resolved_define_values(defines_result.value()));
250 scan_warnings_.insert(scan_warnings_.end(), parser.scan_warnings().begin(), parser.scan_warnings().end());
257 auto load_result = ensure_loaded();
258 if (!load_result.has_value()) {
266 Lexer lexer{format_, content_, context_.get()};
267 auto lex_result = lexer.lex();
268 if (!lex_result.has_value()) {
276 auto parser = make_seeded_parser(std::move(lex_result).value());
277 auto parse_result = parser.parse_pointer_arrays();
278 if (!parse_result.has_value()) {
286 auto arrays = std::move(parse_result).value();
287 if (name_prefix.has_value()) {
289 arrays, [&](
const ArrayDeclaration &arr) {
return !arr.
name().starts_with(name_prefix.value()); });
298 auto load_result = ensure_loaded();
299 if (!load_result.has_value()) {
307 Lexer lexer{format_, content_, context_.get()};
308 auto lex_result = lexer.lex();
309 if (!lex_result.has_value()) {
317 auto parser = make_seeded_parser(std::move(lex_result).value());
318 auto parse_result = parser.parse_functions();
319 if (!parse_result.has_value()) {
327 auto functions = std::move(parse_result).value();
328 if (name_prefix.has_value()) {
330 functions, [&](
const FunctionDefinition &func) {
return !func.
name().starts_with(name_prefix.value()); });
339 auto load_result = ensure_loaded();
340 if (!load_result.has_value()) {
348 Lexer lexer{format_, content_, context_.get()};
349 auto lex_result = lexer.lex();
350 if (!lex_result.has_value()) {
358 auto parser = make_seeded_parser(std::move(lex_result).value());
359 auto parse_result = parser.parse_struct_variables();
360 if (!parse_result.has_value()) {
368 auto structs = std::move(parse_result).value();
369 if (name_prefix.has_value()) {
381 auto load_result = ensure_loaded();
382 if (!load_result.has_value()) {
390 Lexer lexer{format_, content_, context_.get()};
391 auto lex_result = lexer.lex();
392 if (!lex_result.has_value()) {
400 auto parser = make_seeded_parser(std::move(lex_result).value());
401 auto parse_result = parser.parse_struct_initializers();
402 if (!parse_result.has_value()) {
410 auto structs = std::move(parse_result).value();
411 if (name_prefix.has_value()) {
423 auto load_result = ensure_loaded();
424 if (!load_result.has_value()) {
432 Lexer lexer{format_, content_, context_.get()};
433 auto lex_result = lexer.lex();
434 if (!lex_result.has_value()) {
442 auto parser = make_seeded_parser(std::move(lex_result).value());
443 auto parse_result = parser.parse_struct_definitions();
444 if (!parse_result.has_value()) {
452 auto definitions = std::move(parse_result).value();
453 if (name_filter.has_value()) {
454 std::erase_if(definitions, [&](
const StructDefinition &def) {
return def.
name != name_filter.value(); });
463 auto load_result = ensure_loaded();
464 if (!load_result.has_value()) {
472 Lexer lexer{format_, content_, context_.get()};
473 auto lex_result = lexer.lex();
474 if (!lex_result.has_value()) {
482 auto parser = make_seeded_parser(std::move(lex_result).value());
483 auto parse_result = parser.parse_incbin_arrays();
484 if (!parse_result.has_value()) {
492 auto incbins = std::move(parse_result).value();
493 if (name_prefix.has_value()) {
495 return !inc.
variable_name().starts_with(name_prefix.value());
505 auto load_result = ensure_loaded();
506 if (!load_result.has_value()) {
513 Lexer lexer{format_, content_, context_.get()};
514 auto lex_result = lexer.lex();
515 if (!lex_result.has_value()) {
522 auto parser = make_seeded_parser(std::move(lex_result).value());
523 auto parse_result = parser.parse_indexed_arrays();
524 if (!parse_result.has_value()) {
532 auto arrays = std::move(parse_result).value();
533 if (name_prefix.has_value()) {
544 if (!cached_defines_.has_value()) {
546 if (!result.has_value()) {
549 "{}: failed to find #define '{}'",
554 cached_defines_ = std::move(result.value());
558 for (
const auto &define : cached_defines_.value()) {
559 if (define.name() == define_name) {
560 return std::optional{define};
565 return std::optional<DefineStatement>{std::nullopt};
Represents a parsed C pointer array declaration.
const std::string & name() const
Returns the array variable name.
const std::vector< std::string > & file_lines() const
Returns the cached file lines.
ChainableResult< std::vector< IncbinDeclaration > > parse_incbin_arrays(const std::optional< std::string > &name_prefix=std::nullopt)
Parses INCBIN array declarations from the file.
ChainableResult< std::vector< EnumDeclaration > > parse_enums()
Parses all enum declarations from the file.
ChainableResult< std::vector< StructVariableDeclaration > > parse_struct_variables(const std::optional< std::string > &name_prefix=std::nullopt)
Parses struct variable declarations from the file.
ChainableResult< std::vector< DefineStatement > > parse_defines()
Parses all #define statements from the file.
ChainableResult< std::optional< DefineStatement > > find_define(const std::string &define_name)
Finds a specific #define statement by name.
CParserFacade(std::filesystem::path file_path, gsl::not_null< const TextFormatter * > format)
Constructs a facade for parsing the specified file.
ChainableResult< std::vector< StructDefinition > > parse_struct_definitions(const std::optional< std::string > &name_filter=std::nullopt)
Parses struct type definitions from the file.
ChainableResult< TolerantDefineScan > parse_defines_tolerant()
Parses all #define statements, tolerating individual evaluation failures.
ChainableResult< std::vector< FunctionDefinition > > parse_functions(const std::optional< std::string > &name_prefix=std::nullopt)
Parses function definitions from the file.
ChainableResult< std::vector< IndexedArrayDeclaration > > parse_indexed_arrays(const std::optional< std::string > &name_prefix=std::nullopt)
Parses designated (indexed) array declarations from the file.
ChainableResult< std::vector< StructInitializerDeclaration > > parse_struct_initializers(const std::optional< std::string > &name_prefix=std::nullopt)
Parses struct variable declarations with their designated initializer fields.
ChainableResult< std::vector< ArrayDeclaration > > parse_pointer_arrays(const std::optional< std::string > &name_prefix=std::nullopt)
Parses all pointer array declarations from the file.
ChainableResult< TolerantEnumScan > parse_enums_tolerant()
Parses all enum declarations, tolerating individual member evaluation failures.
A result type that maintains a chainable sequence of errors for debugging and error reporting.
Represents a parsed C function definition.
const std::string & name() const
Returns the function name.
Represents a parsed INCBIN array declaration from C source code.
const std::string & variable_name() const
Returns the variable name.
Lexical analyzer for C/C++ source code.
Parser for C preprocessor constructs.
Represents a parsed C struct variable declaration with its initializer fields.
const std::string & variable_name() const
Returns the variable name.
Represents a parsed C struct variable declaration.
const std::string & variable_name() const
Returns the variable name.
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.
std::string & trim_line_ending(std::string &line)
Removes line ending characters from a string in-place.
Utility functions for string manipulation and formatting.
A parsed C array declaration that uses designated initializers.
A parsed C struct type definition.
The result of a tolerant #define scan.
std::unordered_set< std::string > ambiguous_values
The result of a tolerant enum scan.