compowler hawd >~<
This commit is contained in:
parent
4bdbf4c13b
commit
a6c77f6633
11
src/ir.rs
11
src/ir.rs
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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)]
|
||||||
|
Loading…
Reference in New Issue
Block a user