compowler hawd >~<

This commit is contained in:
SimonFJ20 2024-05-31 00:41:02 +02:00
parent 4bdbf4c13b
commit a6c77f6633
2 changed files with 227 additions and 69 deletions

View File

@ -1,5 +1,11 @@
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub enum Data { pub struct Data {
pub kind: DataKind,
pub id: u64,
}
#[derive(Clone, PartialEq, Debug)]
pub enum DataKind {
U8(Vec<u8>), U8(Vec<u8>),
} }
@ -26,6 +32,7 @@ pub enum Op {
LoadLocal(i32), LoadLocal(i32),
Jump(u64), Jump(u64),
JumpIfTrue(u64), JumpIfTrue(u64),
Call(u64, i32), CallFn(u64, i32),
CallPtr(i32),
Return, Return,
} }

View File

@ -4,104 +4,255 @@ use std::collections::HashMap;
use crate::{ use crate::{
checked::{self, Node, NodeKind}, checked::{self, Node, NodeKind},
ir::{Block, Fn, Op}, ir::{Block, Data, DataKind, Fn, Op},
sym::Syms, sym::Syms,
}; };
pub struct IrProgram { pub struct Program {
pub fns: Vec<Fn>, pub fns: Vec<Fn>,
pub data: Vec<Data>,
pub entry: u64, pub entry: u64,
pub sym: Syms, pub sym: Syms,
} }
struct Compiler { struct Compiler {
syms: Syms, syms: Syms,
fns: Vec<Fn>,
} }
impl Compiler { impl Compiler {
pub fn new(syms: Syms) -> Self { pub fn new(syms: Syms) -> Self {
Self { Self { syms }
syms,
fns: Vec::new(),
}
} }
pub fn compile(mut self, ast: &[Node]) -> Result<IrProgram, ()> { pub fn compile(self, ast: &[Node]) -> Result<Program, ()> {
let (blocks, local_count) = self.compile_fn_body(ast)?; let (fns, data) = FnCompiler::new(&self.syms).compile_entry(ast)?;
let entry_fn = Fn { Ok(Program {
blocks, fns,
id: 0, data,
arg_count: 0,
local_count,
};
self.fns.push(entry_fn);
Ok(IrProgram {
fns: self.fns,
sym: self.syms, sym: self.syms,
entry: 0, entry: 0,
}) })
} }
fn compile_fn(&mut self, node: &Node) -> Result<Fn, ()> { fn error<S: Into<String>>(&mut self, msg: S) {
let Node { kind: NodeKind::Fn { subject: _, params, return_typ: _, body, id }, .. } = node else { println!("ir compiler: {}", msg.into());
}
}
struct FnCompiler<'syms> {
syms: &'syms Syms,
ops: Vec<Op>,
local_count: i32,
local_map: HashMap<u64, i32>,
fns: Vec<Fn>,
data: Vec<Data>,
}
impl<'syms> FnCompiler<'syms> {
pub fn new(syms: &'syms Syms) -> Self {
Self {
syms,
ops: Vec::new(),
local_count: 0,
local_map: HashMap::new(),
fns: Vec::new(),
data: Vec::new(),
}
}
pub fn compile_entry(mut self, ast: &[Node]) -> Result<(Vec<Fn>, Vec<Data>), ()> {
let mut blocks = Vec::new();
for stmt in ast {
blocks.append(&mut self.compile_stmt(stmt)?);
if stmt.typ != checked::Type::Unit {
self.ops.push(Op::Pop);
}
}
self.fns.push(Fn {
blocks,
id: 0,
arg_count: 0,
local_count: self.local_count,
});
Ok((self.fns, self.data))
}
pub fn compile(mut self, node: &Node) -> Result<Fn, ()> {
let Node {
kind:
NodeKind::Fn {
subject: _,
params,
return_typ: _,
body,
id,
},
..
} = node
else {
unreachable!() unreachable!()
}; };
let NodeKind::Block(body) = &body.kind else { unreachable!() }; let NodeKind::Block(body) = &body.kind else {
let (blocks, local_count) = self.compile_fn_body(body)?; unreachable!()
};
let mut blocks = Vec::new();
for stmt in body {
blocks.append(&mut self.compile_stmt(stmt)?);
if stmt.typ != checked::Type::Unit {
self.ops.push(Op::Pop);
}
}
self.push_ops(&mut blocks);
Ok(Fn { Ok(Fn {
blocks, blocks,
id: *id, id: *id,
arg_count: params.len() as i32, arg_count: params.len() as i32,
local_count, local_count: self.local_count,
}) })
} }
fn compile_fn_body(&mut self, body: &[Node]) -> Result<(Vec<Block>, i32), ()> { pub fn compile_stmt(&mut self, stmt: &Node) -> Result<Vec<Block>, ()> {
let syms = self.syms.view(stmt.table_id);
let mut blocks = Vec::new(); let mut blocks = Vec::new();
let mut ops = Vec::<Op>::new(); match &stmt.kind {
let mut local_count = 0; NodeKind::Error => return Err(()),
let mut local_map = HashMap::<u64, i32>::new(); NodeKind::Break => todo!(),
for node in body { NodeKind::Assign { subject, value } => todo!(),
let syms = self.syms.view(node.table_id); NodeKind::Let { subject, value } => todo!(),
match &node.kind { NodeKind::Fn {
NodeKind::Error => return Err(()), subject,
NodeKind::Id(id) => { params,
let sym = syms.get(*id).unwrap(); return_typ,
let local_id = local_map.get(&sym.uid).unwrap(); body,
ops.push(Op::LoadLocal(*local_id)); id,
} } => todo!(),
NodeKind::Int(value) => match node.typ { NodeKind::Return { value } => {
checked::Type::I32 => ops.push(Op::PushI32(*value as i32)), self.ops.push(Op::Return);
checked::Type::U32 => ops.push(Op::PushU32(*value as u32)), }
_ => unreachable!(), _ => {
}, blocks.append(&mut self.compile_expr(stmt)?);
NodeKind::String(_) => todo!(),
NodeKind::Group(_) => todo!(),
NodeKind::Block(_) => todo!(),
NodeKind::Call { subject, args } => todo!(),
NodeKind::If {
cond,
truthy,
falsy,
} => todo!(),
NodeKind::Loop { body } => todo!(),
NodeKind::Break => todo!(),
NodeKind::Assign { subject, value } => todo!(),
NodeKind::Let { subject, value } => todo!(),
NodeKind::Fn {
subject,
params,
return_typ,
body,
id,
} => todo!(),
NodeKind::Return { value } => todo!(),
NodeKind::Param { subject, typ } => todo!(),
} }
} }
if stmt.typ != checked::Type::Unit {
self.ops.push(Op::Pop);
}
Ok(blocks)
}
fn compile_expr(&mut self, expr: &Node) -> Result<Vec<Block>, ()> {
let syms = self.syms.view(expr.table_id);
let mut blocks = Vec::new();
match &expr.kind {
NodeKind::Error => return Err(()),
NodeKind::Id(id) => {
let sym = syms.get(*id).unwrap();
let local_id = self.local_map.get(&sym.uid).unwrap();
self.ops.push(Op::LoadLocal(*local_id));
}
NodeKind::Int(value) => match expr.typ {
checked::Type::I32 => self.ops.push(Op::PushI32(*value as i32)),
checked::Type::U32 => self.ops.push(Op::PushU32(*value as u32)),
_ => unreachable!(),
},
NodeKind::String(value) => {
let id = self.data.len() as u64;
let bytes = value.bytes().collect();
self.data.push(Data {
kind: DataKind::U8(bytes),
id,
});
self.ops.push(Op::PushStaticPtr(id));
}
NodeKind::Group(expr) => {
blocks.append(&mut self.compile_expr(expr)?);
}
NodeKind::Block(stmts) => {
let mut last_typ = None;
for stmt in stmts {
if last_typ.filter(|typ| *typ != checked::Type::Unit).is_some() {
self.ops.push(Op::Pop);
}
last_typ = Some(stmt.typ.clone());
self.compile_stmt(stmt)?;
}
}
NodeKind::Call { subject, args } => {
self.compile_expr(subject)?;
for arg in args {
self.compile_expr(arg)?;
}
match subject.typ {
checked::Type::Fn {
id,
params: _,
return_typ: _,
} => {
self.ops.push(Op::CallFn(id, args.len() as i32));
}
_ => {
self.ops.push(Op::CallPtr(args.len() as i32));
}
}
}
NodeKind::If {
cond,
truthy,
falsy,
} => {
self.compile_expr(cond)?;
let cond_idx = blocks.len();
self.push_ops(&mut blocks);
match falsy {
Some(falsy) => {
let truthy_first_idx = blocks.len() as u64;
let mut truthy = self.compile_expr(truthy)?;
let truthy_last_idx = blocks.len();
self.push_ops(&mut truthy);
blocks.append(&mut truthy);
let falsy_first_idx = blocks.len() as u64;
let mut falsy = self.compile_expr(falsy)?;
let falsy_last_idx = blocks.len();
self.push_ops(&mut falsy);
blocks.append(&mut falsy);
let after_idx = blocks.len() as u64;
blocks[cond_idx].ops.push(Op::JumpIfTrue(truthy_first_idx));
blocks[cond_idx].ops.push(Op::Jump(falsy_first_idx));
blocks[truthy_last_idx].ops.push(Op::Jump(after_idx));
blocks[falsy_last_idx].ops.push(Op::Jump(after_idx));
}
None => {
let truthy_first_idx = blocks.len() as u64;
let mut truthy = self.compile_expr(truthy)?;
let truthy_last_idx = blocks.len();
self.push_ops(&mut truthy);
blocks.append(&mut truthy);
let after_idx = blocks.len() as u64;
blocks[cond_idx].ops.push(Op::JumpIfTrue(truthy_first_idx));
blocks[cond_idx].ops.push(Op::Jump(after_idx));
blocks[truthy_last_idx].ops.push(Op::Jump(after_idx));
}
}
}
NodeKind::Loop { body } => {
let body = self.compile_expr(body)?;
let body_idx = blocks.len();
}
_ => unreachable!(),
}
self.push_ops(&mut blocks);
Ok(blocks)
}
fn push_ops(&mut self, blocks: &mut Vec<Block>) {
let mut ops = Vec::new();
std::mem::swap(&mut self.ops, &mut ops);
blocks.push(Block { ops }); blocks.push(Block { ops });
Ok((blocks, local_count))
} }
fn error<S: Into<String>>(&mut self, msg: S) { fn error<S: Into<String>>(&mut self, msg: S) {
@ -110,7 +261,7 @@ impl Compiler {
} }
#[test] #[test]
fn test_checker() { fn test_compiler() {
use crate::checker::{Checker, IdGen}; use crate::checker::{Checker, IdGen};
use crate::parser::Parser; use crate::parser::Parser;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
@ -134,11 +285,11 @@ fn test_checker() {
let checked = checker.check(&Parser::new(text).parse()); let checked = checker.check(&Parser::new(text).parse());
let syms = checker.finish(); let syms = checker.finish();
let compiled = Compiler::new(syms).compile(&checked); let compiled = Compiler::new(syms).compile(&checked);
compiled.map(|program| program.fns) compiled
}; };
assert_eq!( assert_eq!(
compile("123;"), compile("123;").map(|program| program.fns),
Ok(vec![Fn { Ok(vec![Fn {
blocks: vec![Block { blocks: vec![Block {
ops: vec![PushI32(123)] ops: vec![PushI32(123)]