Serenity Operating System
at master 179 lines 7.9 kB view raw
1/* 2 * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org> 4 * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org> 5 * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org> 6 * 7 * SPDX-License-Identifier: BSD-2-Clause 8 */ 9 10#include "Namespaces.h" 11#include <AK/Debug.h> 12#include <AK/LexicalPath.h> 13#include <LibCore/ArgsParser.h> 14#include <LibCore/File.h> 15#include <LibIDL/IDLParser.h> 16#include <LibIDL/Types.h> 17 18extern Vector<StringView> s_header_search_paths; 19 20namespace IDL { 21void generate_constructor_header(IDL::Interface const&, StringBuilder&); 22void generate_constructor_implementation(IDL::Interface const&, StringBuilder&); 23void generate_prototype_header(IDL::Interface const&, StringBuilder&); 24void generate_prototype_implementation(IDL::Interface const&, StringBuilder&); 25void generate_iterator_prototype_header(IDL::Interface const&, StringBuilder&); 26void generate_iterator_prototype_implementation(IDL::Interface const&, StringBuilder&); 27void generate_global_mixin_header(IDL::Interface const&, StringBuilder&); 28void generate_global_mixin_implementation(IDL::Interface const&, StringBuilder&); 29} 30 31ErrorOr<int> serenity_main(Main::Arguments arguments) 32{ 33 Core::ArgsParser args_parser; 34 StringView path; 35 StringView import_base_path; 36 StringView output_path = "-"sv; 37 StringView depfile_path; 38 StringView depfile_target; 39 bool constructor_header_mode = false; 40 bool constructor_implementation_mode = false; 41 bool prototype_header_mode = false; 42 bool prototype_implementation_mode = false; 43 bool iterator_prototype_header_mode = false; 44 bool iterator_prototype_implementation_mode = false; 45 bool global_mixin_header_mode = false; 46 bool global_mixin_implementation_mode = false; 47 args_parser.add_option(constructor_header_mode, "Generate the constructor .h file", "constructor-header", 'C'); 48 args_parser.add_option(constructor_implementation_mode, "Generate the constructor .cpp file", "constructor-implementation", 'O'); 49 args_parser.add_option(prototype_header_mode, "Generate the prototype .h file", "prototype-header", 'P'); 50 args_parser.add_option(prototype_implementation_mode, "Generate the prototype .cpp file", "prototype-implementation", 'R'); 51 args_parser.add_option(iterator_prototype_header_mode, "Generate the iterator prototype .h file", "iterator-prototype-header", 0); 52 args_parser.add_option(iterator_prototype_implementation_mode, "Generate the iterator prototype .cpp file", "iterator-prototype-implementation", 0); 53 args_parser.add_option(global_mixin_header_mode, "Generate the global object mixin .h file", "global-mixin-header", 0); 54 args_parser.add_option(global_mixin_implementation_mode, "Generate the global object mixin .cpp file", "global-mixin-implementation", 0); 55 args_parser.add_option(Core::ArgsParser::Option { 56 .argument_mode = Core::ArgsParser::OptionArgumentMode::Required, 57 .help_string = "Add a header search path passed to the compiler", 58 .long_name = "header-include-path", 59 .short_name = 'i', 60 .value_name = "path", 61 .accept_value = [&](StringView s) { 62 s_header_search_paths.append(s); 63 return true; 64 }, 65 }); 66 args_parser.add_option(output_path, "Path to output generated file into", "output-path", 'o', "output-path"); 67 args_parser.add_option(depfile_path, "Path to write dependency file to", "depfile", 'd', "depfile-path"); 68 args_parser.add_option(depfile_target, "Name of target in the depfile (default: output path)", "depfile-target", 't', "target"); 69 args_parser.add_positional_argument(path, "IDL file", "idl-file"); 70 args_parser.add_positional_argument(import_base_path, "Import base path", "import-base-path", Core::ArgsParser::Required::No); 71 args_parser.parse(arguments); 72 73 auto file = TRY(Core::File::open(path, Core::File::OpenMode::Read)); 74 75 LexicalPath lexical_path(path); 76 auto& namespace_ = lexical_path.parts_view().at(lexical_path.parts_view().size() - 2); 77 78 auto data = TRY(file->read_until_eof()); 79 80 if (import_base_path.is_null()) 81 import_base_path = lexical_path.dirname(); 82 83 auto output_file = TRY(Core::File::open_file_or_standard_stream(output_path, Core::File::OpenMode::Write)); 84 85 IDL::Parser parser(path, data, import_base_path); 86 auto& interface = parser.parse(); 87 88 if (IDL::libweb_interface_namespaces.span().contains_slow(namespace_)) { 89 StringBuilder builder; 90 builder.append(namespace_); 91 builder.append("::"sv); 92 builder.append(interface.name); 93 interface.fully_qualified_name = builder.to_deprecated_string(); 94 } else { 95 interface.fully_qualified_name = interface.name; 96 } 97 98 if constexpr (BINDINGS_GENERATOR_DEBUG) { 99 dbgln("Attributes:"); 100 for (auto& attribute : interface.attributes) { 101 dbgln(" {}{}{}{} {}", 102 attribute.inherit ? "inherit " : "", 103 attribute.readonly ? "readonly " : "", 104 attribute.type->name(), 105 attribute.type->is_nullable() ? "?" : "", 106 attribute.name); 107 } 108 109 dbgln("Functions:"); 110 for (auto& function : interface.functions) { 111 dbgln(" {}{} {}", 112 function.return_type->name(), 113 function.return_type->is_nullable() ? "?" : "", 114 function.name); 115 for (auto& parameter : function.parameters) { 116 dbgln(" {}{} {}", 117 parameter.type->name(), 118 parameter.type->is_nullable() ? "?" : "", 119 parameter.name); 120 } 121 } 122 123 dbgln("Static Functions:"); 124 for (auto& function : interface.static_functions) { 125 dbgln(" static {}{} {}", 126 function.return_type->name(), 127 function.return_type->is_nullable() ? "?" : "", 128 function.name); 129 for (auto& parameter : function.parameters) { 130 dbgln(" {}{} {}", 131 parameter.type->name(), 132 parameter.type->is_nullable() ? "?" : "", 133 parameter.name); 134 } 135 } 136 } 137 138 StringBuilder output_builder; 139 if (constructor_header_mode) 140 IDL::generate_constructor_header(interface, output_builder); 141 142 if (constructor_implementation_mode) 143 IDL::generate_constructor_implementation(interface, output_builder); 144 145 if (prototype_header_mode) 146 IDL::generate_prototype_header(interface, output_builder); 147 148 if (prototype_implementation_mode) 149 IDL::generate_prototype_implementation(interface, output_builder); 150 151 if (iterator_prototype_header_mode) 152 IDL::generate_iterator_prototype_header(interface, output_builder); 153 154 if (iterator_prototype_implementation_mode) 155 IDL::generate_iterator_prototype_implementation(interface, output_builder); 156 157 if (global_mixin_header_mode) 158 IDL::generate_global_mixin_header(interface, output_builder); 159 160 if (global_mixin_implementation_mode) 161 IDL::generate_global_mixin_implementation(interface, output_builder); 162 163 TRY(output_file->write_until_depleted(output_builder.string_view().bytes())); 164 165 if (!depfile_path.is_null()) { 166 auto depfile = TRY(Core::File::open_file_or_standard_stream(depfile_path, Core::File::OpenMode::Write)); 167 168 StringBuilder depfile_builder; 169 depfile_builder.append(depfile_target.is_null() ? output_path : depfile_target); 170 depfile_builder.append(':'); 171 for (auto const& path : parser.imported_files()) { 172 depfile_builder.append(" \\\n "sv); 173 depfile_builder.append(path); 174 } 175 depfile_builder.append('\n'); 176 TRY(depfile->write_until_depleted(depfile_builder.string_view().bytes())); 177 } 178 return 0; 179}