feat(tvix/eval): implement chunk disassembler output

This makes for a much nicer view of an execution if `--feature
disassembler` is set, for example:

  tvix-repl> let value = [ 1 2 { a = 1; } ]; in value ++ [ 1 ]
  === compiled bytecode (11 operations) ===
  02   OpConstant(1)
  02   OpConstant(2)
  02   OpConstant("a")
  02   OpConstant(1)
  02   OpAttrs(1)
  02   OpList(3)
  02   OpGetLocal(0)
  02   OpConstant(1)
  02   OpList(1)
  02   OpConcat
  02   OpCloseScope(1)
  === runtime trace ===
  0001 OpConstant(ConstantIdx(0))  [ 1 ]
  0002 OpConstant(ConstantIdx(1))  [ 1 2 ]
  0003 OpConstant(ConstantIdx(2))  [ 1 2 "a" ]
  0004 OpConstant(ConstantIdx(3))  [ 1 2 "a" 1 ]
  0005 OpAttrs(1)                  [ 1 2 { a = 1; } ]
  0006 OpList(3)                   [ [ 1 2 { a = 1; } ] ]
  0007 OpGetLocal(0)               [ [ 1 2 { a = 1; } ] [ 1 2 { a = 1; } ] ]
  0008 OpConstant(ConstantIdx(4))  [ [ 1 2 { a = 1; } ] [ 1 2 { a = 1; } ] 1 ]
  0009 OpList(1)                   [ [ 1 2 { a = 1; } ] [ 1 2 { a = 1; } ] [ 1 ] ]
  0010 OpConcat                    [ [ 1 2 { a = 1; } ] [ 1 2 { a = 1; } 1 ] ]
  0011 OpCloseScope(1)             [ [ 1 2 { a = 1; } 1 ] ]
  => [ 1 2 { a = 1; } 1 ] :: list

Change-Id: If79c7fd1f0f18255ddb3763c1ba585fda8041b1b
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6195
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
Vincent Ambo 2022-08-13 22:14:53 +03:00 committed by tazjin
parent 57d0dbb1c6
commit e041851581
3 changed files with 35 additions and 2 deletions

View file

@ -4,7 +4,7 @@ use crate::value::Value;
#[derive(Debug, Default)]
pub struct Chunk {
pub code: Vec<OpCode>,
constants: Vec<Value>,
pub constants: Vec<Value>,
}
impl Chunk {

View file

@ -4,6 +4,7 @@
use std::io::{Stderr, Write};
use tabwriter::TabWriter;
use crate::chunk::Chunk;
use crate::opcode::OpCode;
use crate::value::Value;
@ -35,3 +36,33 @@ impl Drop for Tracer {
self.0.flush().ok();
}
}
fn disassemble_op(tw: &mut TabWriter<Stderr>, chunk: &Chunk, offset: usize) {
let code_width = format!("{}", chunk.code.len()).len();
write!(tw, "{:0width$}\t ", width = code_width).ok();
match chunk.code[offset] {
OpCode::OpConstant(idx) => write!(tw, "OpConstant({})\n", chunk.constant(idx)).ok(),
op => write!(tw, "{:?}\n", op).ok(),
};
}
/// Disassemble a chunk of code, printing out the operations in a
/// reasonable, human-readable format.
pub fn disassemble_chunk(chunk: &Chunk) {
let mut tw = TabWriter::new(std::io::stderr());
write!(
&mut tw,
"=== compiled bytecode ({} operations) ===\n",
chunk.code.len()
)
.ok();
for (idx, _) in chunk.code.iter().enumerate() {
disassemble_op(&mut tw, chunk, idx);
}
tw.flush().ok();
}

View file

@ -17,7 +17,9 @@ pub fn interpret(code: &str, location: Option<PathBuf>) -> EvalResult<Value> {
}
let result = crate::compiler::compile(ast, location)?;
println!("code: {:?}", result.chunk);
#[cfg(feature = "disassembler")]
crate::disassembler::disassemble_chunk(&result.chunk);
for warning in result.warnings {
eprintln!(