things that don't work but sound fun

This commit is contained in:
nora 2022-04-13 22:36:48 +02:00
parent 799b1591e0
commit eda2476021
6 changed files with 256 additions and 191 deletions

94
rust2/src/codegen.rs Normal file
View 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!()
}

View 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
}
}

View file

@ -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);
}
}

View file

@ -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);
} }
} }

View file

@ -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);
} }

View file

@ -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,