spans and tests

This commit is contained in:
nora 2022-04-12 21:49:59 +02:00
parent e82b14b09a
commit 5634330287
10 changed files with 300 additions and 112 deletions

View file

@ -1,7 +1,11 @@
use crate::parse::Instr;
use crate::parse::{Instr, Span};
use bumpalo::Bump;
pub type Ir<'ir> = Vec<Stmt<'ir>, &'ir Bump>;
#[derive(Debug)]
pub struct Ir<'ir> {
pub stmts: Vec<Stmt<'ir>, &'ir Bump>,
pub spans: Vec<Span, &'ir Bump>,
}
#[derive(Debug)]
pub enum Stmt<'ir> {
@ -15,23 +19,27 @@ pub enum Stmt<'ir> {
SetNull,
}
pub fn optimize<'ir>(alloc: &'ir Bump, instrs: &[Instr<'_>]) -> Ir<'ir> {
pub fn optimize<'ir>(alloc: &'ir Bump, instrs: &[(Instr<'_>, Span)]) -> Ir<'ir> {
let mut ir = ast_to_ir(alloc, instrs);
pass_find_set_null(&mut ir);
ir
}
fn ast_to_ir<'ir>(alloc: &'ir Bump, ast: &[Instr<'_>]) -> Ir<'ir> {
let mut ir = Vec::new_in(alloc);
fn ast_to_ir<'ir>(alloc: &'ir Bump, ast: &[(Instr<'_>, Span)]) -> Ir<'ir> {
let mut stmts = Vec::new_in(alloc);
let mut spans = Vec::new_in(alloc);
let mut instr_iter = ast.iter();
let Some(first) = instr_iter.next() else { return ir; };
let Some(first) = instr_iter.next() else {
return Ir { stmts, spans: Vec::new_in(alloc) };
};
let mut last = first;
let mut last = &first.0;
let mut last_span = first.1;
let mut count = 1;
for next in instr_iter {
for (next, next_span) in instr_iter {
match last {
Instr::Add | Instr::Sub | Instr::Right | Instr::Left if last == next => {
count += 1;
@ -47,8 +55,10 @@ fn ast_to_ir<'ir>(alloc: &'ir Bump, ast: &[Instr<'_>]) -> Ir<'ir> {
Instr::In => Stmt::In,
Instr::Loop(body) => Stmt::Loop(ast_to_ir(alloc, body)),
};
ir.push(new_last);
stmts.push(new_last);
spans.push(last_span.until(*next_span));
last = next;
last_span = *next_span;
count = 1;
}
}
@ -61,17 +71,18 @@ fn ast_to_ir<'ir>(alloc: &'ir Bump, ast: &[Instr<'_>]) -> Ir<'ir> {
Instr::Left => Stmt::Left(count.into()),
Instr::Out => Stmt::Out,
Instr::In => Stmt::In,
Instr::Loop(body) => Stmt::Loop(ast_to_ir(alloc, body)),
Instr::Loop(body) => Stmt::Loop(ast_to_ir(alloc, &body)),
};
ir.push(new_last);
stmts.push(new_last);
spans.push(last_span);
ir
Ir { stmts, spans }
}
fn pass_find_set_null(ir: &mut Ir<'_>) {
for stmt in ir {
for stmt in &mut ir.stmts {
if let Stmt::Loop(body) = stmt {
if let [Stmt::Sub(_)] = body.as_slice() {
if let [Stmt::Sub(_)] = body.stmts.as_slice() {
*stmt = Stmt::SetNull;
} else {
pass_find_set_null(body);