rename a bunch of stuff

This commit is contained in:
nora 2022-04-16 20:13:15 +02:00
parent ddf2686049
commit 5fc5c49dff
10 changed files with 252 additions and 215 deletions

3
rust2/.rustfmt.toml Normal file
View file

@ -0,0 +1,3 @@
imports_granularity = "Crate"
newline_style = "Unix"
group_imports = "StdExternalCrate"

View file

@ -1,6 +1,7 @@
use std::io::{Read, Write};
use bumpalo::Bump; use bumpalo::Bump;
use criterion::{black_box, criterion_main, Criterion}; use criterion::{black_box, criterion_main, Criterion};
use std::io::{Read, Write};
struct MockReadWrite; struct MockReadWrite;
@ -24,9 +25,9 @@ impl Write for MockReadWrite {
fn run_bf(bf: &str) { fn run_bf(bf: &str) {
let bump = Bump::new(); let bump = Bump::new();
let ast = brainfuck::parse::parse(&bump, bf.bytes().enumerate()).unwrap(); let ast = brainfuck::parse::parse(&bump, bf.bytes().enumerate()).unwrap();
let ir = brainfuck::opts::optimize(&bump, &ast); let hir = brainfuck::hir::optimized_hir(&bump, &ast);
let code = brainfuck::codegen::generate(&bump, &ir); let lir = brainfuck::lir::generate(&bump, &hir);
brainfuck::codegen_interpreter::run(&code, MockReadWrite, MockReadWrite, |_| {}); brainfuck::lir::interpreter::run(&lir, MockReadWrite, MockReadWrite, |_| {});
} }
fn optimized(c: &mut Criterion) { fn optimized(c: &mut Criterion) {

89
rust2/src/hir/mod.rs Normal file
View file

@ -0,0 +1,89 @@
use std::fmt::{Debug, Formatter};
use bumpalo::Bump;
use crate::{
parse::{Ast, Instr, Span},
BumpVec,
};
pub mod opts;
#[derive(Clone)]
pub struct Hir<'hir> {
pub stmts: BumpVec<'hir, Stmt<'hir>>,
}
impl Debug for Hir<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.stmts.fmt(f)
}
}
#[derive(Clone)]
pub struct Stmt<'hir> {
pub kind: StmtKind<'hir>,
pub span: Span,
}
impl<'hir> Stmt<'hir> {
fn new(kind: StmtKind<'hir>, span: Span) -> Stmt<'hir> {
Self { kind, span }
}
fn kind(&self) -> &StmtKind<'hir> {
&self.kind
}
}
impl Debug for Stmt<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.kind.fmt(f)
}
}
#[derive(Debug, Clone)]
pub enum StmtKind<'hir> {
Add(i32, u8),
Sub(i32, u8),
/// Sets the current cell to 0 and adds that value of the cell to another cell at `offset`
MoveAddTo {
offset: i32,
},
Right(usize),
Left(usize),
Loop(Hir<'hir>),
Out,
In,
SetN(u8),
}
fn ast_to_ir<'hir>(alloc: &'hir Bump, ast: &Ast<'_>) -> Hir<'hir> {
let mut stmts = Vec::new_in(alloc);
let stmts_iter = ast.iter().map(|(instr, span)| {
let kind = match instr {
Instr::Add => StmtKind::Add(0, 1),
Instr::Sub => StmtKind::Sub(0, 1),
Instr::Right => StmtKind::Right(1),
Instr::Left => StmtKind::Left(1),
Instr::Out => StmtKind::Out,
Instr::In => StmtKind::In,
Instr::Loop(body) => {
let ir_body = ast_to_ir(alloc, body);
StmtKind::Loop(ir_body)
}
};
Stmt::new(kind, *span)
});
stmts.extend(stmts_iter);
Hir { stmts }
}
pub fn optimized_hir<'hir>(alloc: &'hir Bump, ast: &Ast<'_>) -> Hir<'hir> {
let mut hir = ast_to_ir(alloc, ast);
opts::optimize(alloc, &mut hir);
hir
}

View file

