4#include "tutorial_support.hpp"
19int main(
int argument_count,
char const*
const* argument_values)
22 std::filesystem::path
const output_directory = argument_count == 2 ? std::filesystem::path(argument_values[1]) : std::filesystem::current_path();
23 std::filesystem::create_directories(output_directory);
27 static_cast< void >(builder.add_field(
30 rpnx::cortado::field_access_flags::is_public |
31 rpnx::cortado::field_access_flags::is_static));
34 constructor.
aload({0})
35 .invokespecial(
"java/lang/Object",
"<init>",
"()V")
36 .append< rpnx::cortado::opcode::return_ >();
37 static_cast< void >(builder.add_method(
40 rpnx::cortado::method_access_flags::is_public,
51 sum_to.
bind(sum_entry)
52 .append< rpnx::cortado::opcode::iconst_0 >()
54 .append< rpnx::cortado::opcode::iconst_1 >()
59 .branch< rpnx::cortado::opcode::if_icmpgt >(sum_done)
62 .append< rpnx::cortado::opcode::iadd >()
65 .branch< rpnx::cortado::opcode::goto_ >(sum_loop)
68 .append< rpnx::cortado::opcode::ireturn >()
72 .add_line_number(sum_loop, 12)
73 .add_line_number(sum_done, 16)
74 .add_local_variable(sum_entry, sum_end,
"limit",
"I", {0})
75 .add_local_variable(sum_entry, sum_end,
"sum",
"I", {1})
76 .add_local_variable(sum_entry, sum_end,
"index",
"I", {2});
78 static_cast< void >(builder.add_method(
81 rpnx::cortado::method_access_flags::is_public |
82 rpnx::cortado::method_access_flags::is_static,
92 classify.
iload({0}).lookupswitch(
94 {{0, zero_case}, {1, one_case}});
95 classify.
bind(zero_case)
97 .append< rpnx::cortado::opcode::areturn >();
98 classify.
bind(one_case)
100 .append< rpnx::cortado::opcode::areturn >();
101 classify.
bind(other_case)
103 .append< rpnx::cortado::opcode::areturn >();
105 static_cast< void >(builder.add_method(
107 "(I)Ljava/lang/String;",
108 rpnx::cortado::method_access_flags::is_public |
109 rpnx::cortado::method_access_flags::is_static,
119 safe_divide.
bind(protected_start)
122 .append< rpnx::cortado::opcode::idiv >()
123 .append< rpnx::cortado::opcode::ireturn >()
125 .bind(arithmetic_handler)
127 .append< rpnx::cortado::opcode::iconst_0 >()
128 .append< rpnx::cortado::opcode::ireturn >();
133 "java/lang/ArithmeticException");
135 static_cast< void >(builder.add_method(
138 rpnx::cortado::method_access_flags::is_public |
139 rpnx::cortado::method_access_flags::is_static,
147 select_collection.
iload({0})
148 .branch< rpnx::cortado::opcode::ifeq >(use_map)
150 .branch< rpnx::cortado::opcode::goto_ >(collection_selected)
153 .bind(collection_selected)
154 .append< rpnx::cortado::opcode::areturn >();
157 static_cast< void >(builder.add_method(
159 "(ZLjava/util/ArrayList;Ljava/util/HashMap;)Ljava/lang/Object;",
160 rpnx::cortado::method_access_flags::is_public |
161 rpnx::cortado::method_access_flags::is_static,
172 throw std::runtime_error(report.
diagnostics.front().message);
178 std::string
const manifest_text =
"Manifest-Version: 1.0\n\n";
179 std::vector< std::byte > manifest_bytes;
180 manifest_bytes.reserve(manifest_text.size());
181 for (
char const character : manifest_text)
183 manifest_bytes.push_back(
static_cast< std::byte
>(
static_cast< std::uint8_t
>(character)));
188 .name =
"META-INF/MANIFEST.MF",
189 .data = std::move(manifest_bytes),
190 .compression = rpnx::cortado::compression_method::stored,
191 .flags = rpnx::cortado::jar_entry_flags::utf8_names,
194 .name =
"tutorial/Generated.class",
196 .compression = rpnx::cortado::compression_method::deflated,
197 .flags = rpnx::cortado::jar_entry_flags::utf8_names,
202 auto write_binary_file = [](std::filesystem::path
const& path, std::span< std::byte const > bytes)
204 std::ofstream output(path, std::ios::binary | std::ios::trunc);
207 throw std::runtime_error(
"could not open " + path.string());
209 output.write(
reinterpret_cast< char const*
>(bytes.data()),
static_cast< std::streamsize
>(bytes.size()));
212 throw std::runtime_error(
"could not write " + path.string());
216 std::filesystem::path
const package_directory = output_directory /
"tutorial";
217 std::filesystem::create_directories(package_directory);
218 write_binary_file(package_directory /
"Generated.class", class_bytes);
219 write_binary_file(output_directory /
"tutorial-codegen.jar", jar_bytes);
222catch (std::exception
const& error)
224 std::cerr << error.what() <<
'\n';
Deterministic constant-pool and symbolic class-file builders.
An owning symbolic class-file builder with a shared constant-pool interner.
Non-owning type-erased class-hierarchy resolver used for reference merges.
An owning symbolic JVM code builder.
auto iload(local_variable_index index) -> code_builder &
Loads an int from a local using the shortest valid encoding.
auto aload(local_variable_index index) -> code_builder &
Loads a reference from a local using the shortest valid encoding.
auto bind(label value) -> code_builder &
Binds a label at the current instruction position.
label new_label()
Creates a fresh label owned by this builder.
auto add_exception_handler(label start, label end, label handler, std::optional< std::string > catch_type=std::nullopt) -> code_builder &
Adds a symbolic exception-table range.
auto add_line_number(label start, std::uint16_t line_number) -> code_builder &
Associates a source line with a symbolic code position.
JAR-compatible ZIP serialization and deserialization APIs.
std::vector< std::byte > serialize_jar(jar_file const &value)
Serializes an archive as a non-Zip64 JAR-compatible ZIP file.
std::vector< std::byte > serialize_class_file(class_file const &value, class_file_write_options const &options={})
Serializes a class file using the big-endian JVM class-file format.
validation_report validate_class_file(class_file const &value, validation_options const &options={})
Validates a complete class-file model without throwing for model errors.
An owning, typed representation of one JVM class file.
A deliberately conservative hierarchy resolver for the code-generation tutorial.
One owning JAR/ZIP entry, with its data stored uncompressed in memory.
An owning JAR archive representation.
std::vector< jar_entry > entries
Entries in central-directory order; duplicate names remain distinct.
A symbolic bytecode position owned by one code_builder.
The complete bounded diagnostic result of one validation pass.
bool valid() const noexcept
Returns true when validation produced no diagnostics.
std::vector< validation_diagnostic > diagnostics
Failures in deterministic traversal order, bounded by the options.
A packed MS-DOS date value from a ZIP entry header.
Bounded, non-throwing validation for structured class-file models.