Created
December 26, 2025 02:41
-
-
Save RevolvingMadness/9129719a54f0b0ccbcc4fb206816fd44 to your computer and use it in GitHub Desktop.
The code for my JVM interpreter in Minecraft
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // SCORE: bc | |
| let classfile_raw: value = storage bc:parser/classfile raw | |
| let classfile_index: value = score index bc | |
| let tag_utf8: value = 1 | |
| let tag_integer: value = 3 | |
| let tag_float: value = 4 | |
| let tag_long: value = 5 | |
| let tag_double: value = 6 | |
| let tag_class: value = 7 | |
| let tag_string: value = 8 | |
| let tag_fieldref: value = 9 | |
| let tag_methodref: value = 10 | |
| let tag_interface_methodref: value = 11 | |
| let tag_name_and_type: value = 12 | |
| let tag_method_handle: value = 15 | |
| let tag_method_type: value = 16 | |
| let tag_invoke_dynamic: value = 18 | |
| // SCORE: parser_parse_u1 | |
| let parse_u1_output: value = score output parser_parse_u1 | |
| mcfunction bc:parser/parse_u1 { | |
| if !classfile_raw[classfile_index] { | |
| return 1 | |
| } | |
| parse_u1_output = classfile_raw[classfile_index] | |
| classfile_index += 1 | |
| } | |
| // SCORE: parser_parse_u2 | |
| let parser_parse_u2_output: value = score output parser_parse_u2 | |
| mcfunction bc:parser/parse_u2 { | |
| if !classfile_raw[classfile_index] { | |
| return 1 | |
| } | |
| let copied: data = classfile_raw | |
| let first: score = (copied[classfile_index]) * 256 | |
| classfile_index += 1 | |
| if !copied[classfile_index] { | |
| return 1 | |
| } | |
| first += copied[classfile_index] | |
| classfile_index += 1 | |
| parser_parse_u2_output = first | |
| } | |
| // SCORE: parser_parse_u4_part | |
| let parse_u4_part_output: value = score output parser_parse_u4_part | |
| mcfunction bc:parser/parse_u4_part { | |
| if !classfile_raw[classfile_index] { | |
| return 1 | |
| } | |
| let copied: data = classfile_raw | |
| let first: score = (copied[classfile_index]) * 256 | |
| classfile_index += 1 | |
| if !copied[classfile_index] { | |
| return 1 | |
| } | |
| first += copied[classfile_index] | |
| classfile_index += 1 | |
| parse_u4_part_output = first | |
| } | |
| let parser_parse_bytes_length: value = storage bc:parser/parse_bytes length | |
| let parser_parse_bytes_output: value = storage bc:parser/parse_bytes output | |
| mcfunction bc:parser/parse_bytes { | |
| parser_parse_bytes_output = [] | |
| if !classfile_raw[classfile_index] { | |
| return 1 | |
| } | |
| let offset: score = 0 | |
| while offset < parser_parse_bytes_length { | |
| let byte: value = classfile_raw[classfile_index] | |
| append parser_parse_bytes_output byte | |
| offset += 1 | |
| classfile_index += 1 | |
| } | |
| } | |
| let constant_pool_raw: value = storage bc:parser/classfile classfile.constant_pool_raw | |
| mcfunction bc:parser/constant_pool/parse { | |
| function bc:parser/parse_u2 | |
| let constant_pool_entries: score = parser_parse_u2_output | |
| constant_pool_raw = [{}] | |
| let index: score = 1 | |
| while index < constant_pool_entries { | |
| function bc:parser/parse_u1 | |
| let tag: score = parse_u1_output | |
| let entry: data = {tag: tag} | |
| let parsed_slots: score = 1 | |
| if tag == tag_utf8 { | |
| function bc:parser/parse_u2 | |
| parser_parse_bytes_length = parser_parse_u2_output | |
| function bc:parser/parse_bytes | |
| entry.value = parser_parse_bytes_output | |
| } else if tag == tag_class { | |
| function bc:parser/parse_u2 | |
| entry.name_index = parser_parse_u2_output | |
| } else if tag == tag_string { | |
| function bc:parser/parse_u2 | |
| entry.string_index = parser_parse_u2_output | |
| } else if tag == tag_fieldref || tag == tag_methodref || tag == tag_interface_methodref { | |
| function bc:parser/parse_u2 | |
| entry.class_index = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| entry.name_and_type_index = parser_parse_u2_output | |
| } else if tag == tag_name_and_type { | |
| function bc:parser/parse_u2 | |
| entry.name_index = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| entry.descriptor_index = parser_parse_u2_output | |
| } else { | |
| tellraw @a {text: "Failed to parse CP entry", color: "red"} | |
| index = constant_pool_entries | |
| } | |
| append constant_pool_raw entry | |
| index += parsed_slots | |
| } | |
| } | |
| // SCORE: byte_to_string | |
| let byte_to_string_byte: value = score byte byte_to_string | |
| let byte_to_string_output: value = storage bc:parser/byte_to_string output | |
| mcfunction bc:parser/byte_to_string { | |
| if (byte_to_string_byte >= 32 && byte_to_string_byte <= 44) { | |
| function bc:parser/byte_to_string/part_0 | |
| } else if (byte_to_string_byte >= 45 && byte_to_string_byte <= 57) { | |
| function bc:parser/byte_to_string/part_1 | |
| } else if (byte_to_string_byte >= 58 && byte_to_string_byte <= 70) { | |
| function bc:parser/byte_to_string/part_2 | |
| } else if (byte_to_string_byte >= 71 && byte_to_string_byte <= 83) { | |
| function bc:parser/byte_to_string/part_3 | |
| } else if (byte_to_string_byte >= 84 && byte_to_string_byte <= 96) { | |
| function bc:parser/byte_to_string/part_4 | |
| } else if (byte_to_string_byte >= 97 && byte_to_string_byte <= 109) { | |
| function bc:parser/byte_to_string/part_5 | |
| } else if (byte_to_string_byte >= 110 && byte_to_string_byte <= 122) { | |
| function bc:parser/byte_to_string/part_6 | |
| } else if (byte_to_string_byte >= 123 && byte_to_string_byte <= 126) { | |
| function bc:parser/byte_to_string/part_7 | |
| } | |
| } | |
| mcfunction bc:parser/byte_to_string/part_0 { | |
| if (byte_to_string_byte == 32) { | |
| byte_to_string_output = " " | |
| } else if (byte_to_string_byte == 33) { | |
| byte_to_string_output = "!" | |
| } else if (byte_to_string_byte == 34) { | |
| byte_to_string_output = "\"" | |
| } else if (byte_to_string_byte == 35) { | |
| byte_to_string_output = "#" | |
| } else if (byte_to_string_byte == 36) { | |
| byte_to_string_output = "$" | |
| } else if (byte_to_string_byte == 37) { | |
| byte_to_string_output = "%" | |
| } else if (byte_to_string_byte == 38) { | |
| byte_to_string_output = "&" | |
| } else if (byte_to_string_byte == 39) { | |
| byte_to_string_output = "'" | |
| } else if (byte_to_string_byte == 40) { | |
| byte_to_string_output = "(" | |
| } else if (byte_to_string_byte == 41) { | |
| byte_to_string_output = ")" | |
| } else if (byte_to_string_byte == 42) { | |
| byte_to_string_output = "*" | |
| } else if (byte_to_string_byte == 43) { | |
| byte_to_string_output = "+" | |
| } else if (byte_to_string_byte == 44) { | |
| byte_to_string_output = "," | |
| } | |
| } | |
| mcfunction bc:parser/byte_to_string/part_1 { | |
| if (byte_to_string_byte == 45) { | |
| byte_to_string_output = "-" | |
| } else if (byte_to_string_byte == 46) { | |
| byte_to_string_output = "." | |
| } else if (byte_to_string_byte == 47) { | |
| byte_to_string_output = "/" | |
| } else if (byte_to_string_byte == 48) { | |
| byte_to_string_output = "0" | |
| } else if (byte_to_string_byte == 49) { | |
| byte_to_string_output = "1" | |
| } else if (byte_to_string_byte == 50) { | |
| byte_to_string_output = "2" | |
| } else if (byte_to_string_byte == 51) { | |
| byte_to_string_output = "3" | |
| } else if (byte_to_string_byte == 52) { | |
| byte_to_string_output = "4" | |
| } else if (byte_to_string_byte == 53) { | |
| byte_to_string_output = "5" | |
| } else if (byte_to_string_byte == 54) { | |
| byte_to_string_output = "6" | |
| } else if (byte_to_string_byte == 55) { | |
| byte_to_string_output = "7" | |
| } else if (byte_to_string_byte == 56) { | |
| byte_to_string_output = "8" | |
| } else if (byte_to_string_byte == 57) { | |
| byte_to_string_output = "9" | |
| } | |
| } | |
| mcfunction bc:parser/byte_to_string/part_2 { | |
| if (byte_to_string_byte == 58) { | |
| byte_to_string_output = ":" | |
| } else if (byte_to_string_byte == 59) { | |
| byte_to_string_output = ";" | |
| } else if (byte_to_string_byte == 60) { | |
| byte_to_string_output = "<" | |
| } else if (byte_to_string_byte == 61) { | |
| byte_to_string_output = "=" | |
| } else if (byte_to_string_byte == 62) { | |
| byte_to_string_output = ">" | |
| } else if (byte_to_string_byte == 63) { | |
| byte_to_string_output = "?" | |
| } else if (byte_to_string_byte == 64) { | |
| byte_to_string_output = "@" | |
| } else if (byte_to_string_byte == 65) { | |
| byte_to_string_output = "A" | |
| } else if (byte_to_string_byte == 66) { | |
| byte_to_string_output = "B" | |
| } else if (byte_to_string_byte == 67) { | |
| byte_to_string_output = "C" | |
| } else if (byte_to_string_byte == 68) { | |
| byte_to_string_output = "D" | |
| } else if (byte_to_string_byte == 69) { | |
| byte_to_string_output = "E" | |
| } else if (byte_to_string_byte == 70) { | |
| byte_to_string_output = "F" | |
| } | |
| } | |
| mcfunction bc:parser/byte_to_string/part_3 { | |
| if (byte_to_string_byte == 71) { | |
| byte_to_string_output = "G" | |
| } else if (byte_to_string_byte == 72) { | |
| byte_to_string_output = "H" | |
| } else if (byte_to_string_byte == 73) { | |
| byte_to_string_output = "I" | |
| } else if (byte_to_string_byte == 74) { | |
| byte_to_string_output = "J" | |
| } else if (byte_to_string_byte == 75) { | |
| byte_to_string_output = "K" | |
| } else if (byte_to_string_byte == 76) { | |
| byte_to_string_output = "L" | |
| } else if (byte_to_string_byte == 77) { | |
| byte_to_string_output = "M" | |
| } else if (byte_to_string_byte == 78) { | |
| byte_to_string_output = "N" | |
| } else if (byte_to_string_byte == 79) { | |
| byte_to_string_output = "O" | |
| } else if (byte_to_string_byte == 80) { | |
| byte_to_string_output = "P" | |
| } else if (byte_to_string_byte == 81) { | |
| byte_to_string_output = "Q" | |
| } else if (byte_to_string_byte == 82) { | |
| byte_to_string_output = "R" | |
| } else if (byte_to_string_byte == 83) { | |
| byte_to_string_output = "S" | |
| } | |
| } | |
| mcfunction bc:parser/byte_to_string/part_4 { | |
| if (byte_to_string_byte == 84) { | |
| byte_to_string_output = "T" | |
| } else if (byte_to_string_byte == 85) { | |
| byte_to_string_output = "U" | |
| } else if (byte_to_string_byte == 86) { | |
| byte_to_string_output = "V" | |
| } else if (byte_to_string_byte == 87) { | |
| byte_to_string_output = "W" | |
| } else if (byte_to_string_byte == 88) { | |
| byte_to_string_output = "X" | |
| } else if (byte_to_string_byte == 89) { | |
| byte_to_string_output = "Y" | |
| } else if (byte_to_string_byte == 90) { | |
| byte_to_string_output = "Z" | |
| } else if (byte_to_string_byte == 91) { | |
| byte_to_string_output = "[" | |
| } else if (byte_to_string_byte == 92) { | |
| byte_to_string_output = "\\" | |
| } else if (byte_to_string_byte == 93) { | |
| byte_to_string_output = "]" | |
| } else if (byte_to_string_byte == 94) { | |
| byte_to_string_output = "^" | |
| } else if (byte_to_string_byte == 95) { | |
| byte_to_string_output = "_" | |
| } else if (byte_to_string_byte == 96) { | |
| byte_to_string_output = "`" | |
| } | |
| } | |
| mcfunction bc:parser/byte_to_string/part_5 { | |
| if (byte_to_string_byte == 97) { | |
| byte_to_string_output = "a" | |
| } else if (byte_to_string_byte == 98) { | |
| byte_to_string_output = "b" | |
| } else if (byte_to_string_byte == 99) { | |
| byte_to_string_output = "c" | |
| } else if (byte_to_string_byte == 100) { | |
| byte_to_string_output = "d" | |
| } else if (byte_to_string_byte == 101) { | |
| byte_to_string_output = "e" | |
| } else if (byte_to_string_byte == 102) { | |
| byte_to_string_output = "f" | |
| } else if (byte_to_string_byte == 103) { | |
| byte_to_string_output = "g" | |
| } else if (byte_to_string_byte == 104) { | |
| byte_to_string_output = "h" | |
| } else if (byte_to_string_byte == 105) { | |
| byte_to_string_output = "i" | |
| } else if (byte_to_string_byte == 106) { | |
| byte_to_string_output = "j" | |
| } else if (byte_to_string_byte == 107) { | |
| byte_to_string_output = "k" | |
| } else if (byte_to_string_byte == 108) { | |
| byte_to_string_output = "l" | |
| } else if (byte_to_string_byte == 109) { | |
| byte_to_string_output = "m" | |
| } | |
| } | |
| mcfunction bc:parser/byte_to_string/part_6 { | |
| if (byte_to_string_byte == 110) { | |
| byte_to_string_output = "n" | |
| } else if (byte_to_string_byte == 111) { | |
| byte_to_string_output = "o" | |
| } else if (byte_to_string_byte == 112) { | |
| byte_to_string_output = "p" | |
| } else if (byte_to_string_byte == 113) { | |
| byte_to_string_output = "q" | |
| } else if (byte_to_string_byte == 114) { | |
| byte_to_string_output = "r" | |
| } else if (byte_to_string_byte == 115) { | |
| byte_to_string_output = "s" | |
| } else if (byte_to_string_byte == 116) { | |
| byte_to_string_output = "t" | |
| } else if (byte_to_string_byte == 117) { | |
| byte_to_string_output = "u" | |
| } else if (byte_to_string_byte == 118) { | |
| byte_to_string_output = "v" | |
| } else if (byte_to_string_byte == 119) { | |
| byte_to_string_output = "w" | |
| } else if (byte_to_string_byte == 120) { | |
| byte_to_string_output = "x" | |
| } else if (byte_to_string_byte == 121) { | |
| byte_to_string_output = "y" | |
| } else if (byte_to_string_byte == 122) { | |
| byte_to_string_output = "z" | |
| } | |
| } | |
| mcfunction bc:parser/byte_to_string/part_7 { | |
| if (byte_to_string_byte == 123) { | |
| byte_to_string_output = "{" | |
| } else if (byte_to_string_byte == 124) { | |
| byte_to_string_output = "|" | |
| } else if (byte_to_string_byte == 125) { | |
| byte_to_string_output = "}" | |
| } else if (byte_to_string_byte == 126) { | |
| byte_to_string_output = "~" | |
| } | |
| } | |
| let bytes_to_string_bytes: value = storage bc:parser/bytes_to_string bytes | |
| let bytes_to_string_output: value = storage bc:parser/bytes_to_string output | |
| mcfunction bc:parser/bytes_to_string { | |
| bytes_to_string_output = "" | |
| for byte in bytes_to_string_bytes { | |
| byte_to_string_byte = byte | |
| function bc:parser/byte_to_string | |
| bytes_to_string_output = "$(bytes_to_string_output)$(byte_to_string_output)" | |
| } | |
| } | |
| // SCORE: resolve_cp_utf8 | |
| let resolve_cp_utf8_index: value = score index resolve_cp_utf8 | |
| let resolve_cp_utf8_output: value = storage bc:parser/resolve_cp_utf8 output | |
| mcfunction bc:parser/resolve_cp_utf8 { | |
| resolve_cp_utf8_output = "INVALID_UTF8_INDEX" | |
| let entry: data = constant_pool_raw[resolve_cp_utf8_index] | |
| if entry && entry.tag == tag_utf8 { | |
| bytes_to_string_bytes = entry.value | |
| function bc:parser/bytes_to_string | |
| resolve_cp_utf8_output = bytes_to_string_output | |
| } | |
| } | |
| // SCORE: resolve_class_name | |
| let resolve_class_name_index: value = score index resolve_class_name | |
| let resolve_class_name_output: value = storage bc:parser/resolve_class_name output | |
| mcfunction bc:parser/resolve_class_name { | |
| resolve_class_name_output = "INVALID_CLASS_INDEX" | |
| let entry: data = constant_pool_raw[resolve_class_name_index] | |
| if entry && entry.tag == tag_class { | |
| resolve_cp_utf8_index = entry.name_index | |
| function bc:parser/resolve_cp_utf8 | |
| resolve_class_name_output = resolve_cp_utf8_output | |
| } | |
| } | |
| let owner_struct_stack: value = storage bc:parser/parse_attributes owner_struct_stack | |
| let current_owner_struct: value = storage bc:parser/parse_attributes owner_struct_stack[-1] | |
| let attribute_stack: value = storage bc:parser/parse_attributes attribute_stack | |
| let current_attribute: value = storage bc:parser/parse_attributes attribute_stack[-1] | |
| let parse_attributes_is_class_attributes: score = 0 | |
| mcfunction bc:parser/parse_attributes { | |
| function bc:parser/parse_u2 | |
| let attributes_count: score = parser_parse_u2_output | |
| current_owner_struct.attributes_count = attributes_count | |
| let index: score = 0 | |
| while index < attributes_count { | |
| append attribute_stack {} | |
| let attribute: value = current_attribute | |
| function bc:parser/parse_u2 | |
| attribute.attribute_name_index = parser_parse_u2_output | |
| resolve_cp_utf8_index = parser_parse_u2_output | |
| function bc:parser/resolve_cp_utf8 | |
| attribute.name = resolve_cp_utf8_output | |
| if attribute.name == "INVALID_UTF8_INDEX" { | |
| tellraw @a "invalid" | |
| index = attributes_count | |
| } | |
| function bc:parser/parse_u4_part | |
| attribute.attribute_length.upper = parse_u4_part_output | |
| function bc:parser/parse_u4_part | |
| attribute.attribute_length.lower = parse_u4_part_output | |
| if attribute.name == "Code" { | |
| function bc:parser/parse_u2 | |
| attribute.max_stack = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| attribute.max_locals = parser_parse_u2_output | |
| function bc:parser/parse_u4_part | |
| let code_length_upper: score = parse_u4_part_output | |
| function bc:parser/parse_u4_part | |
| let code_length_lower: score = parse_u4_part_output | |
| parser_parse_bytes_length = code_length_lower | |
| function bc:parser/parse_bytes | |
| attribute.code = parser_parse_bytes_output | |
| function bc:parser/parse_u2 | |
| let exception_table_length: score = parser_parse_u2_output | |
| let exception_table: value = attribute.exception_table | |
| exception_table = [] | |
| if exception_table_length != 0 { | |
| tellraw @a {text: "TODO", color: "red"} | |
| } | |
| let index: score = 0 | |
| while index < exception_table_length { | |
| append exception_table {} | |
| let exception_table_entry: value = exception_table[-1] | |
| function bc:parser/parse_u2 | |
| exception_table_entry.start_pc = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| exception_table_entry.end_pc = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| exception_table_entry.handler_pc = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| exception_table_entry.catch_type = parser_parse_u2_output | |
| } | |
| append owner_struct_stack attribute | |
| function bc:parser/parse_attributes | |
| attribute = owner_struct_stack[-1] | |
| remove owner_struct_stack[-1] | |
| } else if attribute.name == "LineNumberTable" { | |
| function bc:parser/parse_u2 | |
| let line_number_table_length: score = parser_parse_u2_output | |
| let line_number_table: value = attribute.line_number_table | |
| line_number_table = [] | |
| let index: score = 0 | |
| while index < line_number_table_length { | |
| append line_number_table {} | |
| let line_number_table_entry: value = line_number_table[-1] | |
| function bc:parser/parse_u2 | |
| line_number_table_entry.start_pc = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| line_number_table_entry.line_number = parser_parse_u2_output | |
| index += 1 | |
| } | |
| } else if attribute.name == "SourceFile" && parse_attributes_is_class_attributes { | |
| function bc:parser/parse_u2 | |
| attribute.sourcefile_index = parser_parse_u2_output | |
| resolve_cp_utf8_index = parser_parse_u2_output | |
| function bc:parser/resolve_cp_utf8 | |
| attribute.sourcefile = resolve_cp_utf8_output | |
| } else { | |
| tellraw @a ["Unknown attribute ", attribute.name] | |
| } | |
| append current_owner_struct.attributes attribute | |
| remove attribute_stack[-1] | |
| index += 1 | |
| } | |
| parse_attributes_is_class_attributes = 0 | |
| } | |
| mcfunction bc:parser/parse_interfaces { | |
| function bc:parser/parse_u2 | |
| let interfaces_count: score = parser_parse_u2_output | |
| storage bc:parser/classfile classfile.interfaces_count = interfaces_count | |
| storage bc:parser/classfile classfile.interfaces_indices = [] | |
| let index: score = 0 | |
| while index < interfaces_count { | |
| function bc:parser/parse_u2 | |
| append storage bc:parser/classfile classfile.interfaces_indices parser_parse_u2_output | |
| index += 1 | |
| } | |
| if interfaces_count != 0 { | |
| tellraw @a {text: "TODO interfaces", color: "red"} | |
| } | |
| } | |
| mcfunction bc:parser/parse_fields { | |
| function bc:parser/parse_u2 | |
| let fields_count: score = parser_parse_u2_output | |
| storage bc:parser/classfile classfile.fields_count = fields_count | |
| let fields: value = storage bc:parser/classfile classfile.fields | |
| fields = [] | |
| let index: score = 0 | |
| while index < fields_count { | |
| let field: data = {} | |
| function bc:parser/parse_u2 | |
| field.access_flags = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| field.name_index = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| field.descriptor_index = parser_parse_u2_output | |
| resolve_cp_utf8_index = field.name_index | |
| function bc:parser/resolve_cp_utf8 | |
| field.name = resolve_cp_utf8_output | |
| resolve_cp_utf8_index = field.descriptor_index | |
| function bc:parser/resolve_cp_utf8 | |
| field.descriptor = resolve_cp_utf8_output | |
| append owner_struct_stack field | |
| function bc:parser/parse_attributes | |
| field = owner_struct_stack[-1] | |
| remove owner_struct_stack[-1] | |
| append fields field | |
| index += 1 | |
| } | |
| } | |
| mcfunction bc:parser/parse_methods { | |
| function bc:parser/parse_u2 | |
| let methods_count: score = parser_parse_u2_output | |
| storage bc:parser/classfile classfile.methods_count = methods_count | |
| let methods: value = storage bc:parser/classfile classfile.methods | |
| methods = [] | |
| let index: score = 0 | |
| while index < methods_count { | |
| let method: data = {} | |
| function bc:parser/parse_u2 | |
| method.access_flags = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| method.name_index = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| method.descriptor_index = parser_parse_u2_output | |
| resolve_cp_utf8_index = method.name_index | |
| function bc:parser/resolve_cp_utf8 | |
| method.name = resolve_cp_utf8_output | |
| resolve_cp_utf8_index = method.descriptor_index | |
| function bc:parser/resolve_cp_utf8 | |
| method.descriptor = resolve_cp_utf8_output | |
| append owner_struct_stack method | |
| function bc:parser/parse_attributes | |
| method = owner_struct_stack[-1] | |
| remove owner_struct_stack[-1] | |
| append methods method | |
| index += 1 | |
| } | |
| } | |
| let constant_pool: value = storage bc:parser/classfile classfile.constant_pool | |
| mcfunction bc:parser/resolve_constant_pool_for_interpreter { | |
| constant_pool = [{}] | |
| let index: score = 1 | |
| let len: score = constant_pool_raw | |
| while index < constant_pool_raw { | |
| let raw_entry: data = constant_pool_raw[index] | |
| if raw_entry { | |
| let tag: value = raw_entry.tag | |
| if tag == tag_utf8 { | |
| append `constant_pool` [tag_utf8, raw_entry.value] | |
| } else if tag == tag_integer { | |
| append `constant_pool` [tag_integer, raw_entry.value] | |
| } else if tag == tag_float { | |
| append `constant_pool` [tag_float, raw_entry.value] | |
| } else if tag == tag_long { | |
| append `constant_pool` [tag_long, raw_entry.value] | |
| } else if tag == tag_double { | |
| append `constant_pool` [tag_double, raw_entry.value] | |
| } else if tag == tag_class { | |
| append `constant_pool` [tag_class, raw_entry.name_index] | |
| } else if tag == tag_string { | |
| append `constant_pool` [tag_string, raw_entry.string_index] | |
| } else if tag == tag_fieldref || tag == tag_methodref || tag == tag_interface_methodref { | |
| append `constant_pool` [tag, raw_entry.class_index, raw_entry.name_and_type_index] | |
| } else if tag == tag_name_and_type { | |
| append `constant_pool` [tag_name_and_type, raw_entry.name_index, raw_entry.descriptor_index] | |
| } else { | |
| append `constant_pool` raw_entry | |
| } | |
| } else { | |
| append constant_pool {} | |
| } | |
| index += 1 | |
| } | |
| } | |
| mcfunction bc:parser/parse { | |
| classfile_index = 0 | |
| function bc:parser/parse_u4_part | |
| storage bc:parser/classfile classfile.magic.upper = parse_u4_part_output | |
| function bc:parser/parse_u4_part | |
| storage bc:parser/classfile classfile.magic.lower = parse_u4_part_output | |
| if storage bc:parser/classfile classfile.magic.upper != 51966 || storage bc:parser/classfile classfile.magic.lower != 47806 { | |
| tellraw @a {text: "Invalid classfile", color: "red"} | |
| return 1 | |
| } | |
| function bc:parser/parse_u2 | |
| storage bc:parser/classfile classfile.minor_version = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| storage bc:parser/classfile classfile.major_version = parser_parse_u2_output | |
| function bc:parser/constant_pool/parse | |
| function bc:parser/parse_u2 | |
| storage bc:parser/classfile classfile.access_flags = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| storage bc:parser/classfile classfile.this_class_index = parser_parse_u2_output | |
| function bc:parser/parse_u2 | |
| storage bc:parser/classfile classfile.super_class_index = parser_parse_u2_output | |
| function bc:parser/parse_interfaces | |
| function bc:parser/parse_fields | |
| function bc:parser/parse_methods | |
| append owner_struct_stack storage bc:parser/classfile classfile | |
| parse_attributes_is_class_attributes = 1 | |
| function bc:parser/parse_attributes | |
| storage bc:parser/classfile classfile = owner_struct_stack[-1] | |
| remove owner_struct_stack[-1] | |
| resolve_class_name_index = storage bc:parser/classfile classfile.this_class_index | |
| function bc:parser/resolve_class_name | |
| storage bc:parser/classfile classfile.this_class = resolve_class_name_output | |
| if storage bc:parser/classfile classfile.super_class_index != 0 { | |
| resolve_class_name_index = storage bc:parser/classfile classfile.super_class_index | |
| function bc:parser/resolve_class_name | |
| storage bc:parser/classfile classfile.super_class = resolve_class_name_output | |
| } else { | |
| storage bc:parser/classfile classfile.super_class = "java/lang/Object" | |
| } | |
| storage bc:parser/classfile classfile.name = storage bc:parser/classfile classfile.this_class | |
| function bc:parser/resolve_constant_pool_for_interpreter | |
| } | |
| // ---------------------------------------------------------------- | |
| let jvm_interpreter: value = storage bc:parser/interpreter interpreter | |
| let stack_frames: value = jvm_interpreter.stack_frames | |
| let frame: value = stack_frames[-1] | |
| let parsed_class_data: value = storage bc:parser/interpreter parsed_class_data | |
| // SCORE: interpreter_parse_u2 | |
| let interpreter_parse_u2_output: value = score output interpreter_parse_u2 | |
| mcfunction bc:interpreter/parse_u2 { | |
| if !frame.bytecode[frame.pc] { | |
| return 1 | |
| } | |
| let copied: data = frame.bytecode | |
| let first: score = (copied[frame.pc]) * 256 | |
| frame.pc += 1 | |
| if !copied[frame.pc] { | |
| return 1 | |
| } | |
| first += copied[frame.pc] | |
| frame.pc += 1 | |
| interpreter_parse_u2_output = first | |
| } | |
| // SCORE: interpreter_parse_i2 | |
| let interpreter_parse_i2_output: value = score output interpreter_parse_i2 | |
| mcfunction bc:interpreter/parse_i2 { | |
| if !frame.bytecode[frame.pc] { | |
| return 1 | |
| } | |
| let copied: data = frame.bytecode | |
| let first: score = (copied[frame.pc]) * 256 | |
| frame.pc += 1 | |
| if !copied[frame.pc] { | |
| return 1 | |
| } | |
| first += copied[frame.pc] | |
| frame.pc += 1 | |
| if first >= 0x8000 { | |
| first -= 0x10000 | |
| } | |
| interpreter_parse_i2_output = first | |
| } | |
| let load_class_data_class_data: value = storage bc:interpreter/load_class_data class_data | |
| mcfunction bc:interpreter/load_class_data { | |
| let class_name: value = load_class_data_class_data.name | |
| tellraw @a ["Loading class data for '", class_name, "'"] | |
| jvm_interpreter.loaded_classes."$(class_name)" = load_class_data_class_data | |
| } | |
| let class_files_to_load: value = storage bc:parser/interpreter class_files_to_load | |
| mcfunction bc:init { | |
| parsed_class_data = {} | |
| stack_frames = [] | |
| class_files_to_load = [ | |
| ["Main", [202, 254, 186, 190, 0, 0, 0, 69, 0, 28, 10, 0, 2, 0, 3, 7, 0, 4, 12, 0, 5, 0, 6, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 9, 0, 8, 0, 9, 7, 0, 10, 12, 0, 11, 0, 12, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 121, 115, 116, 101, 109, 1, 0, 3, 111, 117, 116, 1, 0, 21, 76, 106, 97, 118, 97, 47, 105, 111, 47, 80, 114, 105, 110, 116, 83, 116, 114, 101, 97, 109, 59, 10, 0, 14, 0, 15, 7, 0, 16, 12, 0, 17, 0, 18, 1, 0, 19, 106, 97, 118, 97, 47, 105, 111, 47, 80, 114, 105, 110, 116, 83, 116, 114, 101, 97, 109, 1, 0, 7, 112, 114, 105, 110, 116, 108, 110, 1, 0, 4, 40, 73, 41, 86, 7, 0, 20, 1, 0, 4, 77, 97, 105, 110, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 4, 109, 97, 105, 110, 1, 0, 22, 40, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86, 1, 0, 13, 83, 116, 97, 99, 107, 77, 97, 112, 84, 97, 98, 108, 101, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 9, 77, 97, 105, 110, 46, 106, 97, 118, 97, 0, 33, 0, 19, 0, 2, 0, 0, 0, 0, 0, 2, 0, 1, 0, 5, 0, 6, 0, 1, 0, 21, 0, 0, 0, 29, 0, 1, 0, 1, 0, 0, 0, 5, 42, 183, 0, 1, 177, 0, 0, 0, 1, 0, 22, 0, 0, 0, 6, 0, 1, 0, 0, 0, 1, 0, 9, 0, 23, 0, 24, 0, 1, 0, 21, 0, 0, 0, 105, 0, 2, 0, 4, 0, 0, 0, 36, 8, 60, 4, 61, 5, 62, 29, 27, 163, 0, 20, 178, 0, 7, 28, 182, 0, 13, 28, 29, 104, 61, 132, 3, 1, 167, 255, 237, 178, 0, 7, 28, 182, 0, 13, 177, 0, 0, 0, 2, 0, 22, 0, 0, 0, 34, 0, 8, 0, 0, 0, 3, 0, 2, 0, 5, 0, 4, 0, 7, 0, 11, 0, 8, 0, 18, 0, 10, 0, 22, 0, 7, 0, 28, 0, 13, 0, 35, 0, 14, 0, 25, 0, 0, 0, 11, 0, 2, 254, 0, 6, 1, 1, 1, 250, 0, 21, 0, 1, 0, 26, 0, 0, 0, 2, 0, 27]] | |
| ] | |
| } | |
| let run_method_by_name_class_name: value = storage bc:interpreter/run_method_by_name class_name | |
| let run_method_by_name_method_name: value = storage bc:interpreter/run_method_by_name method_name | |
| let run_method_by_name_descriptor: value = storage bc:interpreter/run_method_by_name descriptor | |
| let run_method_by_name_args: value = storage bc:interpreter/run_method_by_name args | |
| let new_stack_frame_method_info: value = storage bc:interpreter/new_stack_frame method_info | |
| let new_stack_frame_args: value = storage bc:interpreter/new_stack_frame args | |
| let new_stack_frame_class_file_data: value = storage bc:interpreter/new_stack_frame class_file_data | |
| mcfunction bc:interpreter/new_stack_frame { | |
| tellraw @a "Creating a new stack frame" | |
| append stack_frames {} | |
| let stack_frame: value = stack_frames[-1] | |
| stack_frame.method_info = new_stack_frame_method_info | |
| let code_attribute: data = {} | |
| reverse_for attribute in new_stack_frame_method_info.attributes { | |
| if attribute.name == "Code" { | |
| code_attribute = attribute | |
| } | |
| } | |
| if code_attribute == {} { | |
| tellraw @a "No code attribute" | |
| return fail | |
| } | |
| stack_frame.max_locals = code_attribute.max_locals | |
| stack_frame.max_stack = code_attribute.max_stack | |
| stack_frame.locals = [] | |
| let index: score = 0 | |
| while index < stack_frame.max_locals { | |
| append stack_frame.locals {} | |
| index += 1 | |
| } | |
| stack_frame.operand_stack = [] | |
| stack_frame.bytecode = code_attribute.code | |
| stack_frame.pc = 0 | |
| stack_frame.class_file_data = new_stack_frame_class_file_data | |
| let is_static: score = new_stack_frame_method_info.access_flags & 0x0008 | |
| let current_local_index: score = 0 | |
| let args_for_params: data = {} | |
| if is_static == 0 { | |
| if new_stack_frame_args { | |
| let args_copy: data = new_stack_frame_args | |
| stack_frame.locals[current_local_index] = args_copy[0] | |
| remove args_copy[0] | |
| current_local_index += 1 | |
| args_for_params = args_copy | |
| } else { | |
| args_for_params = [] | |
| } | |
| } else { | |
| args_for_params = new_stack_frame_args | |
| } | |
| for argument in args_for_params { | |
| stack_frame.locals[current_local_index] = argument | |
| current_local_index += 1 | |
| } | |
| } | |
| let current_class_data: value = stack_frames[-1].class_file_data | |
| // SCORE get_cp_entry | |
| let get_cp_entry_index: score = score index get_cp_entry | |
| let get_cp_entry_class_data: data = storage bc:interpreter/get_cp_entry class_data | |
| let get_cp_entry_output: data = storage bc:interpreter/get_cp_entry output | |
| mcfunction bc:interpreter/get_cp_entry { | |
| if get_cp_entry_class_data == {} { | |
| get_cp_entry_class_data = current_class_data | |
| } | |
| get_cp_entry_output = get_cp_entry_class_data.constant_pool[get_cp_entry_index] | |
| get_cp_entry_class_data = {} | |
| } | |
| let get_utf8_from_cp_index: score = score index get_utf8_from_cp | |
| let get_utf8_from_cp_class_data: data = storage bc:interpreter/get_utf8_from_cp class_data | |
| let get_utf8_from_cp_output: data = storage bc:interpreter/get_utf8_from_cp output | |
| mcfunction bc:interpreter/get_utf8_from_cp { | |
| get_cp_entry_index = get_utf8_from_cp_index | |
| get_cp_entry_class_data = get_utf8_from_cp_class_data | |
| function bc:interpreter/get_cp_entry | |
| let tag: score = get_cp_entry_output[0] | |
| let value: data = get_cp_entry_output[1] | |
| if tag != tag_utf8 { | |
| tellraw @a {text: "Expected utf8", color: "red"} | |
| } | |
| bytes_to_string_bytes = value | |
| function bc:parser/bytes_to_string | |
| get_utf8_from_cp_output = bytes_to_string_output | |
| } | |
| // SCORE: parse_descriptor_for_arg_count | |
| let parse_descriptor_for_arg_count_descriptor: value = storage bc:parse_descriptor_for_arg_count descriptor | |
| let parse_descriptor_for_arg_count_output: value = score output parse_descriptor_for_arg_count | |
| mcfunction bc:interpreter/parse_descriptor_for_arg_count { | |
| parse_descriptor_for_arg_count_output = 0 | |
| let in_args: score = 0 | |
| let type_parsing_state: score = 0 | |
| let early_return: score = 0 | |
| string_for char in parse_descriptor_for_arg_count_descriptor { | |
| if !early_return { | |
| if char == "(" { | |
| in_args = 1 | |
| } else if char == ")" { | |
| early_return = 1 | |
| } else if in_args { | |
| if type_parsing_state == 0 { | |
| parse_descriptor_for_arg_count_output += 1 | |
| if char == "L" { | |
| type_parsing_state = 1 | |
| } else if char == "[" { | |
| type_parsing_state = 2 | |
| } | |
| } else if type_parsing_state == 1 && char == ";" { | |
| type_parsing_state = 0 | |
| } else if type_parsing_state == 2 { | |
| if char != "[" && char != "L" { | |
| type_parsing_state = 0 | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| mcfunction bc:interpreter/execute { | |
| tellraw @a "Executing..." | |
| tellraw @a "" | |
| let index: score = 1 | |
| let early_return: score = 0 | |
| while !early_return && stack_frames[-1] { | |
| let stack_frames_len: score = stack_frames | |
| let bytecode_len: score = frame.bytecode | |
| if frame.pc >= bytecode_len { | |
| if stack_frames_len > 1 { | |
| remove stack_frames[-1] | |
| } else { | |
| early_return = 1 | |
| } | |
| } else { | |
| let opcode: score = frame.bytecode[frame.pc] | |
| let old_pc: score = frame.pc | |
| frame.pc += 1 | |
| if opcode == 0xB2 { | |
| tellraw @a[tag=opcode] "getstatic" | |
| function bc:interpreter/parse_u2 | |
| let field_ref_index: score = interpreter_parse_u2_output | |
| get_cp_entry_index = field_ref_index | |
| get_cp_entry_class_data = frame.class_file_data | |
| function bc:interpreter/get_cp_entry | |
| let field_ref_cp_type: score = get_cp_entry_output[0] | |
| let field_entry_index: score = get_cp_entry_output[1] | |
| let name_and_type_index: score = get_cp_entry_output[2] | |
| get_cp_entry_index = field_entry_index | |
| get_cp_entry_class_data = frame.class_file_data | |
| function bc:interpreter/get_cp_entry | |
| let class_tag: score = get_cp_entry_output[0] | |
| let field_entry_class_index: score = get_cp_entry_output[1] | |
| get_utf8_from_cp_index = field_entry_class_index | |
| get_utf8_from_cp_class_data = frame.class_file_data | |
| function bc:interpreter/get_utf8_from_cp | |
| let target_class_name_for_field: data = get_utf8_from_cp_output | |
| get_utf8_from_cp_index = field_entry_class_index | |
| get_utf8_from_cp_class_data = frame.class_file_data | |
| function bc:interpreter/get_utf8_from_cp | |
| let target_class_name: data = get_utf8_from_cp_output | |
| get_cp_entry_index = name_and_type_index | |
| get_cp_entry_class_data = frame.class_file_data | |
| function bc:interpreter/get_cp_entry | |
| let name_and_type_tag: score = get_cp_entry_output[0] | |
| let name_index: score = get_cp_entry_output[1] | |
| let descriptor_index: score = get_cp_entry_output[2] | |
| get_utf8_from_cp_index = name_index | |
| get_utf8_from_cp_class_data = frame.class_file_data | |
| function bc:interpreter/get_utf8_from_cp | |
| let field_name: data = get_utf8_from_cp_output | |
| get_utf8_from_cp_index = descriptor_index | |
| get_utf8_from_cp_class_data = frame.class_file_data | |
| function bc:interpreter/get_utf8_from_cp | |
| let field_descriptor: data = get_utf8_from_cp_output | |
| let target_class_data: value = jvm_interpreter.loaded_classes."$(target_class_name_for_field)" | |
| if !target_class_data { | |
| tellraw @a {text: "Class for getstatic not found.", color: "red"} | |
| } | |
| if target_class_name == "java/lang/System" && field_name == "out" { | |
| if !jvm_interpreter.object_heap.SYSTEM_OUT_STREAM { | |
| jvm_interpreter.object_heap.SYSTEM_OUT_STREAM = { | |
| type: "java/io/PrintStream", | |
| "_class_data": {} | |
| } | |
| } | |
| append frame.operand_stack { | |
| type: "reference", | |
| id: "SYSTEM_OUT_STREAM" | |
| } | |
| } else if field_name == "Companion" { | |
| tellraw @a {text: "TODO companion", color: "yellow"} | |
| } else { | |
| if !target_class_data.static_fields { | |
| target_class_data.static_fields = [] | |
| } | |
| let static_fields: value = target_class_data.static_fields | |
| if static_fields."$(field_name)" { | |
| append frame.operand_stack static_fields."$(field_name)" | |
| } else { | |
| tellraw @a {text: "Static field not found", color: "red"} | |
| } | |
| } | |
| } else if opcode == 0x12 { | |
| tellraw @a[tag=opcode] "ldc" | |
| let constant_index: score = frame.bytecode[frame.pc] | |
| frame.pc += 1 | |
| get_cp_entry_index = constant_index | |
| get_cp_entry_class_data = frame.class_file_data | |
| function bc:interpreter/get_cp_entry | |
| let cp_entry_type: data = get_cp_entry_output[0] | |
| let cp_val_or_idx: data = get_cp_entry_output[1] | |
| if cp_entry_type == tag_string { | |
| get_utf8_from_cp_index = cp_val_or_idx | |
| get_utf8_from_cp_class_data = frame.class_file_data | |
| function bc:interpreter/get_utf8_from_cp | |
| append frame.operand_stack get_utf8_from_cp_output | |
| } else if cp_entry_type == tag_integer { | |
| append frame.operand_stack cp_val_or_idx | |
| } else if cp_entry_type == tag_float { | |
| append frame.operand_stack cp_val_or_idx | |
| } else { | |
| tellraw @a cp_entry_type | |
| tellraw @a {text: "ldc for cp type {} not implemented", color: "red"} | |
| } | |
| index += 1 | |
| } else if opcode == 0xB6 { | |
| tellraw @a[tag=opcode] "invokevirtual" | |
| function bc:interpreter/parse_u2 | |
| let method_ref_index: score = interpreter_parse_u2_output | |
| get_cp_entry_index = method_ref_index | |
| get_cp_entry_class_data = frame.class_file_data | |
| function bc:interpreter/get_cp_entry | |
| let method_tag: score = get_cp_entry_output[0] | |
| let class_idx_on_ref: score = get_cp_entry_output[1] | |
| let name_and_type_index: score = get_cp_entry_output[2] | |
| get_cp_entry_index = name_and_type_index | |
| get_cp_entry_class_data = frame.class_file_data | |
| function bc:interpreter/get_cp_entry | |
| let name_and_type_tag: score = get_cp_entry_output[0] | |
| let name_index: score = get_cp_entry_output[1] | |
| let descriptor_index: score = get_cp_entry_output[2] | |
| get_utf8_from_cp_index = name_index | |
| get_utf8_from_cp_class_data = frame.class_file_data | |
| function bc:interpreter/get_utf8_from_cp | |
| let method_name: data = get_utf8_from_cp_output | |
| get_utf8_from_cp_index = descriptor_index | |
| get_utf8_from_cp_class_data = frame.class_file_data | |
| function bc:interpreter/get_utf8_from_cp | |
| let method_descriptor: data = get_utf8_from_cp_output | |
| parse_descriptor_for_arg_count_descriptor = method_descriptor | |
| function bc:interpreter/parse_descriptor_for_arg_count | |
| let num_args: score = parse_descriptor_for_arg_count_output | |
| let old_args_for_method_params: data = [] | |
| let index: score = 0 | |
| while index < num_args { | |
| append old_args_for_method_params frame.operand_stack[-1] | |
| remove frame.operand_stack[-1] | |
| index += 1 | |
| } | |
| let args_for_method_params: data = [] | |
| index = 0 | |
| while index < num_args { | |
| append args_for_method_params old_args_for_method_params[0] | |
| remove old_args_for_method_params[0] | |
| index += 1 | |
| } | |
| if !frame.operand_stack[-1] { | |
| tellraw @a {text: "Attempt to call {} on null object", color: "red"} | |
| } | |
| let obj_ref_this: data = frame.operand_stack[-1] | |
| remove frame.operand_stack[-1] | |
| let obj_data: data = jvm_interpreter.object_heap."$(obj_ref_this.id)" | |
| let actual_obj_type_name: value = obj_data.type | |
| // TODO create insert statement | |
| let all_args_for_call: data = [] | |
| append all_args_for_call obj_ref_this | |
| for argument in args_for_method_params { | |
| append all_args_for_call argument | |
| } | |
| if actual_obj_type_name == "java/lang/StringBuilder" { | |
| tellraw @a ["StringBuilder.", method_name, " not implemented"] | |
| } else if actual_obj_type_name == "java/io/PrintStream" { | |
| if method_name == "println" { | |
| tellraw @a ["stdout: ", args_for_method_params[0]] | |
| } else { | |
| tellraw @a ["PrintStream.", method_name, " not implemented"] | |
| } | |
| } else { | |
| // TODO dynamic dispatch? | |
| } | |
| } else if opcode == 0xB1 { | |
| tellraw @a[tag=opcode] "return (void)" | |
| remove stack_frames[-1] | |
| let len: score = stack_frames | |
| if len == 0 { | |
| early_return = 1 | |
| } | |
| } else if opcode >= 0x02 && opcode <= 0x08 { | |
| tellraw @a[tag=opcode] "iconst_m1 -> iconst_5" | |
| let value: score = opcode - 0x03 | |
| if opcode == 0x02 { | |
| value -= 1 | |
| } | |
| append frame.operand_stack value | |
| } else if opcode == 0x3C { | |
| tellraw @a[tag=opcode] "istore_1" | |
| frame.locals[1] = frame.operand_stack[-1] | |
| remove frame.operand_stack[-1] | |
| } else if opcode == 0x3D { | |
| tellraw @a[tag=opcode] "istore_2" | |
| frame.locals[2] = frame.operand_stack[-1] | |
| remove frame.operand_stack[-1] | |
| } else if opcode == 0x1B { | |
| tellraw @a[tag=opcode] "iload_1" | |
| append frame.operand_stack frame.locals[1] | |
| } else if opcode == 0x1C { | |
| tellraw @a[tag=opcode] "iload_2" | |
| append frame.operand_stack frame.locals[2] | |
| } else if opcode == 0x60 { | |
| tellraw @a[tag=opcode] "iadd" | |
| let len: score = frame.operand_stack | |
| if len < 2 { | |
| tellraw @a {text: "Stack underflow for iadd", color: "red"} | |
| } else { | |
| let value2: score = frame.operand_stack[-1] | |
| remove frame.operand_stack[-1] | |
| let value1: score = frame.operand_stack[-1] | |
| remove frame.operand_stack[-1] | |
| append frame.operand_stack value1 + value2 | |
| } | |
| } else if opcode == 0x3E { | |
| tellraw @a[tag=opcode] "istore_3" | |
| frame.locals[3] = frame.operand_stack[-1] | |
| remove frame.operand_stack[-1] | |
| } else if opcode == 0x1D { | |
| tellraw @a[tag=opcode] "iload_3" | |
| append frame.operand_stack frame.locals[3] | |
| } else if opcode == 0xA3 { | |
| tellraw @a[tag=opcode] "if_icmpgt" | |
| function bc:interpreter/parse_u2 | |
| let offset: score = interpreter_parse_u2_output | |
| let value2: score = frame.operand_stack[-1] | |
| remove frame.operand_stack[-1] | |
| let value1: score = frame.operand_stack[-1] | |
| remove frame.operand_stack[-1] | |
| if value1 > value2 { | |
| frame.pc = old_pc + offset | |
| } | |
| } else if opcode == 0x68 { | |
| tellraw @a[tag=opcode] "imul" | |
| let value2: score = frame.operand_stack[-1] | |
| remove frame.operand_stack[-1] | |
| let value1: score = frame.operand_stack[-1] | |
| remove frame.operand_stack[-1] | |
| append frame.operand_stack value1 * value2 | |
| } else if opcode == 0x84 { | |
| tellraw @a[tag=opcode] "iinc" | |
| let index: score = frame.bytecode[frame.pc] | |
| frame.pc += 1 | |
| let const_val_byte: score = frame.bytecode[frame.pc] | |
| frame.pc += 1 | |
| frame.locals[index] += const_val_byte | |
| } else if opcode == 0x01 { | |
| tellraw @a[tag=opcode] "aconst_null" | |
| append frame.operand_stack {} | |
| } else if opcode == 0xA7 { | |
| tellraw @a[tag=opcode] "goto" | |
| function bc:interpreter/parse_i2 | |
| frame.pc = old_pc + interpreter_parse_i2_output | |
| } else { | |
| tellraw @a ["Unknown opcode ", opcode] | |
| early_return = 1 | |
| } | |
| } | |
| } | |
| } | |
| mcfunction bc:interpreter/run_method_by_name { | |
| if !jvm_interpreter.loaded_classes."$(run_method_by_name_class_name)" { | |
| tellraw @a "Not loaded" | |
| return fail | |
| } | |
| let class_data: value = jvm_interpreter.loaded_classes."$(run_method_by_name_class_name)" | |
| let method_info: data = {} | |
| for method in class_data.methods { | |
| if method.name == run_method_by_name_method_name && method.descriptor == run_method_by_name_descriptor { | |
| method_info = method | |
| } | |
| } | |
| if !method_info { | |
| tellraw @a "Method not found" | |
| return fail | |
| } | |
| tellraw @a "Found method" | |
| if method_info.access_flags & 0x0100 { | |
| tellraw @a "Native" | |
| } else { | |
| new_stack_frame_method_info = method_info | |
| new_stack_frame_args = run_method_by_name_args | |
| new_stack_frame_class_file_data = class_data | |
| function bc:interpreter/new_stack_frame | |
| function bc:interpreter/execute | |
| } | |
| } | |
| mcfunction bc:main { | |
| function bc:init | |
| for class_file_to_load in class_files_to_load { | |
| let name: value = class_file_to_load[0] | |
| let raw_data: value = class_file_to_load[1] | |
| classfile_raw = raw_data | |
| function bc:parser/parse | |
| let class_data: value = storage bc:parser/classfile classfile | |
| load_class_data_class_data = class_data | |
| function bc:interpreter/load_class_data | |
| parsed_class_data."$(name)" = class_data | |
| } | |
| let object_stub_class_data: data = { | |
| "name": "java/lang/Object", | |
| "methods": [ | |
| { | |
| "name": "getClass", | |
| "descriptor": "()Ljava/lang/Class;", | |
| "access_flags": 0x0101, | |
| "attributes": [] | |
| }, | |
| { | |
| "name": "<init>", | |
| "descriptor": "()V", | |
| "access_flags": 0x0001, | |
| "attributes": [ | |
| {"name": "Code", "max_stack": 0, "max_locals": 1, "code": [177]} | |
| ] | |
| } | |
| ], | |
| "constant_pool": [{}], | |
| "super_class": "", | |
| "fields": [], | |
| "access_flags": 0x0001 | |
| } | |
| load_class_data_class_data = object_stub_class_data | |
| function bc:interpreter/load_class_data | |
| let system_stub_class_data: data = { | |
| "name": "java/lang/System", | |
| "methods": [], | |
| "fields": [ | |
| { | |
| "name": "out", | |
| "descriptor": "Ljava/io/PrintStream;", | |
| "access_flags": 0x0019 | |
| } | |
| ], | |
| "constant_pool": [{}], | |
| "super_class": "java/lang/Object", | |
| "access_flags": 0x0001 | |
| } | |
| load_class_data_class_data = system_stub_class_data | |
| function bc:interpreter/load_class_data | |
| let print_stream_stub_class_data: data = { | |
| "name": "java/io/PrintStream", | |
| "methods": [ | |
| { | |
| "name": "println", | |
| "descriptor": "(Ljava/lang/String;)V", | |
| "access_flags": 0x0001, | |
| "attributes": [] | |
| }, | |
| { | |
| "name": "println", | |
| "descriptor": "(I)V", | |
| "access_flags": 0x0001, | |
| "attributes": [] | |
| }, | |
| { | |
| "name": "println", | |
| "descriptor": "(Ljava/lang/Object;)V", | |
| "access_flags": 0x0001, | |
| "attributes": [] | |
| } | |
| ], | |
| "fields": [], | |
| "constant_pool": [{}], | |
| "super_class": "java/lang/Object", | |
| "access_flags": 0x0001 | |
| } | |
| load_class_data_class_data = print_stream_stub_class_data | |
| function bc:interpreter/load_class_data | |
| let main_class_data: value = parsed_class_data.Main | |
| let main_class_actual_name: value = main_class_data.name | |
| tellraw @a ["Locating Main method in class ", main_class_actual_name] | |
| let main_method_name_to_run: value = "main" | |
| let main_method_descriptor_to_run: value = "([Ljava/lang/String;)V" | |
| let main_method_args_to_run: value = [ | |
| {"type": "array", "element_type": "Ljava/lang/String;", "value": []} | |
| ] | |
| let found: score = 0 | |
| if main_class_data.methods { | |
| for method in main_class_data.methods { | |
| if method.name == main_method_name_to_run && method.descriptor == main_method_descriptor_to_run { | |
| found = 1 | |
| } | |
| } | |
| } | |
| if !found { | |
| tellraw @a "Not found" | |
| } | |
| run_method_by_name_class_name = main_class_actual_name | |
| run_method_by_name_method_name = main_method_name_to_run | |
| run_method_by_name_descriptor = main_method_descriptor_to_run | |
| run_method_by_name_args = main_method_args_to_run | |
| function bc:interpreter/run_method_by_name | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment