diff --git a/rust2/src/codegen.rs b/rust2/src/codegen.rs index 6689b30..01316d1 100644 --- a/rust2/src/codegen.rs +++ b/rust2/src/codegen.rs @@ -31,6 +31,7 @@ pub enum Stmt { Out, In, SetNull, + SetN(u8), JmpIfZero(u32), JmpIfNonZero(u32), End, @@ -84,6 +85,7 @@ fn ir_to_stmt<'c>(code: &mut Code<'c>, ir_stmt: &IrStmt<'_>) { StmtKind::Out => Stmt::Out, StmtKind::In => Stmt::In, StmtKind::SetNull => Stmt::SetNull, + StmtKind::SetN(n) => Stmt::SetN(*n), StmtKind::Loop(instr) => { let skip_jmp_idx = code.stmts.len(); code.stmts.push(Stmt::JmpIfZero(0)); // placeholder diff --git a/rust2/src/codegen_interpreter.rs b/rust2/src/codegen_interpreter.rs index ec34b75..0935445 100644 --- a/rust2/src/codegen_interpreter.rs +++ b/rust2/src/codegen_interpreter.rs @@ -87,6 +87,9 @@ where Stmt::SetNull => { *self.elem_mut() = Wrapping(0); } + Stmt::SetN(n) => { + *self.elem_mut() = Wrapping(n); + } Stmt::JmpIfZero(pos) => { if self.elem() == 0 { self.ip = pos as usize; diff --git a/rust2/src/lib.rs b/rust2/src/lib.rs index c5de172..f216805 100644 --- a/rust2/src/lib.rs +++ b/rust2/src/lib.rs @@ -1,7 +1,6 @@ #![feature(allocator_api, let_else)] #![deny(unsafe_op_in_unsafe_fn)] #![warn(rust_2018_idioms)] -#![allow(dead_code)] use crate::parse::ParseError; use bumpalo::Bump; diff --git a/rust2/src/main.rs b/rust2/src/main.rs index 0aafec6..03e5969 100644 --- a/rust2/src/main.rs +++ b/rust2/src/main.rs @@ -20,7 +20,12 @@ fn main() { let stdin = io::stdin(); let stdin = stdin.lock(); - brainfuck::run(&file, stdout, stdin, UseProfile::Yes).unwrap_or_else(|_| { + let profile = env::args() + .any(|a| a == "--profile") + .then(|| UseProfile::Yes) + .unwrap_or(UseProfile::No); + + brainfuck::run(&file, stdout, stdin, profile).unwrap_or_else(|_| { eprintln!("error: Failed to parse brainfuck code"); process::exit(1); }); diff --git a/rust2/src/opts.rs b/rust2/src/opts.rs index 51dc2d4..58c635b 100644 --- a/rust2/src/opts.rs +++ b/rust2/src/opts.rs @@ -14,11 +14,12 @@ pub struct Stmt<'ir> { } impl<'ir> Stmt<'ir> { - fn lol(kind: StmtKind<'ir>) -> Stmt<'ir> { - Self { - kind, - span: Span::default(), - } + fn new(kind: StmtKind<'ir>, span: Span) -> Stmt<'ir> { + Self { kind, span } + } + + fn kind(&self) -> &StmtKind<'ir> { + &self.kind } } @@ -32,12 +33,14 @@ pub enum StmtKind<'ir> { Out, In, SetNull, + SetN(u8), } pub fn optimize<'ir>(alloc: &'ir Bump, instrs: &[(Instr<'_>, Span)]) -> Ir<'ir> { let ir = ast_to_ir(alloc, instrs); let mut ir = pass_group(alloc, ir); pass_find_set_null(&mut ir); + pass_set_n(&mut ir); ir } @@ -57,7 +60,7 @@ fn ast_to_ir<'ir>(alloc: &'ir Bump, ast: &[(Instr<'_>, Span)]) -> Ir<'ir> { StmtKind::Loop(ir_body) } }; - Stmt { kind, span: *span } + Stmt::new(kind, *span) }); stmts.extend(stmts_iter); @@ -65,6 +68,7 @@ fn ast_to_ir<'ir>(alloc: &'ir Bump, ast: &[(Instr<'_>, Span)]) -> Ir<'ir> { Ir { stmts } } +/// pass that replaces things like `Sub(1) Sub(1)` with `Sub(2)` fn pass_group<'ir>(alloc: &'ir Bump, ir: Ir<'ir>) -> Ir<'ir> { let new_stmts = Vec::new_in(alloc); let stmts = ir @@ -74,10 +78,10 @@ fn pass_group<'ir>(alloc: &'ir Bump, ir: Ir<'ir>) -> Ir<'ir> { let Some(old) = stmts.last_mut() else { if let StmtKind::Loop(body) = next.kind { let new_body = pass_group(alloc, body); - stmts.push(Stmt { - span: next.span, - kind: StmtKind::Loop(new_body), - }); + stmts.push(Stmt::new( + StmtKind::Loop(new_body), + next.span, + )); } else { stmts.push(next); } @@ -109,10 +113,7 @@ fn pass_group<'ir>(alloc: &'ir Bump, ir: Ir<'ir>) -> Ir<'ir> { }); } (_, kind) => { - stmts.push(Stmt { - span: next.span, - kind, - }); + stmts.push(Stmt::new(kind, next.span)); } } @@ -122,6 +123,7 @@ fn pass_group<'ir>(alloc: &'ir Bump, ir: Ir<'ir>) -> Ir<'ir> { Ir { stmts } } +/// pass that replaces `Loop([Sub(_)])` to `SetNull` fn pass_find_set_null(ir: &mut Ir<'_>) { for stmt in &mut ir.stmts { if let Stmt { @@ -131,13 +133,37 @@ fn pass_find_set_null(ir: &mut Ir<'_>) { { if let [Stmt { kind: StmtKind::Sub(_), - .. + span, }] = body.stmts.as_slice() { - *stmt = Stmt::lol(StmtKind::SetNull); + *stmt = Stmt::new(StmtKind::SetNull, *span); } else { pass_find_set_null(body); } } } } + +/// pass that replaces `SetNull Add(5)` with `SetN(5)` +fn pass_set_n(ir: &mut Ir<'_>) { + let stmts = &mut ir.stmts; + let mut i = 0; + while i < stmts.len() - 1 { + let a = &stmts[i]; + if let StmtKind::SetNull = a.kind() { + let b = &stmts[i + 1]; + let new = match b.kind() { + StmtKind::Add(n) => StmtKind::SetN(*n), + StmtKind::Sub(n) => StmtKind::SetN(0u8.wrapping_sub(*n)), + _ => { + i += 1; + continue; + } + }; + let span = a.span.merge(b.span); + stmts.remove(i + 1); + stmts[i] = Stmt::new(new, span); + } + i += 1; + } +} diff --git a/rust2/src/snapshots/brainfuck__parse__tests__nested_loop.snap b/rust2/src/snapshots/brainfuck__parse__tests__nested_loop.snap index e2f734d..a58adc7 100644 --- a/rust2/src/snapshots/brainfuck__parse__tests__nested_loop.snap +++ b/rust2/src/snapshots/brainfuck__parse__tests__nested_loop.snap @@ -1,6 +1,6 @@ --- source: src/parse.rs -assertion_line: 132 +assertion_line: 164 expression: instrs --- Ok( @@ -46,14 +46,14 @@ Ok( ), Span { start: 5, - len: 2, + len: 3, }, ), ], ), Span { start: 3, - len: 5, + len: 6, }, ), ( @@ -88,7 +88,7 @@ Ok( ), Span { start: 1, - len: 12, + len: 13, }, ), ], diff --git a/rust2/src/snapshots/brainfuck__parse__tests__simple.snap b/rust2/src/snapshots/brainfuck__parse__tests__simple.snap index 4c32fe4..e534701 100644 --- a/rust2/src/snapshots/brainfuck__parse__tests__simple.snap +++ b/rust2/src/snapshots/brainfuck__parse__tests__simple.snap @@ -1,6 +1,6 @@ --- source: src/parse.rs -assertion_line: 123 +assertion_line: 155 expression: instrs --- Ok( @@ -54,7 +54,7 @@ Ok( ), Span { start: 5, - len: 2, + len: 3, }, ), (