#pragma clang diagnostic ignored "-Wswitch" #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS #define GEN_ENFORCE_STRING_CODE_TYPES #define GEN_EXPOSE_BACKEND #include "gencpp/gen.cpp" #include "gencpp/gen.builder.cpp" using namespace gen; #ifdef GEN_SYSTEM_WINDOWS #include #endif #pragma region Directories // Program assumes its working directory is the src directory #define path_root "" #define path_codegen path_root "codegen/" #define path_src path_root "src/" #pragma endregion Directories inline CodeBody parse_file( char const* path ) { FileContents content = file_read_contents( GlobalAllocator, true, path ); CodeBody code = parse_global_body( StrC { content.size, (char const*)content.data }); return code; } inline void format_file( char const* path ) { // Need to execute clang format on the generated file to get it to match the original. #define clang_format "clang-format " #define cf_format_inplace "-i " #define cf_style "-style=file:" "./scripts/.clang-format " #define cf_verbose "-verbose " String command = String::make( GlobalAllocator, clang_format ); command.append( cf_format_inplace ); command.append( cf_style ); command.append( cf_verbose ); command.append( path ); log_fmt("\tRunning clang-format on file:\n"); system( command ); log_fmt("\tclang-format finished reformatting.\n"); #undef cf_cmd #undef cf_format_inplace #undef cf_style #undef cf_verbse } struct Odin_AstKind { StringCached desc; Code def; }; Array get_odin_ast_kinds() { local_persist Array kinds = Array::init_reserve(GlobalAllocator, kilobytes(64)); { local_persist s32 done_once = 0; if (done_once) return kinds; ++ done_once; } CodeType t_char_const_ptr = parse_type(code(char const*)); CodeBody ast_kinds_header = parse_file( path_codegen "ast_kinds.hpp" ); for ( Code code = ast_kinds_header.begin(); code != ast_kinds_header.end(); ++ code ) { switch (code->Type) { using namespace ECode; case Comment: case Preprocess_Pragma: // Ignore continue; case Variable: { Odin_AstKind entry { {nullptr}, {} }; CodeVar var = code.cast(); if ( ! var->ValueType.is_equal( t_char_const_ptr ) ) { __debugbreak(); log_failure("Expected all globally defined variables to be char cons* type"); return kinds; } if ( ! var->Value || ! var->Value->Content ) { __debugbreak(); log_failure("Expected all globally defined variable to have a string assigned to it"); return kinds; } // Grab the description entry.desc = var->Value->Content; ++ code; // Grab the definition if ( code->Type != Struct && code->Type != Typedef ) { __debugbreak(); log_failure("Expected a struct or typedef for the entry definition"); return kinds; } entry.def = code; kinds.append(entry); } continue; case Struct: __debugbreak(); log_failure("Expected a description definition as char const* first"); return kinds; break; } } return kinds; } int gen_main() { gen::init(); log_fmt("Generating code for Odin's src\n"); // Remove TOKEN_KINDS usage in tokenizer.cpp if (0) { } // Remove AST_KINDS macro usage in parser.hpp if (1) { CodeBody src_parser_header = parse_file( path_src "parser.hpp" ); CodeBody body = def_body( ECode::Global_Body ); body.append( def_comment(txt("NOTICE(github: Ed94): This is a generated variant of parser.hpp using /codegen/gen_src.cpp"))); body.append(fmt_newline); Array ast_kinds = get_odin_ast_kinds(); for (Code code = src_parser_header.begin(); code != src_parser_header.end(); ++ code) { switch (code->Type) { case ECode::Preprocess_Define: if ( code->Name.starts_with( txt("AST_KINDS"))) { // Skip, we don't want it. continue; } if ( code->Name.starts_with( txt("AST_KIND"))) { // Skip the next 3 definitions ++ code; ++ code; continue; } body.append(code); continue; case ECode::Untyped: if (code->Content.starts_with(txt("AST_KINDS"))) break; case ECode::Enum: { if (code->Name.starts_with( txt("AstKind"))) { // Swap with generated variant CodeBody swap_body = def_body( ECode::Enum_Body ); { swap_body.append( code_str(Ast_Invalid,)); for (Odin_AstKind& kind : ast_kinds) swap_body.append( untyped_str( String::fmt_buf(GlobalAllocator, "Ast_%S,", kind.def->Name ))); swap_body.append( code_str(Ast_COUNT)); } CodeEnum swapped_enum = code.cast().duplicate(); swapped_enum->Body = swap_body; body.append(swapped_enum); } else body.append(code); } continue; case ECode::Variable: { if (code->Name.starts_with(txt("ast_strings"))) { // Swap with generated table String generated_table = String::make_reserve(GlobalAllocator, kilobytes(32)); { for (Odin_AstKind& kind : ast_kinds) generated_table.append(token_fmt("desc", (StrC)kind.desc, stringize( { cast(u8 *) , gb_size_of() -1 }, ))); } CodeVar swapped_table = code.cast().duplicate(); swapped_table->Value = code_fmt( "kinds", (StrC)generated_table, stringize( { {cast(u8 *)"invalid node", gb_size_of("invalid node")},\n })); body.append(swapped_table); body.append(fmt_newline); // Right after is where the struct definitions were defined, we'll insert them here body.append(def_pragma(txt("region AST_KINDS"))); body.append(fmt_newline); for (Odin_AstKind& kind : ast_kinds) { Code def = kind.def.duplicate(); def->Name = get_cached_string( String::fmt_buf(GlobalAllocator, "Ast%S", kind.def->Name)); body.append( def ); body.append(fmt_newline); } body.append(def_pragma(txt("endregion AST_KINDS"))); continue; } if (code->Name.starts_with(txt("ast_variant_sizes"))) { // Swap with generated table String generated_table = String::make_reserve(GlobalAllocator, kilobytes(32)); { for (Odin_AstKind& kind : ast_kinds) generated_table.append(token_fmt( "name", (StrC)kind.def->Name, stringize( gb_size_of(Ast),\n ))); } CodeVar swapped_table = code.cast().duplicate(); swapped_table->Value = code_fmt( "kinds", (StrC)generated_table, stringize( { 0,\n })); body.append(swapped_table); continue; } body.append(code); } continue; case ECode::Struct: { CodeStruct code_struct = code.cast(); if (code->Name.starts_with(txt("Ast"))) for (Code ast_code : code_struct->Body) switch (ast_code->Type) { case ECode::Union: { // Swap out the union's contents with the generated member definitions CodeBody body_swap = def_body(ECode::Union_Body); for (Odin_AstKind kind : ast_kinds) body_swap.append( parse_variable( token_fmt( "name", (StrC)kind.def->Name, stringize( Ast ; )))); ast_code->Body = rcast(AST*, body_swap.ast); } break; default: continue; } body.append(code); } continue; default: body.append(code); continue; } } Builder header = Builder::open( path_src "parser.hpp" ); header.print(body); header.write(); format_file( path_src "parser.hpp" ); } // Remove TYPE_KINDS usage in types.cpp if (0) { } // gen::deinit(); return 0; }