diff --git a/src/checked.rs b/src/checked.rs index 23bd74b..c982e2b 100644 --- a/src/checked.rs +++ b/src/checked.rs @@ -39,6 +39,7 @@ pub enum NodeKind { params: Vec, return_typ: Type, body: Box, + id: u64, }, Return { value: Option>, diff --git a/src/checker.rs b/src/checker.rs index e898ccc..abf1931 100644 --- a/src/checker.rs +++ b/src/checker.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - use rand::random; use crate::{ @@ -46,6 +44,10 @@ impl Checker { } } + pub fn finish(self) -> Syms { + self.syms + } + pub fn check(&mut self, ast: &[parsed::Node]) -> Vec { self.fn_scan(ast); ast.iter().map(|stmt| self.check_expr(stmt)).collect() @@ -57,14 +59,14 @@ impl Checker { subject, params, return_typ, - body, + body: _, } = node { let Ok(params) = self.fn_scan_params(params) else { 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"); continue; } @@ -317,6 +319,7 @@ impl Checker { params, return_typ: *return_typ, body, + id: fn_id, }, Type::Unit, ) @@ -571,6 +574,7 @@ fn test_checker() { typ: I32, table_id: 1, }), + id: 0, }, typ: Unit, table_id: 0, diff --git a/src/ir.rs b/src/ir.rs new file mode 100644 index 0000000..aed2e30 --- /dev/null +++ b/src/ir.rs @@ -0,0 +1,31 @@ +#[derive(Clone, PartialEq, Debug)] +pub enum Data { + U8(Vec), +} + +#[derive(Clone, PartialEq, Debug)] +pub struct Fn { + pub blocks: Vec, + pub id: u64, + pub arg_count: i32, + pub local_count: i32, +} + +#[derive(Clone, PartialEq, Debug)] +pub struct Block { + pub ops: Vec, +} + +#[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, +} diff --git a/src/ir_compiler.rs b/src/ir_compiler.rs new file mode 100644 index 0000000..b4824fb --- /dev/null +++ b/src/ir_compiler.rs @@ -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, + pub entry: u64, + pub sym: Syms, +} + +struct Compiler { + syms: Syms, + fns: Vec, +} + +impl Compiler { + pub fn new(syms: Syms) -> Self { + Self { + syms, + fns: Vec::new(), + } + } + + pub fn compile(mut self, ast: &[Node]) -> Result { + 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 { + 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, i32), ()> { + let mut blocks = Vec::new(); + let mut ops = Vec::::new(); + let mut local_count = 0; + let mut local_map = HashMap::::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>(&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::::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 + }]) + ); +} diff --git a/src/main.rs b/src/main.rs index 7ec1052..77c0eeb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ mod checked; mod checker; +mod ir; +mod ir_compiler; mod itertewls; mod lexer; mod parsed; diff --git a/src/sym.rs b/src/sym.rs index 698522e..9ae9168 100644 --- a/src/sym.rs +++ b/src/sym.rs @@ -1,11 +1,14 @@ #![allow(unused_variables)] use std::collections::HashMap; +use rand::random; + use crate::checked::Type; #[derive(Clone, PartialEq, Debug)] pub struct Sym { pub id: u64, + pub uid: u64, pub typ: Type, } @@ -110,6 +113,13 @@ impl SymTable { } 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, + }, + ); } }