diff --git a/public/vm/bytecode-parser.js b/public/vm/bytecode-parser.js index 0abe875..1804c86 100644 --- a/public/vm/bytecode-parser.js +++ b/public/vm/bytecode-parser.js @@ -24,10 +24,33 @@ function getBytes(data) { } +function getLineNumbers(data) { + var string_data = data.toString(); + + // Strip all the comments for easier parsing + var without_comments = string_data.replace(new RegExp("#.*", "gi"), ""); + + // Each byte should now be a pair of two hex digits. + // Put all these in an array. + var lines = without_comments.split("\n"); + var line_numbers = []; + for (var line_number = 0; line_number < lines.length; line_number++ ) { + lines[line_number].replace( + new RegExp("([0123456789ABCDEF][0123456789ABCDEF])", "gi"), + function(next_byte) { + // +1 because lines start at 1, for some weird reason. + // Who doesn't start counting at 0? + line_numbers.push(line_number+1); + }); + } + return line_numbers; +} + var FunctionInfo = function (stream) { this.num_args = stream.get_u2(); this.num_vars = stream.get_u2(); this.code_length = stream.get_u2(); + this.code_byte_offset = stream.index; this.code = stream.get_bytes(this.code_length); } @@ -36,8 +59,9 @@ var NativeInfo = function (stream) { this.function_table_index = stream.get_u2(); } -var Bc0File = function (filename) { - var file = getBytes(filename); +var Bc0File = function (bytecode) { + var file = getBytes(bytecode); + this.line_numbers = getLineNumbers(bytecode); var stream = new byte_stream.ByteStream(file); var magic = stream.get_u4(); @@ -95,6 +119,12 @@ Bc0File.prototype.string_from_index = function (i) { return result; } +Bc0File.prototype.line_for_indices = function(function_index, byte_offset) { + var offset_in_file = this.function_pool[function_index].code_byte_offset + + byte_offset; + return this.line_numbers[offset_in_file]; +} + function parse(bytecode) { return new Bc0File(bytecode); } diff --git a/public/vm/c0vm.js b/public/vm/c0vm.js index 2e9ae9d..267df54 100755 --- a/public/vm/c0vm.js +++ b/public/vm/c0vm.js @@ -115,9 +115,10 @@ ProgramState.prototype.doIf = function(f) { } ProgramState.prototype.step = function() { + this.maintain_line_numbers(); var opcode = this.frame.program[this.frame.pc] log("0x" + this.frame.pc.toString(16) + " Running opcode " + - op.lookup_table[opcode]); + op.lookup_table[opcode] + " at line " + this.bytecode_line); switch (opcode) { // Stack manipulation case op.POP: @@ -473,6 +474,12 @@ ProgramState.prototype.step = function() { } } +ProgramState.prototype.maintain_line_numbers = function() { + this.bytecode_line = this.file.line_for_indices(this.frame.function_id, + this.frame.pc); + // this.c0_line = SOMEHOW GET THE LINE IN THE c0 FILE +} + ProgramState.prototype.remove_breakpoint = function(opcode_index) { if (opcode_index < 0){ console.log("Error: negative opcode_index" + opcode_index.toString()); @@ -514,14 +521,17 @@ ProgramState.prototype.run = function() { if (this.frame.function_id == breakpoint[0] && this.frame.pc == breakpoint[1] && - this.stoppedAt !== breakpoint) { + this.stopped_at !== breakpoint) { log("Breakpoint reached!"); - this.stoppedAt = breakpoint; + this.stopped_at = breakpoint; + + this.maintain_line_numbers(); + return this; } } - this.stoppedAt = undefined; + this.stopped_at = undefined; var val = this.step(); if (val !== undefined) return val; diff --git a/test/tests.js b/test/tests.js index abbcd2e..0cc7f39 100644 --- a/test/tests.js +++ b/test/tests.js @@ -121,7 +121,12 @@ exports.testBREAKPOINT1 = function(test) { test.ok(vm.frame.stack[0] == 23 && vm.frame.stack[1] == 19, "VM stack incorrect"); + + test.ok(vm.bytecode_line == 19, + "VM reports incorrect line in bytecode: " + vm.bytecode_line); + result = vm.run(); - test.ok(result == 1748, "VM did not resume operation correctly, gave result " + result); + test.ok(result == 1748, + "VM did not resume operation correctly, gave result " + result); test.done(); }