@ -1,110 +1,37 @@
use crate::parse::{Instr, Span};
use crate::BumpVec;
use bumpalo::Bump;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt::{Debug, Formatter};
use bumpalo::Bump;
use tracing::trace; use tracing::trace;
#[derive(Clone)] use crate::{
pub struct Ir<'ir> { hir::{Hir, Stmt, StmtKind},
pub stmts: BumpVec<'ir, Stmt<'ir>>, BumpVec,
} };
impl Debug for Ir<'_> { pub fn optimize<'hir>(alloc: &'hir Bump, hir: &mut Hir<'hir>) {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { pass_group(alloc, hir);
self.stmts.fmt(f) pass_find_set_null(hir);
} pass_set_n(hir);
} pass_cancel_left_right_add_sub(hir);
pass_add_sub_offset(hir);
#[derive(Clone)] pass_move_add_to(hir);
pub struct Stmt<'ir> {
pub kind: StmtKind<'ir>,
pub span: Span,
}
impl<'ir> Stmt<'ir> {
fn new(kind: StmtKind<'ir>, span: Span) -> Stmt<'ir> {
Self { kind, span }
}
fn kind(&self) -> &StmtKind<'ir> {
&self.kind
}
}
impl Debug for Stmt<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.kind.fmt(f)
}
}
#[derive(Debug, Clone)]
pub enum StmtKind<'ir> {
Add(i32, u8),
Sub(i32, u8),
/// Sets the current cell to 0 and adds that value of the cell to another cell at `offset`
MoveAddTo {
offset: i32,
},
Right(usize),
Left(usize),
Loop(Ir<'ir>),
Out,
In,
SetN(u8),
}
pub fn optimize<'ir>(alloc: &'ir Bump, instrs: &[(Instr<'_>, Span)]) -> Ir<'ir> {
let mut ir = ast_to_ir(alloc, instrs);
pass_group(alloc, &mut ir);
pass_find_set_null(&mut ir);
pass_set_n(&mut ir);
pass_cancel_left_right_add_sub(&mut ir);
pass_add_sub_offset(&mut ir);
pass_move_add_to(&mut ir);
ir
}
fn ast_to_ir<'ir>(alloc: &'ir Bump, ast: &[(Instr<'_>, Span)]) -> Ir<'ir> {
let mut stmts = Vec::new_in(alloc);
let stmts_iter = ast.iter().map(|(instr, span)| {
let kind = match instr {
Instr::Add => StmtKind::Add(0, 1),
Instr::Sub => StmtKind::Sub(0, 1),
Instr::Right => StmtKind::Right(1),
Instr::Left => StmtKind::Left(1),
Instr::Out => StmtKind::Out,
Instr::In => StmtKind::In,
Instr::Loop(body) => {
let ir_body = ast_to_ir(alloc, body);
StmtKind::Loop(ir_body)
}
};
Stmt::new(kind, *span)
});
stmts.extend(stmts_iter);
Ir { stmts }
} }
/// pass that replaces things like `Sub(1) Sub(1)` with `Sub(2)` /// pass that replaces things like `Sub(1) Sub(1)` with `Sub(2)`
// TODO: This pass is really slow, speed it up please // TODO: This pass is really slow, speed it up please
#[tracing::instrument] #[tracing::instrument]
fn pass_group<'ir>(alloc: &'ir Bump, ir_param: &mut Ir<'ir>) { fn pass_group<'hir>(alloc: &'hir Bump, ir_param: &mut Hir<'hir>) {
let empty_ir = Ir { let empty_ir = Hir {
stmts: Vec::new_in(alloc), stmts: Vec::new_in(alloc),
}; };
let ir = std::mem::replace(ir_param, empty_ir); let ir = std::mem::replace(ir_param, empty_ir);
let new_stmts = Vec::new_in(alloc); let new_stmts = Vec::new_in(alloc);
let stmts = ir let stmts =
.stmts ir.stmts
.into_iter() .into_iter()
.fold(new_stmts, |mut stmts: BumpVec<'ir, Stmt<'ir>>, next| { .fold(new_stmts, |mut stmts: BumpVec<'hir, Stmt<'hir>>, next| {
let Some(old) = stmts.last_mut() else { let Some(old) = stmts.last_mut() else {
if let StmtKind::Loop(mut body) = next.kind { if let StmtKind::Loop(mut body) = next.kind {
pass_group(alloc, &mut body); pass_group(alloc, &mut body);
@ -154,12 +81,12 @@ fn pass_group<'ir>(alloc: &'ir Bump, ir_param: &mut Ir<'ir>) {
stmts stmts
}); });
*ir_param = Ir { stmts }; *ir_param = Hir { stmts };
} }
/// pass that replaces `Loop([Sub(_)])` to `SetNull` /// pass that replaces `Loop([Sub(_)])` to `SetNull`
#[tracing::instrument] #[tracing::instrument]
fn pass_find_set_null(ir: &mut Ir<'_>) { fn pass_find_set_null(ir: &mut Hir<'_>) {
for stmt in &mut ir.stmts { for stmt in &mut ir.stmts {
if let Stmt { if let Stmt {
kind: StmtKind::Loop(body), kind: StmtKind::Loop(body),
@ -182,7 +109,7 @@ fn pass_find_set_null(ir: &mut Ir<'_>) {
/// pass that replaces `SetN(n) Add(m)` with `SetN(n + m)` /// pass that replaces `SetN(n) Add(m)` with `SetN(n + m)`
#[tracing::instrument] #[tracing::instrument]
fn pass_set_n(ir: &mut Ir<'_>) { fn pass_set_n(ir: &mut Hir<'_>) {
window_pass(ir, pass_set_n, |[a, b]| { window_pass(ir, pass_set_n, |[a, b]| {
if let StmtKind::SetN(before) = a.kind() { if let StmtKind::SetN(before) = a.kind() {
let new = match b.kind() { let new = match b.kind() {
@ -200,7 +127,7 @@ fn pass_set_n(ir: &mut Ir<'_>) {
/// pass that replaces `Left(5) Right(3)` with `Left(2)` /// pass that replaces `Left(5) Right(3)` with `Left(2)`
#[tracing::instrument] #[tracing::instrument]
fn pass_cancel_left_right_add_sub(ir: &mut Ir<'_>) { fn pass_cancel_left_right_add_sub(ir: &mut Hir<'_>) {
window_pass(ir, pass_cancel_left_right_add_sub, |[a, b]| { window_pass(ir, pass_cancel_left_right_add_sub, |[a, b]| {
match (a.kind(), b.kind()) { match (a.kind(), b.kind()) {
(StmtKind::Right(r), StmtKind::Left(l)) | (StmtKind::Left(l), StmtKind::Right(r)) => { (StmtKind::Right(r), StmtKind::Left(l)) | (StmtKind::Left(l), StmtKind::Right(r)) => {
@ -233,7 +160,7 @@ fn pass_cancel_left_right_add_sub(ir: &mut Ir<'_>) {
/// pass that replaces `Right(9) Add(5) Left(9)` with `AddOffset(9, 5)` /// pass that replaces `Right(9) Add(5) Left(9)` with `AddOffset(9, 5)`
#[tracing::instrument] #[tracing::instrument]
fn pass_add_sub_offset(ir: &mut Ir<'_>) { fn pass_add_sub_offset(ir: &mut Hir<'_>) {
window_pass(ir, pass_add_sub_offset, |[a, b, c]| { window_pass(ir, pass_add_sub_offset, |[a, b, c]| {
match (a.kind(), b.kind(), c.kind()) { match (a.kind(), b.kind(), c.kind()) {
(StmtKind::Right(r), StmtKind::Add(0, n), StmtKind::Left(l)) if r == l => { (StmtKind::Right(r), StmtKind::Add(0, n), StmtKind::Left(l)) if r == l => {
@ -255,7 +182,7 @@ fn pass_add_sub_offset(ir: &mut Ir<'_>) {
/// pass that replaces `Loop([Sub(1) AddOffset(o, 1)])` with `MoveAddTo(o)` /// pass that replaces `Loop([Sub(1) AddOffset(o, 1)])` with `MoveAddTo(o)`
#[tracing::instrument] #[tracing::instrument]
fn pass_move_add_to(ir: &mut Ir<'_>) { fn pass_move_add_to(ir: &mut Hir<'_>) {
for stmt in &mut ir.stmts { for stmt in &mut ir.stmts {
if let Stmt { if let Stmt {
kind: StmtKind::Loop(body), kind: StmtKind::Loop(body),
@ -286,16 +213,16 @@ fn pass_move_add_to(ir: &mut Ir<'_>) {
} }
} }
enum WindowPassAction<'ir> { enum WindowPassAction<'hir> {
None, None,
Merge(StmtKind<'ir>), Merge(StmtKind<'hir>),
RemoveAll, RemoveAll,
} }
fn window_pass<'ir, P, F, const N: usize>(ir: &mut Ir<'ir>, pass_recur: P, action: F) fn window_pass<'hir, P, F, const N: usize>(ir: &mut Hir<'hir>, pass_recur: P, action: F)
where where
P: Fn(&mut Ir<'ir>), P: Fn(&mut Hir<'hir>),
F: Fn([&Stmt<'ir>; N]) -> WindowPassAction<'ir>, F: Fn([&Stmt<'hir>; N]) -> WindowPassAction<'hir>,
{ {
assert!(N > 0); assert!(N > 0);

View file

@ -2,17 +2,20 @@
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
use crate::parse::ParseError; use std::{
fmt::Display,
io::{Read, Write},
path::PathBuf,
str::FromStr,
};
use bumpalo::Bump; use bumpalo::Bump;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use std::fmt::Display;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::str::FromStr;
pub mod codegen; use crate::parse::ParseError;
pub mod codegen_interpreter;
pub mod opts; pub mod hir;
pub mod lir;
pub mod parse; pub mod parse;
#[derive(clap::Parser, Default)] #[derive(clap::Parser, Default)]
@ -27,8 +30,8 @@ pub struct Args {
pub enum DumpKind { pub enum DumpKind {
Ast, Ast,
Ir, Hir,
Code, Lir,
} }
impl FromStr for DumpKind { impl FromStr for DumpKind {
@ -37,8 +40,8 @@ impl FromStr for DumpKind {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { match s {
"ast" => Ok(Self::Ast), "ast" => Ok(Self::Ast),
"ir" => Ok(Self::Ir), "hir" => Ok(Self::Hir),
"code" => Ok(Self::Code), "lir" => Ok(Self::Lir),
other => Err(format!("Invalid IR level: '{other}'")), other => Err(format!("Invalid IR level: '{other}'")),
} }
} }
@ -65,12 +68,12 @@ where
return Ok(()); return Ok(());
} }
let ir_alloc = Bump::new(); let hir_alloc = Bump::new();
let optimized_ir = opts::optimize(&ir_alloc, &parsed); let optimized_hir = hir::optimized_hir(&hir_alloc, &parsed);
if let Some(DumpKind::Ir) = config.dump { if let Some(DumpKind::Hir) = config.dump {
println!("{optimized_ir:#?}"); println!("{optimized_hir:#?}");
return Ok(()); return Ok(());
} }
@ -79,27 +82,27 @@ where
let cg_alloc = Bump::new(); let cg_alloc = Bump::new();
let code = codegen::generate(&cg_alloc, &optimized_ir); let lir = lir::generate(&cg_alloc, &optimized_hir);
if let Some(DumpKind::Code) = config.dump { if let Some(DumpKind::Lir) = config.dump {
println!("{code:#?}"); println!("{lir:#?}");
return Ok(()); return Ok(());
} }
drop(optimized_ir); drop(optimized_hir);
drop(ir_alloc); drop(hir_alloc);
match config.profile { match config.profile {
true => { true => {
let mut code_profile_count = vec![0; code.debug().len()]; let mut code_profile_count = vec![0; lir.debug().len()];
codegen_interpreter::run(&code, stdout, stdin, |ip| unsafe { lir::interpreter::run(&lir, stdout, stdin, |ip| unsafe {
*code_profile_count.get_unchecked_mut(ip) += 1; *code_profile_count.get_unchecked_mut(ip) += 1;
}); });
let mut src_profile_count = vec![0u64; src.len()]; let mut src_profile_count = vec![0u64; src.len()];
for (stmt_span, stmt_count) in code.debug().iter().zip(&code_profile_count) { for (stmt_span, stmt_count) in lir.debug().iter().zip(&code_profile_count) {
for i in &mut src_profile_count[stmt_span.start()..stmt_span.end()] { for i in &mut src_profile_count[stmt_span.start()..stmt_span.end()] {
*i += stmt_count; *i += stmt_count;
} }
@ -112,7 +115,7 @@ where
} }
} }
false => { false => {
codegen_interpreter::run(&code, stdout, stdin, |_| {}); lir::interpreter::run(&lir, stdout, stdin, |_| {});
} }
} }

View file

@ -1,6 +1,9 @@
use crate::codegen::{Code, Stmt}; use std::{
use std::io::{Read, Write}; io::{Read, Write},
use std::num::Wrapping; num::Wrapping,
};
use crate::lir::{Lir, Stmt};
const MEM_SIZE: usize = 32_000; const MEM_SIZE: usize = 32_000;
@ -10,7 +13,7 @@ type Memory = [Wrapping<u8>; MEM_SIZE];
// maybe useless, but seems to give tiny wins // maybe useless, but seems to give tiny wins
#[repr(C)] #[repr(C)]
struct Interpreter<'c, W, R, P> { struct Interpreter<'c, W, R, P> {
code: &'c Code<'c>, code: &'c Lir<'c>,
profile_collector: P, profile_collector: P,
ip: usize, ip: usize,
ptr: usize, ptr: usize,
@ -19,7 +22,7 @@ struct Interpreter<'c, W, R, P> {
stdin: R, stdin: R,
} }
pub fn run<W, R, P>(code: &Code<'_>, stdout: W, stdin: R, profile_collector: P) pub fn run<W, R, P>(code: &Lir<'_>, stdout: W, stdin: R, profile_collector: P)
where where
W: Write, W: Write,
R: Read, R: Read,
@ -35,7 +38,7 @@ where
profile_collector, profile_collector,
}; };
// SAFETY: `Code` can only be produced by the `crate::codegen` module, which is trusted to not // SAFETY: `Lir` can only be produced by the `crate::lir` module, which is trusted to not
// produce out of bounds jumps and put the `End` at the end // produce out of bounds jumps and put the `End` at the end
unsafe { unsafe {
interpreter.execute(); interpreter.execute();

View file

@ -17,12 +17,18 @@
//! this module must not produce out of bounds jumps and always put the `End` instruction at the //! this module must not produce out of bounds jumps and always put the `End` instruction at the
//! end //! end
use crate::opts::{Ir, Stmt as IrStmt, StmtKind}; pub mod interpreter;
use crate::parse::Span;
use crate::BumpVec;
use bumpalo::Bump;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use bumpalo::Bump;
use crate::{
hir::{Hir, Stmt as HirStmt, StmtKind as HirStmtKind},
parse::Span,
BumpVec,
};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Stmt { pub enum Stmt {
Add(u8), Add(u8),
@ -43,18 +49,18 @@ pub enum Stmt {
const _: [(); 8] = [(); std::mem::size_of::<Stmt>()]; const _: [(); 8] = [(); std::mem::size_of::<Stmt>()];
#[derive(Clone)] #[derive(Clone)]
pub struct Code<'c> { pub struct Lir<'c> {
stmts: BumpVec<'c, Stmt>, stmts: BumpVec<'c, Stmt>,
debug: BumpVec<'c, Span>, debug: BumpVec<'c, Span>,
} }
impl Debug for Code<'_> { impl Debug for Lir<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.stmts.fmt(f) self.stmts.fmt(f)
} }
} }
impl Code<'_> { impl Lir<'_> {
pub fn stmts(&self) -> &[Stmt] { pub fn stmts(&self) -> &[Stmt] {
&self.stmts &self.stmts
} }
@ -64,68 +70,68 @@ impl Code<'_> {
} }
} }
pub fn generate<'c>(alloc: &'c Bump, ir: &Ir<'_>) -> Code<'c> { pub fn generate<'c>(alloc: &'c Bump, ir: &Hir<'_>) -> Lir<'c> {
let stmts = Vec::new_in(alloc); let stmts = Vec::new_in(alloc);
let debug = Vec::new_in(alloc); let debug = Vec::new_in(alloc);
let mut code = Code { stmts, debug }; let mut lir = Lir { stmts, debug };
generate_stmts(&mut code, &ir.stmts); generate_stmts(&mut lir, &ir.stmts);
code.stmts.push(Stmt::End); lir.stmts.push(Stmt::End);
code.debug.push(Span::default()); lir.debug.push(Span::default());
assert_eq!(code.stmts.len(), code.debug.len()); assert_eq!(lir.stmts.len(), lir.debug.len());
code lir
} }
fn generate_stmts<'c>(code: &mut Code<'c>, ir: &[IrStmt<'_>]) { fn generate_stmts<'c>(lir: &mut Lir<'c>, ir: &[HirStmt<'_>]) {
for ir_stmt in ir { for ir_stmt in ir {
ir_to_stmt(code, ir_stmt); ir_to_stmt(lir, ir_stmt);
} }
debug_assert_eq!(code.stmts.len(), code.debug.len()); debug_assert_eq!(lir.stmts.len(), lir.debug.len());
} }
fn ir_to_stmt<'c>(code: &mut Code<'c>, ir_stmt: &IrStmt<'_>) { fn ir_to_stmt<'c>(lir: &mut Lir<'c>, ir_stmt: &HirStmt<'_>) {
let stmt = match &ir_stmt.kind { let stmt = match &ir_stmt.kind {
StmtKind::Add(0, n) => Stmt::Add(*n), HirStmtKind::Add(0, n) => Stmt::Add(*n),
StmtKind::Sub(0, n) => Stmt::Sub(*n), HirStmtKind::Sub(0, n) => Stmt::Sub(*n),
StmtKind::Add(offset, n) => Stmt::AddOffset { HirStmtKind::Add(offset, n) => Stmt::AddOffset {
offset: *offset, offset: *offset,
n: *n, n: *n,
}, },
StmtKind::Sub(offset, n) => Stmt::SubOffset { HirStmtKind::Sub(offset, n) => Stmt::SubOffset {
offset: *offset, offset: *offset,
n: *n, n: *n,
}, },
StmtKind::MoveAddTo { offset } => Stmt::MoveAddTo { offset: *offset }, HirStmtKind::MoveAddTo { offset } => Stmt::MoveAddTo { offset: *offset },
StmtKind::Right(n) => Stmt::Right(u32::try_from(*n).unwrap()), HirStmtKind::Right(n) => Stmt::Right(u32::try_from(*n).unwrap()),
StmtKind::Left(n) => Stmt::Left(u32::try_from(*n).unwrap()), HirStmtKind::Left(n) => Stmt::Left(u32::try_from(*n).unwrap()),
StmtKind::Out => Stmt::Out, HirStmtKind::Out => Stmt::Out,
StmtKind::In => Stmt::In, HirStmtKind::In => Stmt::In,
StmtKind::SetN(n) => Stmt::SetN(*n), HirStmtKind::SetN(n) => Stmt::SetN(*n),
StmtKind::Loop(instr) => { HirStmtKind::Loop(instr) => {
let skip_jmp_idx = code.stmts.len(); let skip_jmp_idx = lir.stmts.len();
code.stmts.push(Stmt::JmpIfZero(0)); // placeholder lir.stmts.push(Stmt::JmpIfZero(0)); // placeholder
code.debug.push(ir_stmt.span); lir.debug.push(ir_stmt.span);
// compile the loop body now // compile the loop body now
generate_stmts(code, &instr.stmts); generate_stmts(lir, &instr.stmts);
// if the loop body is empty, we jmp to ourselves, which is an infinite loop - as expected // if the loop body is empty, we jmp to ourselves, which is an infinite loop - as expected
let first_loop_body_idx = skip_jmp_idx + 1; let first_loop_body_idx = skip_jmp_idx + 1;
code.stmts lir.stmts
.push(Stmt::JmpIfNonZero(first_loop_body_idx.try_into().unwrap())); .push(Stmt::JmpIfNonZero(first_loop_body_idx.try_into().unwrap()));
code.debug.push(ir_stmt.span); lir.debug.push(ir_stmt.span);
// there will always at least be an `End` instruction after the loop // there will always at least be an `End` instruction after the loop
let after_loop_idx = code.stmts.len(); let after_loop_idx = lir.stmts.len();
// fix the placeholder with the actual index // fix the placeholder with the actual index
code.stmts[skip_jmp_idx] = Stmt::JmpIfZero(after_loop_idx.try_into().unwrap()); lir.stmts[skip_jmp_idx] = Stmt::JmpIfZero(after_loop_idx.try_into().unwrap());
return; return;
} }
}; };
code.stmts.push(stmt); lir.stmts.push(stmt);
code.debug.push(ir_stmt.span); lir.debug.push(ir_stmt.span);
} }

View file

@ -1,9 +1,10 @@
#![feature(allocator_api, let_else)] #![feature(allocator_api, let_else)]
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
use std::{fs, io, process};
use brainfuck::Args; use brainfuck::Args;
use clap::Parser; use clap::Parser;
use std::{fs, io, process};
fn main() { fn main() {
let stdout = io::stdout(); let stdout = io::stdout();

View file

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

View file

@ -1 +1,5 @@
[->>>>>>>>>+<<<<<<<<<] [<+++>-
>>>>>
+++[->+++++<]>[-]<
<<<<<
]