improve debugging

This commit is contained in:
nora 2022-04-15 23:33:12 +02:00
parent c3c24c73fe
commit 7973d9f77b
8 changed files with 189 additions and 32 deletions

View file

@ -21,6 +21,7 @@ use crate::opts::{Ir, Stmt as IrStmt, StmtKind};
use crate::parse::Span;
use crate::BumpVec;
use bumpalo::Bump;
use std::fmt::{Debug, Formatter};
#[derive(Debug, Clone, Copy)]
pub enum Stmt {
@ -39,12 +40,18 @@ pub enum Stmt {
const _: [(); 8] = [(); std::mem::size_of::<Stmt>()];
#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct Code<'c> {
stmts: BumpVec<'c, Stmt>,
debug: BumpVec<'c, Span>,
}
impl Debug for Code<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.stmts.fmt(f)
}
}
impl Code<'_> {
pub fn stmts(&self) -> &[Stmt] {
&self.stmts

View file

@ -7,12 +7,43 @@ use bumpalo::Bump;
use owo_colors::OwoColorize;
use std::fmt::Display;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::str::FromStr;
pub mod codegen;
pub mod codegen_interpreter;
pub mod opts;
pub mod parse;
#[derive(clap::Parser, Default)]
#[clap(author, about)]
pub struct Args {
#[clap(short, long)]
pub profile: bool,
#[clap(long)]
pub dump: Option<DumpKind>,
pub file: PathBuf,
}
pub enum DumpKind {
Ast,
Ir,
Code,
}
impl FromStr for DumpKind {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"ast" => Ok(Self::Ast),
"ir" => Ok(Self::Ir),
"code" => Ok(Self::Code),
other => Err(format!("Invalid IR level: '{other}'")),
}
}
}
type BumpVec<'a, T> = Vec<T, &'a Bump>;
pub enum UseProfile {
@ -20,7 +51,7 @@ pub enum UseProfile {
No,
}
pub fn run<R, W>(src: &str, stdout: W, stdin: R, use_profile: UseProfile) -> Result<(), ParseError>
pub fn run<R, W>(src: &str, stdout: W, stdin: R, config: &Args) -> Result<(), ParseError>
where
W: Write,
R: Read,
@ -29,10 +60,20 @@ where
let parsed = parse::parse(&ast_alloc, src.bytes().enumerate())?;
if let Some(DumpKind::Ast) = config.dump {
println!("{parsed:#?}");
return Ok(());
}
let ir_alloc = Bump::new();
let optimized_ir = opts::optimize(&ir_alloc, &parsed);
if let Some(DumpKind::Ir) = config.dump {
println!("{optimized_ir:#?}");
return Ok(());
}
drop(parsed);
drop(ast_alloc);
@ -40,11 +81,16 @@ where
let code = codegen::generate(&cg_alloc, &optimized_ir);
if let Some(DumpKind::Code) = config.dump {
println!("{code:#?}");
return Ok(());
}
drop(optimized_ir);
drop(ir_alloc);
match use_profile {
UseProfile::Yes => {
match config.profile {
true => {
let mut code_profile_count = vec![0; code.debug().len()];
codegen_interpreter::run(&code, stdout, stdin, |ip| unsafe {
@ -65,7 +111,7 @@ where
print!("{}", color_by_profile(char as char, value, max));
}
}
UseProfile::No => {
false => {
codegen_interpreter::run(&code, stdout, stdin, |_| {});
}
}
@ -90,7 +136,7 @@ fn color_by_profile(char: char, value: u64, max: u64) -> impl Display {
#[cfg(test)]
mod tests {
use crate::UseProfile;
use crate::Args;
#[test]
fn fizzbuzz() {
@ -98,7 +144,7 @@ mod tests {
let mut stdout = Vec::new();
let stdin = [];
super::run(str, &mut stdout, stdin.as_slice(), UseProfile::No).unwrap();
super::run(str, &mut stdout, stdin.as_slice(), &Args::default()).unwrap();
insta::assert_debug_snapshot!(String::from_utf8(stdout));
}

View file

@ -1,31 +1,24 @@
#![feature(allocator_api, let_else)]
#![warn(rust_2018_idioms)]
use brainfuck::UseProfile;
use std::{env, fs, io, process};
use brainfuck::Args;
use clap::Parser;
use std::{fs, io, process};
fn main() {
let Some(path) = env::args().nth(1) else {
eprintln!("error: Provide a path as input.");
process::exit(1);
};
let file = fs::read_to_string(path).unwrap_or_else(|err| {
eprintln!("error: Failed to read file: {err}");
process::exit(1);
});
let stdout = io::stdout();
let stdout = stdout.lock();
let stdin = io::stdin();
let stdin = stdin.lock();
let profile = env::args()
.any(|a| a == "--profile")
.then(|| UseProfile::Yes)
.unwrap_or(UseProfile::No);
let args = Args::parse();
brainfuck::run(&file, stdout, stdin, profile).unwrap_or_else(|_| {
let src = fs::read_to_string(&args.file).unwrap_or_else(|err| {
eprintln!("error: Failed to read file: {err}");
process::exit(1);
});
brainfuck::run(&src, stdout, stdin, &args).unwrap_or_else(|_| {
eprintln!("error: Failed to parse brainfuck code");
process::exit(1);
});

View file

@ -1,13 +1,14 @@
use crate::parse::{Instr, Span};
use crate::BumpVec;
use bumpalo::Bump;
use std::fmt::{Debug, Formatter};
#[derive(Debug, Clone)]
pub struct Ir<'ir> {
pub stmts: BumpVec<'ir, Stmt<'ir>>,
}
#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct Stmt<'ir> {
pub kind: StmtKind<'ir>,
pub span: Span,
@ -23,6 +24,12 @@ impl<'ir> Stmt<'ir> {
}
}
impl Debug for Stmt<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Stmt").field(&self.kind).finish()
}
}
#[derive(Debug, Clone)]
pub enum StmtKind<'ir> {
Add(u8),

View file

@ -1,5 +1,6 @@
use bumpalo::Bump;
use std::cmp;
use std::fmt::Debug;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Span {