mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 07:14:58 +00:00

Similar to POSIX read, the basic read and write functions of AK::Stream do not have a lower limit of how much data they read or write (apart from "none at all"). Rename the functions to "read some [data]" and "write some [data]" (with "data" being omitted, since everything here is reading and writing data) to make them sufficiently distinct from the functions that ensure to use the entire buffer (which should be the go-to function for most usages). No functional changes, just a lot of new FIXMEs.
570 lines
23 KiB
C++
570 lines
23 KiB
C++
/*
|
|
* Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/Array.h>
|
|
#include <AK/DeprecatedString.h>
|
|
#include <AK/JsonObject.h>
|
|
#include <AK/NumericLimits.h>
|
|
#include <AK/Optional.h>
|
|
#include <AK/SourceGenerator.h>
|
|
#include <AK/StringBuilder.h>
|
|
#include <AK/StringView.h>
|
|
#include <AK/Vector.h>
|
|
#include <LibCore/ArgsParser.h>
|
|
#include <LibCore/File.h>
|
|
#include <LibMain/Main.h>
|
|
|
|
struct ArgumentDefinition {
|
|
Optional<DeprecatedString> name;
|
|
Optional<DeprecatedString> cpp_type;
|
|
DeprecatedString expression;
|
|
Optional<DeprecatedString> cast_to;
|
|
};
|
|
|
|
struct FunctionDefinition {
|
|
DeprecatedString name;
|
|
DeprecatedString return_type;
|
|
Vector<ArgumentDefinition> arguments;
|
|
DeprecatedString implementation;
|
|
bool unimplemented;
|
|
DeprecatedString variant_gl_type;
|
|
};
|
|
|
|
struct VariantType {
|
|
DeprecatedString encoded_type;
|
|
Optional<DeprecatedString> implementation;
|
|
bool unimplemented;
|
|
};
|
|
|
|
struct Variants {
|
|
Vector<DeprecatedString> api_suffixes { "" };
|
|
Vector<u32> argument_counts { NumericLimits<u32>::max() };
|
|
Vector<DeprecatedString> argument_defaults { "" };
|
|
bool convert_range { false };
|
|
Vector<VariantType> types {
|
|
{
|
|
.encoded_type = "",
|
|
.implementation = Optional<DeprecatedString> {},
|
|
.unimplemented = false,
|
|
}
|
|
};
|
|
DeprecatedString pointer_argument { "" };
|
|
};
|
|
|
|
struct EncodedTypeEntry {
|
|
StringView encoded_type;
|
|
StringView cpp_type;
|
|
StringView gl_type;
|
|
};
|
|
|
|
// clang-format off
|
|
constexpr static Array<EncodedTypeEntry, 9> type_definitions = {
|
|
EncodedTypeEntry { "b"sv, "GLbyte"sv, "GL_BYTE"sv },
|
|
EncodedTypeEntry { "d"sv, "GLdouble"sv, "GL_DOUBLE"sv },
|
|
EncodedTypeEntry { "f"sv, "GLfloat"sv, "GL_FLOAT"sv },
|
|
EncodedTypeEntry { "i"sv, "GLint"sv, "GL_INT"sv },
|
|
EncodedTypeEntry { "s"sv, "GLshort"sv, "GL_SHORT"sv },
|
|
EncodedTypeEntry { "ub"sv, "GLubyte"sv, "GL_UNSIGNED_BYTE"sv },
|
|
EncodedTypeEntry { "ui"sv, "GLuint"sv, "GL_UNSIGNED_INT"sv },
|
|
EncodedTypeEntry { "us"sv, "GLushort"sv, "GL_UNSIGNED_SHORT"sv },
|
|
EncodedTypeEntry { "x"sv, "GLfixed"sv, "GL_INT"sv },
|
|
};
|
|
// clang-format on
|
|
|
|
struct EncodedType {
|
|
EncodedTypeEntry type_entry;
|
|
DeprecatedString cpp_type;
|
|
DeprecatedString function_name_suffix;
|
|
bool is_pointer;
|
|
bool is_const_pointer;
|
|
};
|
|
|
|
Vector<DeprecatedString> get_name_list(Optional<JsonValue const&> name_definition)
|
|
{
|
|
if (!name_definition.has_value() || name_definition->is_null())
|
|
return {};
|
|
|
|
Vector<DeprecatedString, 1> names;
|
|
if (name_definition->is_string()) {
|
|
names.append(name_definition->as_string());
|
|
} else if (name_definition->is_array()) {
|
|
name_definition->as_array().for_each([&names](auto& value) {
|
|
VERIFY(value.is_string());
|
|
names.append(value.as_string());
|
|
});
|
|
} else {
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
return names;
|
|
}
|
|
|
|
Optional<EncodedType> get_encoded_type(DeprecatedString encoded_type)
|
|
{
|
|
bool is_const_pointer = !encoded_type.ends_with('!');
|
|
if (!is_const_pointer)
|
|
encoded_type = encoded_type.substring_view(0, encoded_type.length() - 1);
|
|
DeprecatedString function_name_suffix = encoded_type;
|
|
|
|
bool is_pointer = encoded_type.ends_with('v');
|
|
if (is_pointer)
|
|
encoded_type = encoded_type.substring_view(0, encoded_type.length() - 1);
|
|
|
|
VERIFY(is_const_pointer || is_pointer);
|
|
|
|
Optional<EncodedTypeEntry> type_definition;
|
|
for (size_t i = 0; i < type_definitions.size(); ++i) {
|
|
if (type_definitions[i].encoded_type == encoded_type) {
|
|
type_definition = type_definitions[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!type_definition.has_value())
|
|
return {};
|
|
|
|
return EncodedType {
|
|
.type_entry = type_definition.value(),
|
|
.cpp_type = DeprecatedString::formatted(
|
|
"{}{}{}",
|
|
type_definition->cpp_type,
|
|
is_pointer && is_const_pointer ? " const" : "",
|
|
is_pointer ? "*" : ""),
|
|
.function_name_suffix = function_name_suffix,
|
|
.is_pointer = is_pointer,
|
|
.is_const_pointer = is_const_pointer,
|
|
};
|
|
}
|
|
|
|
DeprecatedString wrap_expression_in_range_conversion(DeprecatedString source_type, DeprecatedString target_type, DeprecatedString expression)
|
|
{
|
|
VERIFY(target_type == "GLfloat" || target_type == "GLdouble");
|
|
|
|
// No range conversion required
|
|
if (source_type == target_type || source_type == "GLdouble")
|
|
return expression;
|
|
|
|
if (source_type == "GLbyte")
|
|
return DeprecatedString::formatted("({} + 128.) / 127.5 - 1.", expression);
|
|
else if (source_type == "GLfloat")
|
|
return DeprecatedString::formatted("static_cast<GLdouble>({})", expression);
|
|
else if (source_type == "GLint")
|
|
return DeprecatedString::formatted("({} + 2147483648.) / 2147483647.5 - 1.", expression);
|
|
else if (source_type == "GLshort")
|
|
return DeprecatedString::formatted("({} + 32768.) / 32767.5 - 1.", expression);
|
|
else if (source_type == "GLubyte")
|
|
return DeprecatedString::formatted("{} / 255.", expression);
|
|
else if (source_type == "GLuint")
|
|
return DeprecatedString::formatted("{} / 4294967296.", expression);
|
|
else if (source_type == "GLushort")
|
|
return DeprecatedString::formatted("{} / 65536.", expression);
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
|
|
Variants read_variants_settings(JsonObject const& variants_obj)
|
|
{
|
|
Variants variants;
|
|
|
|
if (variants_obj.has_array("argument_counts"sv)) {
|
|
variants.argument_counts.clear_with_capacity();
|
|
variants_obj.get_array("argument_counts"sv)->for_each([&](auto const& argument_count_value) {
|
|
variants.argument_counts.append(argument_count_value.to_u32());
|
|
});
|
|
}
|
|
if (variants_obj.has_array("argument_defaults"sv)) {
|
|
variants.argument_defaults.clear_with_capacity();
|
|
variants_obj.get_array("argument_defaults"sv)->for_each([&](auto const& argument_default_value) {
|
|
variants.argument_defaults.append(argument_default_value.as_string());
|
|
});
|
|
}
|
|
if (variants_obj.has_bool("convert_range"sv)) {
|
|
variants.convert_range = variants_obj.get_bool("convert_range"sv).value();
|
|
}
|
|
if (variants_obj.has_array("api_suffixes"sv)) {
|
|
variants.api_suffixes.clear_with_capacity();
|
|
variants_obj.get_array("api_suffixes"sv)->for_each([&](auto const& suffix_value) {
|
|
variants.api_suffixes.append(suffix_value.as_string());
|
|
});
|
|
}
|
|
if (variants_obj.has_string("pointer_argument"sv)) {
|
|
variants.pointer_argument = variants_obj.get_deprecated_string("pointer_argument"sv).value();
|
|
}
|
|
if (variants_obj.has_object("types"sv)) {
|
|
variants.types.clear_with_capacity();
|
|
variants_obj.get_object("types"sv)->for_each_member([&](auto const& key, auto const& type_value) {
|
|
auto const& type = type_value.as_object();
|
|
variants.types.append(VariantType {
|
|
.encoded_type = key,
|
|
.implementation = type.get_deprecated_string("implementation"sv),
|
|
.unimplemented = type.get_bool("unimplemented"sv).value_or(false),
|
|
});
|
|
});
|
|
}
|
|
|
|
return variants;
|
|
}
|
|
|
|
Vector<ArgumentDefinition> copy_arguments_for_variant(Vector<ArgumentDefinition> arguments, Variants variants,
|
|
u32 argument_count, EncodedType encoded_type)
|
|
{
|
|
Vector<ArgumentDefinition> variant_arguments = arguments;
|
|
auto base_cpp_type = encoded_type.type_entry.cpp_type;
|
|
|
|
size_t variadic_index = 0;
|
|
for (size_t i = 0; i < variant_arguments.size(); ++i) {
|
|
// Skip arguments with a fixed type
|
|
if (variant_arguments[i].cpp_type.has_value())
|
|
continue;
|
|
|
|
variant_arguments[i].cpp_type = encoded_type.cpp_type;
|
|
auto cast_to = variant_arguments[i].cast_to;
|
|
|
|
// Pointer argument
|
|
if (encoded_type.is_pointer) {
|
|
variant_arguments[i].name = (variadic_index == 0) ? variants.pointer_argument : Optional<DeprecatedString> {};
|
|
|
|
if (variadic_index >= argument_count) {
|
|
// If this variable argument is past the argument count, fall back to the defaults
|
|
variant_arguments[i].expression = variants.argument_defaults[variadic_index];
|
|
variant_arguments[i].cast_to = Optional<DeprecatedString> {};
|
|
|
|
} else if (argument_count == 1 && variants.argument_counts.size() == 1) {
|
|
// Otherwise, if the pointer is the only variadic argument, pass it through unchanged
|
|
variant_arguments[i].cast_to = Optional<DeprecatedString> {};
|
|
|
|
} else {
|
|
// Otherwise, index into the pointer argument
|
|
auto indexed_expression = DeprecatedString::formatted("{}[{}]", variants.pointer_argument, variadic_index);
|
|
if (variants.convert_range && cast_to.has_value())
|
|
indexed_expression = wrap_expression_in_range_conversion(base_cpp_type, cast_to.value(), indexed_expression);
|
|
variant_arguments[i].expression = indexed_expression;
|
|
}
|
|
|
|
} else {
|
|
// Regular argument
|
|
if (variadic_index >= argument_count) {
|
|
// If the variable argument is past the argument count, fall back to the defaults
|
|
variant_arguments[i].name = Optional<DeprecatedString> {};
|
|
variant_arguments[i].expression = variants.argument_defaults[variadic_index];
|
|
variant_arguments[i].cast_to = Optional<DeprecatedString> {};
|
|
|
|
} else if (variants.convert_range && cast_to.has_value()) {
|
|
// Otherwise, if we need to convert the input values, wrap the expression in a range conversion
|
|
variant_arguments[i].expression = wrap_expression_in_range_conversion(
|
|
base_cpp_type,
|
|
cast_to.value(),
|
|
variant_arguments[i].expression);
|
|
}
|
|
}
|
|
|
|
// Determine if we can skip casting to the target type
|
|
if (cast_to == base_cpp_type || (variants.convert_range && cast_to == "GLdouble"))
|
|
variant_arguments[i].cast_to = Optional<DeprecatedString> {};
|
|
|
|
variadic_index++;
|
|
}
|
|
|
|
return variant_arguments;
|
|
}
|
|
|
|
Vector<FunctionDefinition> create_function_definitions(DeprecatedString function_name, JsonObject const& function_definition)
|
|
{
|
|
// A single function definition can expand to multiple generated functions by way of:
|
|
// - differing API suffices (ARB, EXT, etc.);
|
|
// - differing argument counts;
|
|
// - differing argument types.
|
|
// These can all be combined.
|
|
|
|
// Parse base argument definitions first; these may later be modified by variants
|
|
Vector<ArgumentDefinition> argument_definitions;
|
|
JsonArray const& arguments = function_definition.get_array("arguments"sv).value_or(JsonArray {});
|
|
arguments.for_each([&argument_definitions](auto const& argument_value) {
|
|
VERIFY(argument_value.is_object());
|
|
auto const& argument = argument_value.as_object();
|
|
|
|
auto type = argument.get_deprecated_string("type"sv);
|
|
auto argument_names = get_name_list(argument.get("name"sv));
|
|
auto expression = argument.get_deprecated_string("expression"sv).value_or("@argument_name@");
|
|
auto cast_to = argument.get_deprecated_string("cast_to"sv);
|
|
|
|
// Add an empty dummy name when all we have is an expression
|
|
if (argument_names.is_empty() && !expression.is_empty())
|
|
argument_names.append("");
|
|
|
|
for (auto const& argument_name : argument_names) {
|
|
argument_definitions.append({ .name = argument_name.is_empty() ? Optional<DeprecatedString> {} : argument_name,
|
|
.cpp_type = type,
|
|
.expression = expression,
|
|
.cast_to = cast_to });
|
|
}
|
|
});
|
|
|
|
// Create functions for each name and/or variant
|
|
Vector<FunctionDefinition> functions;
|
|
|
|
auto return_type = function_definition.get_deprecated_string("return_type"sv).value_or("void");
|
|
auto function_implementation = function_definition.get_deprecated_string("implementation"sv).value_or(function_name.to_snakecase());
|
|
auto function_unimplemented = function_definition.get_bool("unimplemented"sv).value_or(false);
|
|
|
|
if (!function_definition.has("variants"sv)) {
|
|
functions.append({
|
|
.name = function_name,
|
|
.return_type = return_type,
|
|
.arguments = argument_definitions,
|
|
.implementation = function_implementation,
|
|
.unimplemented = function_unimplemented,
|
|
.variant_gl_type = "",
|
|
});
|
|
return functions;
|
|
}
|
|
|
|
// Read variants settings for this function
|
|
auto variants_obj = function_definition.get_object("variants"sv).value();
|
|
auto variants = read_variants_settings(variants_obj);
|
|
|
|
for (auto argument_count : variants.argument_counts) {
|
|
for (auto const& variant_type : variants.types) {
|
|
auto encoded_type = get_encoded_type(variant_type.encoded_type);
|
|
auto variant_arguments = encoded_type.has_value()
|
|
? copy_arguments_for_variant(argument_definitions, variants, argument_count, encoded_type.value())
|
|
: argument_definitions;
|
|
auto variant_type_implementation = variant_type.implementation.has_value()
|
|
? variant_type.implementation.value()
|
|
: function_implementation;
|
|
|
|
for (auto const& api_suffix : variants.api_suffixes) {
|
|
functions.append({
|
|
.name = DeprecatedString::formatted(
|
|
"{}{}{}{}",
|
|
function_name,
|
|
variants.argument_counts.size() > 1 ? DeprecatedString::formatted("{}", argument_count) : "",
|
|
encoded_type.has_value() && variants.types.size() > 1 ? encoded_type->function_name_suffix : "",
|
|
api_suffix),
|
|
.return_type = return_type,
|
|
.arguments = variant_arguments,
|
|
.implementation = variant_type_implementation,
|
|
.unimplemented = variant_type.unimplemented || function_unimplemented,
|
|
.variant_gl_type = encoded_type.has_value() ? encoded_type->type_entry.gl_type : ""sv,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return functions;
|
|
}
|
|
|
|
ErrorOr<void> generate_header_file(JsonObject& api_data, Core::File& file)
|
|
{
|
|
StringBuilder builder;
|
|
SourceGenerator generator { builder };
|
|
|
|
generator.appendln("#pragma once");
|
|
generator.append("\n");
|
|
generator.appendln("#include <LibGL/GL/glplatform.h>");
|
|
generator.append("\n");
|
|
generator.appendln("#ifdef __cplusplus");
|
|
generator.appendln("extern \"C\" {");
|
|
generator.appendln("#endif");
|
|
generator.append("\n");
|
|
|
|
api_data.for_each_member([&](auto& function_name, auto& value) {
|
|
VERIFY(value.is_object());
|
|
auto const& function = value.as_object();
|
|
auto function_definitions = create_function_definitions(function_name, function);
|
|
|
|
for (auto const& function_definition : function_definitions) {
|
|
auto function_generator = generator.fork();
|
|
|
|
function_generator.set("name", function_definition.name);
|
|
function_generator.set("return_type", function_definition.return_type);
|
|
|
|
function_generator.append("GLAPI @return_type@ gl@name@(");
|
|
|
|
bool first = true;
|
|
for (auto const& argument_definition : function_definition.arguments) {
|
|
if (!argument_definition.name.has_value() || !argument_definition.cpp_type.has_value())
|
|
continue;
|
|
|
|
auto argument_generator = function_generator.fork();
|
|
argument_generator.set("argument_type", argument_definition.cpp_type.value());
|
|
argument_generator.set("argument_name", argument_definition.name.value());
|
|
|
|
if (!first)
|
|
argument_generator.append(", ");
|
|
first = false;
|
|
argument_generator.append("@argument_type@ @argument_name@");
|
|
}
|
|
|
|
function_generator.appendln(");");
|
|
}
|
|
});
|
|
|
|
generator.appendln("#ifdef __cplusplus");
|
|
generator.appendln("}");
|
|
generator.appendln("#endif");
|
|
|
|
// FIXME: This should write the entire span.
|
|
TRY(file.write_some(generator.as_string_view().bytes()));
|
|
return {};
|
|
}
|
|
|
|
ErrorOr<void> generate_implementation_file(JsonObject& api_data, Core::File& file)
|
|
{
|
|
StringBuilder builder;
|
|
SourceGenerator generator { builder };
|
|
|
|
generator.appendln("#include <LibGL/GL/glapi.h>");
|
|
generator.appendln("#include <LibGL/GLContext.h>");
|
|
generator.append("\n");
|
|
generator.appendln("extern GL::GLContext* g_gl_context;");
|
|
generator.append("\n");
|
|
|
|
api_data.for_each_member([&](auto& function_name, auto& value) {
|
|
VERIFY(value.is_object());
|
|
JsonObject const& function = value.as_object();
|
|
auto function_definitions = create_function_definitions(function_name, function);
|
|
|
|
for (auto const& function_definition : function_definitions) {
|
|
auto function_generator = generator.fork();
|
|
auto return_type = function_definition.return_type;
|
|
|
|
function_generator.set("name"sv, function_definition.name);
|
|
function_generator.set("return_type"sv, return_type);
|
|
function_generator.set("implementation"sv, function_definition.implementation);
|
|
function_generator.set("variant_gl_type"sv, function_definition.variant_gl_type);
|
|
|
|
function_generator.append("@return_type@ gl@name@(");
|
|
|
|
bool first = true;
|
|
for (auto const& argument_definition : function_definition.arguments) {
|
|
if (!argument_definition.name.has_value() || !argument_definition.cpp_type.has_value())
|
|
continue;
|
|
|
|
auto argument_generator = function_generator.fork();
|
|
argument_generator.set("argument_type", argument_definition.cpp_type.value());
|
|
argument_generator.set("argument_name", argument_definition.name.value());
|
|
|
|
if (!first)
|
|
argument_generator.append(", ");
|
|
first = false;
|
|
argument_generator.append("@argument_type@ @argument_name@");
|
|
}
|
|
function_generator.appendln(")");
|
|
function_generator.appendln("{");
|
|
|
|
if (function_definition.unimplemented) {
|
|
function_generator.append(" dbgln(\"gl@name@(");
|
|
|
|
first = true;
|
|
for (auto const& argument_definition : function_definition.arguments) {
|
|
if (!argument_definition.name.has_value())
|
|
continue;
|
|
if (!first)
|
|
function_generator.append(", ");
|
|
first = false;
|
|
if (argument_definition.cpp_type.value().ends_with('*'))
|
|
function_generator.append("{:p}");
|
|
else if (argument_definition.cpp_type.value() == "GLenum")
|
|
function_generator.append("{:#x}");
|
|
else
|
|
function_generator.append("{}");
|
|
}
|
|
|
|
function_generator.append("): unimplemented\"");
|
|
|
|
for (auto const& argument_definition : function_definition.arguments) {
|
|
if (!argument_definition.name.has_value())
|
|
continue;
|
|
|
|
function_generator.append(", ");
|
|
function_generator.append(argument_definition.name.value());
|
|
}
|
|
|
|
function_generator.appendln(");");
|
|
function_generator.appendln(" TODO();");
|
|
} else {
|
|
function_generator.appendln(" if (!g_gl_context)");
|
|
if (return_type.ends_with('*'))
|
|
function_generator.appendln(" return nullptr;");
|
|
else if (return_type == "GLboolean"sv)
|
|
function_generator.appendln(" return GL_FALSE;");
|
|
else if (return_type == "GLenum"sv)
|
|
function_generator.appendln(" return GL_INVALID_OPERATION;");
|
|
else if (return_type == "GLuint"sv)
|
|
function_generator.appendln(" return 0;");
|
|
else if (return_type == "void"sv)
|
|
function_generator.appendln(" return;");
|
|
else
|
|
VERIFY_NOT_REACHED();
|
|
function_generator.append(" ");
|
|
if (return_type != "void"sv)
|
|
function_generator.append("return ");
|
|
function_generator.append("g_gl_context->gl_@implementation@(");
|
|
|
|
first = true;
|
|
for (auto const& argument_definition : function_definition.arguments) {
|
|
auto argument_generator = function_generator.fork();
|
|
|
|
auto cast_to = argument_definition.cast_to;
|
|
argument_generator.set("argument_name", argument_definition.name.value_or(""));
|
|
argument_generator.set("cast_to", cast_to.value_or(""));
|
|
|
|
if (!first)
|
|
argument_generator.append(", ");
|
|
first = false;
|
|
|
|
if (cast_to.has_value())
|
|
argument_generator.append("static_cast<@cast_to@>(");
|
|
argument_generator.append(argument_definition.expression);
|
|
if (cast_to.has_value())
|
|
argument_generator.append(")");
|
|
}
|
|
|
|
function_generator.appendln(");");
|
|
}
|
|
|
|
function_generator.appendln("}");
|
|
function_generator.append("\n");
|
|
}
|
|
});
|
|
|
|
// FIXME: This should write the entire span.
|
|
TRY(file.write_some(generator.as_string_view().bytes()));
|
|
return {};
|
|
}
|
|
|
|
ErrorOr<JsonValue> read_entire_file_as_json(StringView filename)
|
|
{
|
|
auto file = TRY(Core::File::open(filename, Core::File::OpenMode::Read));
|
|
auto json_size = TRY(file->size());
|
|
auto json_data = TRY(ByteBuffer::create_uninitialized(json_size));
|
|
TRY(file->read_entire_buffer(json_data.bytes()));
|
|
return JsonValue::from_string(json_data);
|
|
}
|
|
|
|
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|
{
|
|
StringView generated_header_path;
|
|
StringView generated_implementation_path;
|
|
StringView api_json_path;
|
|
|
|
Core::ArgsParser args_parser;
|
|
args_parser.add_option(generated_header_path, "Path to the OpenGL API header file to generate", "generated-header-path", 'h', "generated-header-path");
|
|
args_parser.add_option(generated_implementation_path, "Path to the OpenGL API implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path");
|
|
args_parser.add_option(api_json_path, "Path to the JSON file to read from", "json-path", 'j', "json-path");
|
|
args_parser.parse(arguments);
|
|
|
|
auto json = TRY(read_entire_file_as_json(api_json_path));
|
|
VERIFY(json.is_object());
|
|
auto api_data = json.as_object();
|
|
|
|
auto generated_header_file = TRY(Core::File::open(generated_header_path, Core::File::OpenMode::Write));
|
|
auto generated_implementation_file = TRY(Core::File::open(generated_implementation_path, Core::File::OpenMode::Write));
|
|
|
|
TRY(generate_header_file(api_data, *generated_header_file));
|
|
TRY(generate_implementation_file(api_data, *generated_implementation_file));
|
|
|
|
return 0;
|
|
}
|