delete ir, dumb idea anyway
This commit is contained in:
parent
13135c7da6
commit
bded4e81b1
35
src/ir.rs
35
src/ir.rs
@ -1,35 +0,0 @@
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Fn {
|
||||
pub ops: Vec<Op>,
|
||||
pub data: Vec<Data>,
|
||||
pub id: u64,
|
||||
pub arg_count: i32,
|
||||
pub local_count: i32,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Op {
|
||||
Pop,
|
||||
PushI32(i32),
|
||||
PushU32(u32),
|
||||
PushStaticPtr(u64),
|
||||
StoreLocal(i32),
|
||||
LoadLocal(i32),
|
||||
Jump(u64),
|
||||
JumpIfFalse(u64),
|
||||
JumpIfTrue(u64),
|
||||
CallFn(u64, i32),
|
||||
CallPtr(i32),
|
||||
Return,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Data {
|
||||
pub kind: DataKind,
|
||||
pub id: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum DataKind {
|
||||
U8(Vec<u8>),
|
||||
}
|
@ -1,412 +0,0 @@
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
checked::{self, Node, NodeKind},
|
||||
ir::{Data, DataKind, Fn, Op},
|
||||
sym::Syms,
|
||||
};
|
||||
|
||||
pub struct Program {
|
||||
pub fns: Vec<Fn>,
|
||||
pub entry: u64,
|
||||
pub sym: Syms,
|
||||
}
|
||||
|
||||
struct Compiler {
|
||||
syms: Syms,
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
pub fn new(syms: Syms) -> Self {
|
||||
Self { syms }
|
||||
}
|
||||
|
||||
pub fn compile(self, ast: &[Node]) -> Result<Program, ()> {
|
||||
let fns = FnCompiler::new(&self.syms).compile_entry(ast)?;
|
||||
Ok(Program {
|
||||
fns,
|
||||
sym: self.syms,
|
||||
entry: 0,
|
||||
})
|
||||
}
|
||||
|
||||
fn error<S: Into<String>>(&mut self, msg: S) {
|
||||
println!("ir compiler: {}", msg.into());
|
||||
}
|
||||
}
|
||||
|
||||
struct FnCompiler<'syms> {
|
||||
syms: &'syms Syms,
|
||||
ops: Vec<Op>,
|
||||
data: Vec<Data>,
|
||||
fns: Vec<Fn>,
|
||||
local_count: i32,
|
||||
local_map: HashMap<u64, i32>,
|
||||
break_stack: Vec<usize>,
|
||||
}
|
||||
|
||||
impl<'syms> FnCompiler<'syms> {
|
||||
pub fn new(syms: &'syms Syms) -> Self {
|
||||
Self {
|
||||
syms,
|
||||
ops: Vec::new(),
|
||||
fns: Vec::new(),
|
||||
data: Vec::new(),
|
||||
local_count: 0,
|
||||
local_map: HashMap::new(),
|
||||
break_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_entry(mut self, ast: &[Node]) -> Result<Vec<Fn>, ()> {
|
||||
for stmt in ast {
|
||||
self.compile_stmt(stmt)?;
|
||||
if stmt.typ != checked::Type::Unit {
|
||||
self.ops.push(Op::Pop);
|
||||
}
|
||||
}
|
||||
self.fns.push(Fn {
|
||||
ops: self.ops,
|
||||
data: self.data,
|
||||
id: 0,
|
||||
arg_count: 0,
|
||||
local_count: self.local_count,
|
||||
});
|
||||
Ok(self.fns)
|
||||
}
|
||||
|
||||
pub fn compile(mut self, node: &Node) -> Result<Vec<Fn>, ()> {
|
||||
let Node {
|
||||
kind:
|
||||
NodeKind::Fn {
|
||||
subject,
|
||||
params,
|
||||
return_typ: _,
|
||||
body,
|
||||
id,
|
||||
},
|
||||
..
|
||||
} = node
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
for param in params {
|
||||
let NodeKind::Param { subject, typ } = ¶m.kind else { unreachable!() };
|
||||
let NodeKind::Id(param_id) = subject.kind else { unreachable!() };
|
||||
let sym_table = self.syms.view(body.table_id);
|
||||
let sym = sym_table.get(param_id).unwrap();
|
||||
let local_id = self.local_count;
|
||||
self.local_count += 1;
|
||||
self.local_map.insert(sym.uid, local_id);
|
||||
}
|
||||
let NodeKind::Block(body) = &body.kind else {
|
||||
unreachable!()
|
||||
};
|
||||
for stmt in body {
|
||||
self.compile_stmt(stmt)?;
|
||||
if stmt.typ != checked::Type::Unit {
|
||||
self.push(Op::Pop);
|
||||
}
|
||||
}
|
||||
self.push(Op::Return);
|
||||
self.fns.push(Fn {
|
||||
ops: self.ops,
|
||||
data: self.data,
|
||||
id: *id,
|
||||
arg_count: params.len() as i32,
|
||||
local_count: self.local_count,
|
||||
});
|
||||
Ok(self.fns)
|
||||
}
|
||||
|
||||
fn compile_stmt(&mut self, stmt: &Node) -> Result<(), ()> {
|
||||
let syms = self.syms.view(stmt.table_id);
|
||||
match &stmt.kind {
|
||||
NodeKind::Error => return Err(()),
|
||||
NodeKind::Break => {
|
||||
let addr = self.ops.len();
|
||||
self.push(Op::Jump(0));
|
||||
self.break_stack.push(addr);
|
||||
}
|
||||
NodeKind::Assign { subject, value } => {
|
||||
self.compile_expr(value)?;
|
||||
match subject.kind {
|
||||
NodeKind::Error => {
|
||||
return Err(());
|
||||
}
|
||||
NodeKind::Id(id) => {
|
||||
let sym_table = self.syms.view(stmt.table_id);
|
||||
let sym = sym_table.get(id).unwrap();
|
||||
let local_id = self.local_map.get(&sym.uid).unwrap();
|
||||
self.push(Op::StoreLocal(*local_id));
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
NodeKind::Let { subject, value } => {
|
||||
let NodeKind::Param { subject, typ: _ } = &subject.kind else { unreachable!() };
|
||||
let NodeKind::Id(subject_id) = subject.kind else { unreachable!()};
|
||||
let sym_table = self.syms.view(stmt.table_id);
|
||||
let sym = sym_table.get(subject_id).unwrap();
|
||||
let local_id = self.local_count;
|
||||
self.local_map.insert(sym.uid, local_id);
|
||||
self.local_count += 1;
|
||||
self.compile_expr(value)?;
|
||||
self.push(Op::StoreLocal(local_id));
|
||||
}
|
||||
NodeKind::Fn { subject, .. } => {
|
||||
let mut compiled_fn = FnCompiler::new(self.syms).compile(stmt)?;
|
||||
self.fns.append(&mut compiled_fn);
|
||||
let NodeKind::Id(subject_id) = subject.kind else { unreachable!()};
|
||||
let sym_table = self.syms.view(stmt.table_id);
|
||||
let sym = sym_table.get(subject_id).unwrap();
|
||||
self.local_map.insert(sym.uid, self.local_count);
|
||||
self.local_count += 1;
|
||||
}
|
||||
NodeKind::Return { value } => {
|
||||
self.ops.push(Op::Return);
|
||||
}
|
||||
_ => {
|
||||
self.compile_expr(stmt)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_expr(&mut self, expr: &Node) -> Result<(), ()> {
|
||||
let syms = self.syms.view(expr.table_id);
|
||||
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.push(Op::LoadLocal(*local_id));
|
||||
}
|
||||
NodeKind::Int(value) => match expr.typ {
|
||||
checked::Type::I32 => self.push(Op::PushI32(*value as i32)),
|
||||
checked::Type::U32 => self.push(Op::PushU32(*value as u32)),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
NodeKind::Str(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) => {
|
||||
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.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.push(Op::CallFn(id, args.len() as i32));
|
||||
}
|
||||
_ => {
|
||||
self.push(Op::CallPtr(args.len() as i32));
|
||||
}
|
||||
}
|
||||
}
|
||||
NodeKind::If {
|
||||
cond,
|
||||
truthy,
|
||||
falsy,
|
||||
} => {
|
||||
self.compile_expr(cond)?;
|
||||
let l0 = self.ops.len();
|
||||
self.push(Op::JumpIfFalse(0));
|
||||
self.compile_expr(truthy)?;
|
||||
let l1 = self.ops.len();
|
||||
if let Op::JumpIfFalse(ref mut addr) = self.ops[l0] {
|
||||
*addr = l1 as u64;
|
||||
}
|
||||
if let Some(falsy) = falsy {
|
||||
self.push(Op::Jump(0));
|
||||
self.compile_expr(falsy)?;
|
||||
let l2 = self.ops.len();
|
||||
if let Op::Jump(ref mut addr) = self.ops[l1] {
|
||||
*addr = l2 as u64;
|
||||
}
|
||||
}
|
||||
}
|
||||
NodeKind::Loop { body } => {
|
||||
let l0 = self.ops.len() as u64;
|
||||
self.compile_expr(body)?;
|
||||
let l1 = self.ops.len() as u64;
|
||||
for op in self.break_stack.drain(..) {
|
||||
let Op::Jump(ref mut addr) = self.ops[op] else { unreachable!() };
|
||||
*addr = l1;
|
||||
}
|
||||
self.push(Op::Jump(l0));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn push(&mut self, op: Op) {
|
||||
self.ops.push(op);
|
||||
}
|
||||
|
||||
fn error<S: Into<String>>(&mut self, msg: S) {
|
||||
println!("ir compiler: {}", msg.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compiler() {
|
||||
use crate::checker::{Checker, IdGen};
|
||||
use crate::parser::Parser;
|
||||
use Op::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
struct SeqIdGen(u64);
|
||||
impl IdGen for SeqIdGen {
|
||||
fn new() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
fn gen(&mut self) -> u64 {
|
||||
let v = self.0;
|
||||
self.0 += 1;
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
let compile = |text| {
|
||||
let mut checker = Checker::<SeqIdGen>::new_with_fn_id_gen();
|
||||
let checked = checker.check(&Parser::new(text).parse());
|
||||
let syms = checker.finish();
|
||||
let compiled = Compiler::new(syms).compile(&checked);
|
||||
compiled.map(|program| program.fns)
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
compile("fn test(a: i32) -> i32 { a; } test(123);"),
|
||||
Ok(vec![
|
||||
Fn {
|
||||
ops: vec![LoadLocal(0), Pop],
|
||||
data: vec![],
|
||||
id: 0,
|
||||
arg_count: 1,
|
||||
local_count: 1
|
||||
},
|
||||
Fn {
|
||||
ops: vec![LoadLocal(0), PushI32(123), CallFn(0, 1), Pop],
|
||||
data: vec![],
|
||||
id: 0,
|
||||
arg_count: 0,
|
||||
local_count: 1
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compile("let a = 5; let b = 3; a; b; a = b;"),
|
||||
Ok(vec![Fn {
|
||||
ops: vec![
|
||||
PushI32(5),
|
||||
StoreLocal(0),
|
||||
PushI32(3),
|
||||
StoreLocal(1),
|
||||
LoadLocal(0),
|
||||
Pop,
|
||||
LoadLocal(1),
|
||||
Pop,
|
||||
LoadLocal(1),
|
||||
StoreLocal(0),
|
||||
],
|
||||
data: vec![],
|
||||
id: 0,
|
||||
arg_count: 0,
|
||||
local_count: 2,
|
||||
}])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compile("let a = \"hello\";"),
|
||||
Ok(vec![Fn {
|
||||
ops: vec![PushStaticPtr(0), StoreLocal(0)],
|
||||
data: vec![Data {
|
||||
kind: DataKind::U8(vec![104, 101, 108, 108, 111]),
|
||||
id: 0
|
||||
}],
|
||||
id: 0,
|
||||
arg_count: 0,
|
||||
local_count: 1
|
||||
}])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compile("if 1 { 2; } if 1 { 2; } else { 3; }"),
|
||||
Ok(vec![Fn {
|
||||
ops: vec![
|
||||
PushI32(1),
|
||||
JumpIfFalse(3),
|
||||
PushI32(2),
|
||||
PushI32(1),
|
||||
JumpIfFalse(6),
|
||||
PushI32(2),
|
||||
Jump(8),
|
||||
PushI32(3),
|
||||
Pop,
|
||||
],
|
||||
data: vec![],
|
||||
id: 0,
|
||||
arg_count: 0,
|
||||
local_count: 0
|
||||
}])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compile("let a = if 1 { 2; } else { 3; };"),
|
||||
Ok(vec![Fn {
|
||||
ops: vec![
|
||||
PushI32(1),
|
||||
JumpIfFalse(3),
|
||||
PushI32(2),
|
||||
Jump(5),
|
||||
PushI32(3),
|
||||
StoreLocal(0),
|
||||
],
|
||||
data: vec![],
|
||||
id: 0,
|
||||
arg_count: 0,
|
||||
local_count: 1
|
||||
}])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compile("loop { break; }"),
|
||||
Ok(vec![Fn {
|
||||
ops: vec![Jump(1), Jump(0)],
|
||||
data: vec![],
|
||||
id: 0,
|
||||
arg_count: 0,
|
||||
local_count: 0,
|
||||
},])
|
||||
);
|
||||
}
|
26
src/vm.rs
26
src/vm.rs
@ -1,26 +0,0 @@
|
||||
use crate::ir::Fn;
|
||||
|
||||
enum Value {
|
||||
I32(i32),
|
||||
U32(u32),
|
||||
StaticPtr(u32),
|
||||
Fn(u32),
|
||||
}
|
||||
|
||||
struct Vm<'a> {
|
||||
fns: &'a Vec<Fn>,
|
||||
call_stack: Vec<(u64, i32)>,
|
||||
value_stack: Vec<Value>,
|
||||
}
|
||||
|
||||
impl<'a> Vm<'a> {
|
||||
pub fn new(fns: &'a Vec<Fn>) -> Self {
|
||||
Self {
|
||||
fns,
|
||||
call_stack: Vec::new(),
|
||||
value_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self, entry: u64) {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user