diff --git a/include/Ark/Compiler/BytecodeReader.hpp b/include/Ark/Compiler/BytecodeReader.hpp index ea9a43d0f..7bd76b368 100644 --- a/include/Ark/Compiler/BytecodeReader.hpp +++ b/include/Ark/Compiler/BytecodeReader.hpp @@ -160,6 +160,15 @@ namespace Ark */ [[nodiscard]] Code code(const InstLocations& instLocations) const; + /** + * @brief Find the location of an instruction + * @param inst_locations + * @param ip + * @param pp + * @return + */ + std::optional findSourceLocation(const std::vector& inst_locations, std::size_t ip, std::size_t pp) const; + /** * @brief Display the bytecode opcode in a human friendly way. * diff --git a/include/Ark/Compiler/IntermediateRepresentation/InstLoc.hpp b/include/Ark/Compiler/IntermediateRepresentation/InstLoc.hpp index 801f6a463..de99528d6 100644 --- a/include/Ark/Compiler/IntermediateRepresentation/InstLoc.hpp +++ b/include/Ark/Compiler/IntermediateRepresentation/InstLoc.hpp @@ -12,6 +12,8 @@ namespace Ark::internal uint16_t inst_pointer; uint16_t filename_id; uint32_t line; + + std::strong_ordering operator<=>(const InstLoc&) const = default; }; } diff --git a/src/arkreactor/Compiler/BytecodeReader.cpp b/src/arkreactor/Compiler/BytecodeReader.cpp index 9b15cbf8b..809c5543e 100644 --- a/src/arkreactor/Compiler/BytecodeReader.cpp +++ b/src/arkreactor/Compiler/BytecodeReader.cpp @@ -271,6 +271,29 @@ namespace Ark return block; } + std::optional BytecodeReader::findSourceLocation(const std::vector& inst_locations, const std::size_t ip, const std::size_t pp) const + { + std::optional match = std::nullopt; + + for (const auto location : inst_locations) + { + if (location.page_pointer == pp && !match) + match = location; + + // select the best match: we want to find the location that's nearest our instruction pointer, + // but not equal to it as the IP will always be pointing to the next instruction, + // not yet executed. Thus, the erroneous instruction is the previous one. + if (location.page_pointer == pp && match && location.inst_pointer < ip / 4) + match = location; + + // early exit because we won't find anything better, as inst locations are ordered by ascending (pp, ip) + if (location.page_pointer > pp || (location.page_pointer == pp && location.inst_pointer >= ip / 4)) + break; + } + + return match; + } + void BytecodeReader::display(const BytecodeSegment segment, const std::optional sStart, const std::optional sEnd, @@ -638,13 +661,27 @@ namespace Ark return; } + std::optional previous_loc = std::nullopt; + for (std::size_t j = sStart.value_or(0), end = sEnd.value_or(page.size()); j < end; j += 4) { const uint8_t inst = page[j]; - // TEMP const uint8_t padding = page[j + 1]; const auto arg = static_cast((page[j + 2] << 8) + page[j + 3]); + auto maybe_loc = findSourceLocation(inst_locs.locations, j, pp); + + // location + // we want to print it only when it changed, either the file, the line, or both + if (maybe_loc && (!previous_loc || maybe_loc != previous_loc)) + { + if (!previous_loc || previous_loc->filename_id != maybe_loc->filename_id) + fmt::println("{}", files.filenames[maybe_loc->filename_id]); + fmt::print("{:>4}", maybe_loc->line + 1); + previous_loc = maybe_loc; + } + else + fmt::print(" "); // instruction number fmt::print(fmt::fg(fmt::color::cyan), "{:>4}", j / 4); // padding inst arg arg