compiler :333333333333
This commit is contained in:
parent
d55e9b3c70
commit
4bdbf4c13b
@ -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>>,
|
||||||
|
@ -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
31
src/ir.rs
Normal 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
151
src/ir_compiler.rs
Normal 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
|
||||||
|
}])
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
12
src/sym.rs
12
src/sym.rs
@ -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,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user