compiler :333333333333

This commit is contained in:
SimonFJ20 2024-05-30 15:30:27 +02:00
parent d55e9b3c70
commit 4bdbf4c13b
6 changed files with 204 additions and 5 deletions

View File

@ -39,6 +39,7 @@ pub enum NodeKind {
params: Vec<Node>, params: Vec<Node>,
return_typ: Type, return_typ: Type,
body: Box<Node>, body: Box<Node>,
id: u64,
}, },
Return { Return {
value: Option<Box<Node>>, value: Option<Box<Node>>,

View File

@ -1,5 +1,3 @@
#![allow(unused_variables)]
use rand::random; use rand::random;
use crate::{ use crate::{
@ -46,6 +44,10 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
} }
} }
pub fn finish(self) -> Syms {
self.syms
}
pub fn check(&mut self, ast: &[parsed::Node]) -> Vec<Node> { pub fn check(&mut self, ast: &[parsed::Node]) -> Vec<Node> {
self.fn_scan(ast); self.fn_scan(ast);
ast.iter().map(|stmt| self.check_expr(stmt)).collect() ast.iter().map(|stmt| self.check_expr(stmt)).collect()
@ -57,14 +59,14 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
subject, subject,
params, params,
return_typ, return_typ,
body, body: _,
} = node } = node
{ {
let Ok(params) = self.fn_scan_params(params) else { let Ok(params) = self.fn_scan_params(params) else {
continue; continue;
}; };
if let Some(id) = params.iter().map(|(id, _)| *id).find_first_duplicate() { if let Some(_) = params.iter().map(|(id, _)| *id).find_first_duplicate() {
self.error("redefinition param"); self.error("redefinition param");
continue; continue;
} }
@ -317,6 +319,7 @@ impl<FnIdGen: IdGen> Checker<FnIdGen> {
params, params,
return_typ: *return_typ, return_typ: *return_typ,
body, body,
id: fn_id,
}, },
Type::Unit, Type::Unit,
) )
@ -571,6 +574,7 @@ fn test_checker() {
typ: I32, typ: I32,
table_id: 1, table_id: 1,
}), }),
id: 0,
}, },
typ: Unit, typ: Unit,
table_id: 0, table_id: 0,

31
src/ir.rs Normal file
View File

@ -0,0 +1,31 @@
#[derive(Clone, PartialEq, Debug)]
pub enum Data {
U8(Vec<u8>),
}
#[derive(Clone, PartialEq, Debug)]
pub struct Fn {
pub blocks: Vec<Block>,
pub id: u64,
pub arg_count: i32,
pub local_count: i32,
}
#[derive(Clone, PartialEq, Debug)]
pub struct Block {
pub ops: Vec<Op>,
}
#[derive(Clone, PartialEq, Debug)]
pub enum Op {
Pop,
PushI32(i32),
PushU32(u32),
PushStaticPtr(u64),
StoreLocal(i32),
LoadLocal(i32),
Jump(u64),
JumpIfTrue(u64),
Call(u64, i32),
Return,
}

151
src/ir_compiler.rs Normal file
View File

@ -0,0 +1,151 @@
#![allow(unused_variables)]
use std::collections::HashMap;
use crate::{
checked::{self, Node, NodeKind},
ir::{Block, Fn, Op},
sym::Syms,
};
pub struct IrProgram {
pub fns: Vec<Fn>,
pub entry: u64,
pub sym: Syms,
}
struct Compiler {
syms: Syms,
fns: Vec<Fn>,
}
impl Compiler {
pub fn new(syms: Syms) -> Self {
Self {
syms,
fns: Vec::new(),
}
}
pub fn compile(mut self, ast: &[Node]) -> Result<IrProgram, ()> {
let (blocks, local_count) = self.compile_fn_body(ast)?;
let entry_fn = Fn {
blocks,
id: 0,
arg_count: 0,
local_count,
};
self.fns.push(entry_fn);
Ok(IrProgram {
fns: self.fns,
sym: self.syms,
entry: 0,
})
}
fn compile_fn(&mut self, node: &Node) -> Result<Fn, ()> {
let Node { kind: NodeKind::Fn { subject: _, params, return_typ: _, body, id }, .. } = node else {
unreachable!()
};
let NodeKind::Block(body) = &body.kind else { unreachable!() };
let (blocks, local_count) = self.compile_fn_body(body)?;
Ok(Fn {
blocks,
id: *id,
arg_count: params.len() as i32,
local_count,
})
}
fn compile_fn_body(&mut self, body: &[Node]) -> Result<(Vec<Block>, i32), ()> {
let mut blocks = Vec::new();
let mut ops = Vec::<Op>::new();
let mut local_count = 0;
let mut local_map = HashMap::<u64, i32>::new();
for node in body {
let syms = self.syms.view(node.table_id);
match &node.kind {
NodeKind::Error => return Err(()),
NodeKind::Id(id) => {
let sym = syms.get(*id).unwrap();
let local_id = local_map.get(&sym.uid).unwrap();
ops.push(Op::LoadLocal(*local_id));
}
NodeKind::Int(value) => match node.typ {
checked::Type::I32 => ops.push(Op::PushI32(*value as i32)),
checked::Type::U32 => ops.push(Op::PushU32(*value as u32)),
_ => unreachable!(),
},
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!(),
}
}
blocks.push(Block { ops });
Ok((blocks, local_count))
}
fn error<S: Into<String>>(&mut self, msg: S) {
println!("ir compiler: {}", msg.into());
}
}
#[test]
fn test_checker() {
use crate::checker::{Checker, IdGen};
use crate::parser::Parser;
use pretty_assertions::assert_eq;
use Op::*;
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("123;"),
Ok(vec![Fn {
blocks: vec![Block {
ops: vec![PushI32(123)]
}],
id: 0,
arg_count: 0,
local_count: 0
}])
);
}

View File

@ -2,6 +2,8 @@
mod checked; mod checked;
mod checker; mod checker;
mod ir;
mod ir_compiler;
mod itertewls; mod itertewls;
mod lexer; mod lexer;
mod parsed; mod parsed;

View File

@ -1,11 +1,14 @@
#![allow(unused_variables)] #![allow(unused_variables)]
use std::collections::HashMap; use std::collections::HashMap;
use rand::random;
use crate::checked::Type; use crate::checked::Type;
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub struct Sym { pub struct Sym {
pub id: u64, pub id: u64,
pub uid: u64,
pub typ: Type, pub typ: Type,
} }
@ -110,6 +113,13 @@ impl SymTable {
} }
pub fn define(&mut self, id: u64, typ: Type) { pub fn define(&mut self, id: u64, typ: Type) {
self.map.insert(id, Sym { id, typ }); self.map.insert(
id,
Sym {
id,
uid: random(),
typ,
},
);
} }
} }