main.cpp 8.4 KB

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