mirror of
https://github.com/Noratrieb/brainfuck.git
synced 2026-01-14 13:35:00 +01:00
things that don't work but sound fun
This commit is contained in:
parent
799b1591e0
commit
eda2476021
6 changed files with 256 additions and 191 deletions
94
rust2/src/codegen.rs
Normal file
94
rust2/src/codegen.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
//! codegen to flat code
|
||||||
|
//!
|
||||||
|
//! ```bf
|
||||||
|
//! ++[-].
|
||||||
|
//! ```
|
||||||
|
//! compiles down to
|
||||||
|
//! ```text
|
||||||
|
//! Add | Add | JmpIfZero | Out | End | Sub | JmpIfNonZero | Jmp
|
||||||
|
//! | | ^ | |
|
||||||
|
//! +-------------------+---------|----------+
|
||||||
|
//! +---------------------+
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use crate::opts::{Ir, Stmt as IrStmt, StmtKind};
|
||||||
|
use crate::parse::Span;
|
||||||
|
use bumpalo::Bump;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Stmt {
|
||||||
|
Add(u8),
|
||||||
|
Sub(u8),
|
||||||
|
Right(usize),
|
||||||
|
Left(usize),
|
||||||
|
Out,
|
||||||
|
In,
|
||||||
|
SetNull,
|
||||||
|
JmpIfZero(usize),
|
||||||
|
JmpIfNonZero(usize),
|
||||||
|
Jmp(usize),
|
||||||
|
End,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Code<'c> {
|
||||||
|
pub stmts: Vec<Stmt, &'c Bump>,
|
||||||
|
pub debug: Vec<Span, &'c Bump>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UnlinkedCode<'u> {
|
||||||
|
pub stmts: Vec<Vec<Stmt, &'u Bump>, &'u Bump>,
|
||||||
|
pub debug: Vec<Vec<Span, &'u Bump>, &'u Bump>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate<'c>(alloc: &'c Bump, ir: &Ir<'_>) -> Code<'c> {
|
||||||
|
let unlinked_alloc = Bump::new();
|
||||||
|
|
||||||
|
let stmts = Vec::new_in(&unlinked_alloc);
|
||||||
|
let debug = Vec::new_in(&unlinked_alloc);
|
||||||
|
let mut unlinked = UnlinkedCode { stmts, debug };
|
||||||
|
|
||||||
|
generate_stmts(&unlinked_alloc, &mut unlinked, &ir.stmts);
|
||||||
|
|
||||||
|
link(alloc, &unlinked)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_stmts<'u>(alloc: &'u Bump, code: &mut UnlinkedCode<'u>, ir: &[IrStmt<'_>]) {
|
||||||
|
for ir_stmt in ir {
|
||||||
|
ir_to_stmt(alloc, code, ir_stmt, 0);
|
||||||
|
}
|
||||||
|
assert_eq!(code.stmts.len(), code.debug.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ir_to_stmt<'u>(
|
||||||
|
alloc: &'u Bump,
|
||||||
|
code: &mut UnlinkedCode<'u>,
|
||||||
|
ir_stmt: &IrStmt<'_>,
|
||||||
|
current_block: usize,
|
||||||
|
) {
|
||||||
|
let stmt = match &ir_stmt.kind {
|
||||||
|
StmtKind::Add(n) => Stmt::Add(*n),
|
||||||
|
StmtKind::Sub(n) => Stmt::Sub(*n),
|
||||||
|
StmtKind::Right(n) => Stmt::Right(*n),
|
||||||
|
StmtKind::Left(n) => Stmt::Left(*n),
|
||||||
|
StmtKind::Out => Stmt::Out,
|
||||||
|
StmtKind::In => Stmt::In,
|
||||||
|
StmtKind::SetNull => Stmt::SetNull,
|
||||||
|
StmtKind::Loop(instr) => {
|
||||||
|
let new_block = Vec::new_in(alloc);
|
||||||
|
let new_block_debug = Vec::new_in(alloc);
|
||||||
|
code.stmts.push(new_block);
|
||||||
|
code.stmts.push(new_block_debug);
|
||||||
|
|
||||||
|
let current_block = code.stmts.len() - 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
code.stmts[current_block].push(stmt);
|
||||||
|
code.debug[current_block].push(ir_stmt.span);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn link<'c>(alloc: &'c Bump, code: &UnlinkedCode<'_>) -> Code<'c> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
100
rust2/src/codegen_interpreter.rs
Normal file
100
rust2/src/codegen_interpreter.rs
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
use crate::codegen::{Code, Stmt};
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::num::Wrapping;
|
||||||
|
|
||||||
|
const MEM_SIZE: usize = 32_000;
|
||||||
|
|
||||||
|
type Memory = [Wrapping<u8>; MEM_SIZE];
|
||||||
|
|
||||||
|
// TODO maybe repr(C) to prevent field reordering?
|
||||||
|
struct Interpreter<'c, W, R> {
|
||||||
|
code: &'c Code<'c>,
|
||||||
|
ip: usize,
|
||||||
|
ptr: usize,
|
||||||
|
stdout: W,
|
||||||
|
stdin: R,
|
||||||
|
mem: Memory,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run<W, R>(code: &Code<'_>, stdout: W, stdin: R)
|
||||||
|
where
|
||||||
|
W: Write,
|
||||||
|
R: Read,
|
||||||
|
{
|
||||||
|
let mut interpreter = Interpreter {
|
||||||
|
code,
|
||||||
|
ip: 0,
|
||||||
|
ptr: 0,
|
||||||
|
stdout,
|
||||||
|
stdin,
|
||||||
|
mem: [Wrapping(0u8); MEM_SIZE],
|
||||||
|
};
|
||||||
|
|
||||||
|
interpreter.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'c, W: Write, R: Read> Interpreter<'c, W, R> {
|
||||||
|
fn execute(&mut self) {
|
||||||
|
loop {
|
||||||
|
let instr = self.code.stmts[self.ip];
|
||||||
|
self.ip += 1;
|
||||||
|
match instr {
|
||||||
|
Stmt::Add(n) => {
|
||||||
|
*self.elem_mut() += n;
|
||||||
|
}
|
||||||
|
Stmt::Sub(n) => {
|
||||||
|
*self.elem_mut() -= n;
|
||||||
|
}
|
||||||
|
Stmt::Right(n) => {
|
||||||
|
self.ptr += n;
|
||||||
|
if self.ptr >= MEM_SIZE {
|
||||||
|
self.ptr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stmt::Left(n) => {
|
||||||
|
if self.ptr < n {
|
||||||
|
let diff = n - self.ptr;
|
||||||
|
self.ptr = MEM_SIZE - 1 - diff;
|
||||||
|
} else {
|
||||||
|
self.ptr -= n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stmt::Out => {
|
||||||
|
let char = self.elem() as char;
|
||||||
|
write!(self.stdout, "{char}").unwrap();
|
||||||
|
self.stdout.flush().unwrap();
|
||||||
|
}
|
||||||
|
Stmt::In => {
|
||||||
|
let mut buf = [0; 1];
|
||||||
|
self.stdin.read_exact(&mut buf).unwrap();
|
||||||
|
*self.elem_mut() = Wrapping(buf[0]);
|
||||||
|
}
|
||||||
|
Stmt::SetNull => {
|
||||||
|
*self.elem_mut() = Wrapping(0);
|
||||||
|
}
|
||||||
|
Stmt::JmpIfZero(pos) => {
|
||||||
|
if self.elem() == 0 {
|
||||||
|
self.ip = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stmt::JmpIfNonZero(pos) => {
|
||||||
|
if self.elem() != 0 {
|
||||||
|
self.ip = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stmt::Jmp(pos) => {
|
||||||
|
self.ip = pos;
|
||||||
|
}
|
||||||
|
Stmt::End => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn elem_mut(&mut self) -> &mut Wrapping<u8> {
|
||||||
|
&mut self.mem[self.ptr]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn elem(&self) -> u8 {
|
||||||
|
self.mem[self.ptr].0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
use crate::opts::{Ir, Stmt};
|
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::num::Wrapping;
|
|
||||||
|
|
||||||
const MEM_SIZE: usize = 32_000;
|
|
||||||
|
|
||||||
type Memory = [Wrapping<u8>; MEM_SIZE];
|
|
||||||
|
|
||||||
pub fn run<W, R>(instrs: &Ir<'_>, mut stdout: W, mut stdin: R)
|
|
||||||
where
|
|
||||||
W: Write,
|
|
||||||
R: Read,
|
|
||||||
{
|
|
||||||
let mut mem = [Wrapping(0u8); MEM_SIZE];
|
|
||||||
let mut ptr = 0;
|
|
||||||
|
|
||||||
execute(&mut mem, &mut ptr, &instrs.stmts, &mut stdout, &mut stdin);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute<W, R>(
|
|
||||||
mem: &mut Memory,
|
|
||||||
ptr: &mut usize,
|
|
||||||
instrs: &[Stmt<'_>],
|
|
||||||
stdout: &mut W,
|
|
||||||
stdin: &mut R,
|
|
||||||
) where
|
|
||||||
W: Write,
|
|
||||||
R: Read,
|
|
||||||
{
|
|
||||||
for instr in instrs {
|
|
||||||
match instr {
|
|
||||||
Stmt::Add(n) => {
|
|
||||||
mem[*ptr] += n;
|
|
||||||
}
|
|
||||||
Stmt::Sub(n) => {
|
|
||||||
mem[*ptr] -= n;
|
|
||||||
}
|
|
||||||
Stmt::Right(n) => {
|
|
||||||
*ptr += n;
|
|
||||||
if *ptr >= MEM_SIZE {
|
|
||||||
*ptr = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Stmt::Left(n) => {
|
|
||||||
if *ptr < *n {
|
|
||||||
let diff = *n - *ptr;
|
|
||||||
*ptr = MEM_SIZE - 1 - diff;
|
|
||||||
} else {
|
|
||||||
*ptr -= n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Stmt::Out => {
|
|
||||||
let char = mem[*ptr].0 as char;
|
|
||||||
write!(stdout, "{char}").unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
}
|
|
||||||
Stmt::In => {
|
|
||||||
let mut buf = [0; 1];
|
|
||||||
stdin.read_exact(&mut buf).unwrap();
|
|
||||||
mem[*ptr] = Wrapping(buf[0]);
|
|
||||||
}
|
|
||||||
Stmt::Loop(body) => {
|
|
||||||
while mem[*ptr] != Wrapping(0) {
|
|
||||||
execute(mem, ptr, &body.stmts, stdout, stdin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Stmt::SetNull => {
|
|
||||||
mem[*ptr] = Wrapping(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Profile = Vec<u64>;
|
|
||||||
|
|
||||||
pub fn run_profile<W, R>(instrs: &Ir<'_>, mut stdout: W, mut stdin: R) -> Profile
|
|
||||||
where
|
|
||||||
W: Write,
|
|
||||||
R: Read,
|
|
||||||
{
|
|
||||||
let mut mem = [Wrapping(0u8); MEM_SIZE];
|
|
||||||
let mut ptr = 0;
|
|
||||||
|
|
||||||
let size = instrs
|
|
||||||
.spans
|
|
||||||
.last()
|
|
||||||
.map(|sp| sp.start() + sp.len())
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
let mut profile = vec![0; size];
|
|
||||||
|
|
||||||
execute_profile(
|
|
||||||
&mut mem,
|
|
||||||
&mut ptr,
|
|
||||||
instrs,
|
|
||||||
&mut stdout,
|
|
||||||
&mut stdin,
|
|
||||||
&mut profile,
|
|
||||||
);
|
|
||||||
|
|
||||||
profile
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_profile<W, R>(
|
|
||||||
mem: &mut Memory,
|
|
||||||
ptr: &mut usize,
|
|
||||||
ir: &Ir<'_>,
|
|
||||||
stdout: &mut W,
|
|
||||||
stdin: &mut R,
|
|
||||||
profile: &mut [u64],
|
|
||||||
) where
|
|
||||||
W: Write,
|
|
||||||
R: Read,
|
|
||||||
{
|
|
||||||
for (i, stmt) in ir.stmts.iter().enumerate() {
|
|
||||||
match stmt {
|
|
||||||
Stmt::Add(n) => {
|
|
||||||
mem[*ptr] += n;
|
|
||||||
}
|
|
||||||
Stmt::Sub(n) => {
|
|
||||||
mem[*ptr] -= n;
|
|
||||||
}
|
|
||||||
Stmt::Right(n) => {
|
|
||||||
*ptr += n;
|
|
||||||
if *ptr >= MEM_SIZE {
|
|
||||||
*ptr = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Stmt::Left(n) => {
|
|
||||||
if *ptr < *n {
|
|
||||||
let diff = *n - *ptr;
|
|
||||||
*ptr = MEM_SIZE - 1 - diff;
|
|
||||||
} else {
|
|
||||||
*ptr -= n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Stmt::Out => {
|
|
||||||
let char = mem[*ptr].0 as char;
|
|
||||||
write!(stdout, "{char}").unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
}
|
|
||||||
Stmt::In => {
|
|
||||||
let mut buf = [0; 1];
|
|
||||||
stdin.read_exact(&mut buf).unwrap();
|
|
||||||
mem[*ptr] = Wrapping(buf[0]);
|
|
||||||
}
|
|
||||||
Stmt::Loop(body) => {
|
|
||||||
while mem[*ptr] != Wrapping(0) {
|
|
||||||
execute_profile(mem, ptr, body, stdout, stdin, profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Stmt::SetNull => {
|
|
||||||
mem[*ptr] = Wrapping(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let span = ir.spans[i];
|
|
||||||
profile[span.start()..][..span.len()]
|
|
||||||
.iter_mut()
|
|
||||||
.for_each(|p| *p += 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
#![feature(allocator_api, let_else)]
|
#![feature(allocator_api, let_else)]
|
||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use crate::parse::ParseError;
|
use crate::parse::ParseError;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
pub mod ir_interpreter;
|
mod codegen;
|
||||||
|
mod codegen_interpreter;
|
||||||
pub mod opts;
|
pub mod opts;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
|
|
||||||
|
|
@ -31,17 +33,25 @@ where
|
||||||
drop(parsed);
|
drop(parsed);
|
||||||
drop(ast_alloc);
|
drop(ast_alloc);
|
||||||
|
|
||||||
|
let cg_alloc = Bump::new();
|
||||||
|
|
||||||
|
let code = codegen::generate(&cg_alloc, &optimized_ir);
|
||||||
|
|
||||||
|
drop(optimized_ir);
|
||||||
|
drop(ir_alloc);
|
||||||
|
|
||||||
match use_profile {
|
match use_profile {
|
||||||
UseProfile::Yes => {
|
UseProfile::Yes => {
|
||||||
let profile = ir_interpreter::run_profile(&optimized_ir, stdout, stdin);
|
// let profile = ir_interpreter::run_profile(&optimized_ir, stdout, stdin);
|
||||||
let max = profile.iter().max().copied().unwrap_or(0);
|
// let max = profile.iter().max().copied().unwrap_or(0);
|
||||||
println!("---------------- Profile ----------------");
|
// println!("---------------- Profile ----------------");
|
||||||
for (i, char) in str.bytes().enumerate() {
|
// for (i, char) in str.bytes().enumerate() {
|
||||||
print!("{}", color_by_profile(char as char, profile[i], max));
|
// print!("{}", color_by_profile(char as char, profile[i], max));
|
||||||
}
|
// }
|
||||||
|
println!("no supported lol");
|
||||||
}
|
}
|
||||||
UseProfile::No => {
|
UseProfile::No => {
|
||||||
ir_interpreter::run(&optimized_ir, stdout, stdin);
|
codegen_interpreter::run(&code, stdout, stdin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,25 @@ use bumpalo::Bump;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Ir<'ir> {
|
pub struct Ir<'ir> {
|
||||||
pub stmts: Vec<Stmt<'ir>, &'ir Bump>,
|
pub stmts: Vec<Stmt<'ir>, &'ir Bump>,
|
||||||
pub spans: Vec<Span, &'ir Bump>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Stmt<'ir> {
|
pub struct Stmt<'ir> {
|
||||||
|
pub kind: StmtKind<'ir>,
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ir> Stmt<'ir> {
|
||||||
|
fn lol(kind: StmtKind<'ir>) -> Stmt<'ir> {
|
||||||
|
Self {
|
||||||
|
kind,
|
||||||
|
span: Span::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum StmtKind<'ir> {
|
||||||
Add(u8),
|
Add(u8),
|
||||||
Sub(u8),
|
Sub(u8),
|
||||||
Right(usize),
|
Right(usize),
|
||||||
|
|
@ -32,7 +46,7 @@ fn ast_to_ir<'ir>(alloc: &'ir Bump, ast: &[(Instr<'_>, Span)]) -> Ir<'ir> {
|
||||||
let mut instr_iter = ast.iter();
|
let mut instr_iter = ast.iter();
|
||||||
|
|
||||||
let Some(first) = instr_iter.next() else {
|
let Some(first) = instr_iter.next() else {
|
||||||
return Ir { stmts, spans: Vec::new_in(alloc) };
|
return Ir { stmts };
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut last = &first.0;
|
let mut last = &first.0;
|
||||||
|
|
@ -50,13 +64,13 @@ fn ast_to_ir<'ir>(alloc: &'ir Bump, ast: &[(Instr<'_>, Span)]) -> Ir<'ir> {
|
||||||
_ => {
|
_ => {
|
||||||
end_span = *next_span;
|
end_span = *next_span;
|
||||||
let new_last = match last {
|
let new_last = match last {
|
||||||
Instr::Add => Stmt::Add(count),
|
Instr::Add => Stmt::lol(StmtKind::Add(count)),
|
||||||
Instr::Sub => Stmt::Sub(count),
|
Instr::Sub => Stmt::lol(StmtKind::Sub(count)),
|
||||||
Instr::Right => Stmt::Right(count.into()),
|
Instr::Right => Stmt::lol(StmtKind::Right(count.into())),
|
||||||
Instr::Left => Stmt::Left(count.into()),
|
Instr::Left => Stmt::lol(StmtKind::Left(count.into())),
|
||||||
Instr::Out => Stmt::Out,
|
Instr::Out => Stmt::lol(StmtKind::Out),
|
||||||
Instr::In => Stmt::In,
|
Instr::In => Stmt::lol(StmtKind::In),
|
||||||
Instr::Loop(body) => Stmt::Loop(ast_to_ir(alloc, body)),
|
Instr::Loop(body) => Stmt::lol(StmtKind::Loop(ast_to_ir(alloc, body))),
|
||||||
};
|
};
|
||||||
stmts.push(new_last);
|
stmts.push(new_last);
|
||||||
spans.push(start_span.until(end_span));
|
spans.push(start_span.until(end_span));
|
||||||
|
|
@ -68,25 +82,33 @@ fn ast_to_ir<'ir>(alloc: &'ir Bump, ast: &[(Instr<'_>, Span)]) -> Ir<'ir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_last = match last {
|
let new_last = match last {
|
||||||
Instr::Add => Stmt::Add(count),
|
Instr::Add => Stmt::lol(StmtKind::Add(count)),
|
||||||
Instr::Sub => Stmt::Sub(count),
|
Instr::Sub => Stmt::lol(StmtKind::Sub(count)),
|
||||||
Instr::Right => Stmt::Right(count.into()),
|
Instr::Right => Stmt::lol(StmtKind::Right(count.into())),
|
||||||
Instr::Left => Stmt::Left(count.into()),
|
Instr::Left => Stmt::lol(StmtKind::Left(count.into())),
|
||||||
Instr::Out => Stmt::Out,
|
Instr::Out => Stmt::lol(StmtKind::Out),
|
||||||
Instr::In => Stmt::In,
|
Instr::In => Stmt::lol(StmtKind::In),
|
||||||
Instr::Loop(body) => Stmt::Loop(ast_to_ir(alloc, &body)),
|
Instr::Loop(body) => Stmt::lol(StmtKind::Loop(ast_to_ir(alloc, &body))),
|
||||||
};
|
};
|
||||||
stmts.push(new_last);
|
stmts.push(new_last);
|
||||||
spans.push(start_span.until(end_span));
|
spans.push(start_span.until(end_span));
|
||||||
|
|
||||||
Ir { stmts, spans }
|
Ir { stmts }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pass_find_set_null(ir: &mut Ir<'_>) {
|
fn pass_find_set_null(ir: &mut Ir<'_>) {
|
||||||
for stmt in &mut ir.stmts {
|
for stmt in &mut ir.stmts {
|
||||||
if let Stmt::Loop(body) = stmt {
|
if let Stmt {
|
||||||
if let [Stmt::Sub(_)] = body.stmts.as_slice() {
|
kind: StmtKind::Loop(body),
|
||||||
*stmt = Stmt::SetNull;
|
..
|
||||||
|
} = stmt
|
||||||
|
{
|
||||||
|
if let [Stmt {
|
||||||
|
kind: StmtKind::Sub(_),
|
||||||
|
..
|
||||||
|
}] = body.stmts.as_slice()
|
||||||
|
{
|
||||||
|
*stmt = Stmt::lol(StmtKind::SetNull);
|
||||||
} else {
|
} else {
|
||||||
pass_find_set_null(body);
|
pass_find_set_null(body);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
pub struct Span {
|
pub struct Span {
|
||||||
start: u32,
|
start: u32,
|
||||||
len: u32,
|
len: u32,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue