debug printing the program now shows the original source code

This commit is contained in:
nora 2021-09-18 21:28:24 +02:00
parent dba4a2e2ec
commit 92b026ccba
3 changed files with 69 additions and 36 deletions

View file

@ -1,9 +1,11 @@
use crate::stmt::Stmt;
use crate::stmt::{Code, Stmt};
use std::io::Write;
#[derive(Debug, Clone)]
struct Vm {
struct Vm<'a> {
stmts: Vec<Stmt>,
span: Vec<usize>,
code_lines: Vec<&'a str>,
pc: usize,
registers: Vec<usize>,
breakpoints: Vec<usize>,
@ -17,7 +19,7 @@ enum VmState {
OutOfBounds,
}
impl Vm {
impl Vm<'_> {
fn step(&mut self) -> VmState {
let pc = self.pc;
self.pc += 1;
@ -57,10 +59,12 @@ enum VmInstruction {
Set(usize, usize),
}
pub fn run(stmts: Vec<Stmt>) {
let max_register_index = max_register(&stmts);
pub fn run(code: Code) {
let max_register_index = max_register(&code.stmts);
let mut vm = Vm {
stmts,
stmts: code.stmts,
span: code.span,
code_lines: code.code_lines,
pc: 0,
registers: vec![0; max_register_index + 1],
breakpoints: vec![],
@ -157,16 +161,19 @@ fn print_program(vm: &Vm) {
use std::cmp::min;
println!("Program:");
let lower = if vm.pc > 5 { vm.pc - 5 } else { 0 };
let lower_stmt = if vm.pc > 5 { vm.pc - 5 } else { 0 };
let len = vm.stmts.len();
let higher = if len < 5 { len } else { min(vm.pc + 5, len) };
let higher_stmt = if len < 5 { len } else { min(vm.pc + 5, len) };
for i in lower..higher {
let stmt = vm.stmts[i];
if i == vm.pc {
println!("> {} {}", i, stmt)
let lower_code = vm.span[lower_stmt];
let higher_code = vm.span[higher_stmt - 1];
for line_number in lower_code..higher_code {
let code_line = vm.code_lines[line_number];
if line_number == vm.span[vm.pc] {
println!("> {} {}", line_number, code_line)
} else {
println!("{} {}", i, stmt);
println!("{} {}", line_number, code_line);
}
}
}

View file

@ -11,6 +11,13 @@ pub enum Stmt {
Stop,
}
pub struct Code<'a> {
pub stmts: Vec<Stmt>,
/// Has the same length as `stmts`, points to line numbers where the instructions come from
pub span: Vec<usize>,
pub code_lines: Vec<&'a str>,
}
enum IrStmt<'a> {
Inc(usize),
Dec(usize),
@ -20,13 +27,15 @@ enum IrStmt<'a> {
Stop,
}
pub fn parse(text: &str) -> Result<Vec<Stmt>, String> {
pub fn parse(text: &str) -> Result<Code, String> {
let mut labels = HashMap::new();
let mut statements = Vec::new();
let mut statement_number = 0;
for (line_number, line) in text.lines().enumerate() {
let code_lines = text.lines().collect::<Vec<_>>();
for (line_number, line) in code_lines.iter().enumerate() {
if line.split_whitespace().next().is_none() {
continue;
}
@ -43,26 +52,43 @@ pub fn parse(text: &str) -> Result<Vec<Stmt>, String> {
}
}
statements
let result: Result<Vec<(Stmt, usize)>, String> = statements
.iter()
.map(|stmt| match stmt.0 {
IrStmt::Inc(r) => Ok(Stmt::Inc(r)),
IrStmt::Dec(r) => Ok(Stmt::Dec(r)),
IrStmt::IsZero(r, label) => Ok(Stmt::IsZero(
r,
match labels.get(label) {
Some(line) => *line,
None => return Err(format!("Label '{}' not found on line {}", label, stmt.1)),
},
.map(|(stmt, span)| match *stmt {
IrStmt::Inc(r) => Ok((Stmt::Inc(r), *span)),
IrStmt::Dec(r) => Ok((Stmt::Dec(r), *span)),
IrStmt::IsZero(r, label) => Ok((
Stmt::IsZero(
r,
match labels.get(label) {
Some(line) => *line,
None => {
return Err(format!("Label '{}' not found on line {}", label, span))
}
},
),
*span,
)),
IrStmt::Jump(label) => Ok(Stmt::Jump(match labels.get(label) {
Some(line) => *line,
None => return Err(format!("Label '{}' not found on line {}", label, stmt.1)),
})),
IrStmt::Stop => Ok(Stmt::Stop),
IrStmt::Jump(label) => Ok((
Stmt::Jump(match labels.get(label) {
Some(line) => *line,
None => return Err(format!("Label '{}' not found on line {}", label, span)),
}),
*span,
)),
IrStmt::Stop => Ok((Stmt::Stop, *span)),
IrStmt::Label(_) => unreachable!(),
})
.collect()
.collect();
result.map(|vec| {
let (stmts, span) = vec.iter().cloned().unzip();
Code {
stmts,
span,
code_lines,
}
})
}
fn parse_line(line: &str) -> Result<IrStmt, String> {