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:
parent
57d0dbb1c6
commit
e041851581
3 changed files with 35 additions and 2 deletions
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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!(
|
||||
|
|
Loading…
Reference in a new issue