delete checker

This commit is contained in:
SimonFJ20 2024-08-28 21:32:17 +02:00
parent 1331ba1009
commit 012c01e537
4 changed files with 21 additions and 737 deletions

View File

@ -1,65 +0,0 @@
#[derive(Clone, PartialEq, Debug)]
pub struct Node {
pub kind: NodeKind,
pub typ: Type,
pub table_id: usize,
}
#[derive(Clone, PartialEq, Debug)]
pub enum NodeKind {
Error,
Id(u64),
Int(i64),
Str(String),
Group(Box<Node>),
Block(Vec<Node>),
Call {
subject: Box<Node>,
args: Vec<Node>,
},
If {
cond: Box<Node>,
truthy: Box<Node>,
falsy: Option<Box<Node>>,
},
Loop {
body: Box<Node>,
},
Break,
Assign {
subject: Box<Node>,
value: Box<Node>,
},
Let {
subject: Box<Node>,
value: Box<Node>,
},
Fn {
subject: Box<Node>,
params: Vec<Node>,
return_typ: Type,
body: Box<Node>,
id: u64,
},
Return {
value: Option<Box<Node>>,
},
Param {
subject: Box<Node>,
typ: Option<Type>,
},
}
#[derive(Clone, PartialEq, Debug)]
pub enum Type {
Error,
Unit,
I32,
U32,
Str,
Fn {
id: u64,
params: Vec<Type>,
return_typ: Box<Type>,
},
}

View File

@ -1,647 +0,0 @@
use std::{rc::Rc, sync::Mutex};
use rand::random;
use crate::{
checked::{Node, NodeKind, Type},
parsed,
pos::{Error, ErrorAcc, Pos},
sym::Syms,
util::{hash, Itertewls},
};
pub trait IdGen {
fn new() -> Self;
fn gen(&mut self) -> u64;
}
pub struct RandIdGen;
impl IdGen for RandIdGen {
fn new() -> Self {
Self
}
fn gen(&mut self) -> u64 {
random()
}
}
pub struct Checker<FnIdGen: IdGen = RandIdGen> {
syms: Syms,
fn_id_gen: FnIdGen,
error_acc: Rc<Mutex<ErrorAcc>>,
}
impl Checker {
pub fn new(error_acc: Rc<Mutex<ErrorAcc>>) -> Self {
Self {
syms: Syms::new(),
fn_id_gen: RandIdGen::new(),
error_acc,
}
}
}
impl<FnIdGen: IdGen> Checker<FnIdGen> {
pub fn new_with_fn_id_gen(error_acc: Rc<Mutex<ErrorAcc>>) -> Self {
Self {
syms: Syms::new(),
fn_id_gen: FnIdGen::new(),
error_acc,
}
}
pub fn finish(self) -> Syms {
self.syms
}
pub fn check(&mut self, ast: &[parsed::Node]) -> Vec<Node> {
self.fn_scan(ast);
ast.iter().map(|stmt| self.check_expr(stmt)).collect()
}
fn fn_scan(&mut self, ast: &[parsed::Node]) {
for node in ast {
let pos = node.pos.clone();
if let parsed::NodeKind::Fn {
subject,
params,
return_typ,
body: _,
} = &node.kind
{
let Ok(params) = self.fn_scan_params(&params) else {
continue;
};
if let Some(_) = params.iter().map(|(id, _)| *id).find_first_duplicate() {
self.error("redefinition param", pos.clone());
continue;
}
let params = params
.into_iter()
.map(|(_, param)| {
let NodeKind::Param { subject: _, typ } = param.kind else {unreachable!()};
typ.as_ref().cloned().unwrap()
})
.collect::<Vec<_>>();
let parsed::NodeKind::Id(id) = subject.as_ref().kind else { unreachable!() };
if self.syms.defined_locally(id) {
self.error("redefinition fn", pos.clone());
continue;
}
let return_typ = self.check_type(&return_typ);
let typ = Type::Fn {
id: self.fn_id_gen.gen(),
params,
return_typ: Box::new(return_typ),
};
self.syms.define(id, typ.clone());
}
}
}
fn fn_scan_params(&self, params: &[parsed::Node]) -> Result<Vec<(u64, Node)>, ()> {
params
.iter()
.map(|param| {
let parsed::NodeKind::Param { subject, typ } = &param.kind else { unreachable!() };
let parsed::NodeKind::Id(id) = subject.as_ref().kind else { unreachable!() };
let typ = self.check_type(typ.as_ref().ok_or(())?);
Ok((
id,
self.node(
NodeKind::Param {
subject: Box::new(self.node(NodeKind::Id(id), Type::Unit)),
typ: Some(typ),
},
Type::Unit,
),
))
})
.collect::<Result<Vec<_>, _>>()
}
fn check_expr(&mut self, node: &parsed::Node) -> Node {
let pos = node.pos.clone();
match &node.kind {
parsed::NodeKind::Error => self.node(NodeKind::Error, Type::Unit),
parsed::NodeKind::Id(id) => {
let Some(sym) = self.syms.get(*id) else {
self.error("undefined >~<", pos.clone());
return self.node(NodeKind::Error, Type::Error);
};
self.node(NodeKind::Id(*id), sym.typ.clone())
}
parsed::NodeKind::Int(value) => self.node(
NodeKind::Int(*value),
if *value > i32::MAX as i64 {
Type::U32
} else {
Type::I32
},
),
parsed::NodeKind::Str(value) => self.node(NodeKind::Str(value.clone()), Type::Str),
parsed::NodeKind::Group(expr) => {
let expr = self.check_expr(&expr);
let typ = expr.typ.clone();
self.node(NodeKind::Group(Box::new(expr)), typ)
}
parsed::NodeKind::Block(stmts) => {
self.syms.enter_scope();
let stmts = stmts
.iter()
.map(|stmt| self.check_expr(stmt))
.collect::<Vec<_>>();
self.syms.leave_scope().unwrap();
let typ = stmts
.last()
.map(|stmt| stmt.typ.clone())
.unwrap_or(Type::Unit);
self.node(NodeKind::Block(stmts), typ)
}
parsed::NodeKind::Call { subject, args } => {
let subject = Box::new(self.check_expr(&subject));
let args = args
.iter()
.map(|arg| self.check_expr(arg))
.collect::<Vec<_>>();
let typ = 'br: {
match subject.typ.clone() {
Type::Fn {
id: _,
params,
return_typ,
} => {
if args.len() != params.len() {
self.error("too few/many args", pos.clone());
break 'br Type::Error;
}
if args
.iter()
.zip(params.clone())
.map(|(arg, param)| self.compatible(&arg.typ, &param))
.any(|is_compatible| !is_compatible)
{
self.error("incorrect args", pos.clone());
break 'br Type::Error;
}
*return_typ
}
_ => {
self.error("not a function", pos.clone());
Type::Error
}
}
};
self.node(NodeKind::Call { subject, args }, typ)
}
parsed::NodeKind::If {
cond,
truthy,
falsy,
} => {
let cond = Box::new(self.check_expr(&cond));
let truthy = Box::new(self.check_expr(&truthy));
let falsy = falsy.as_ref().map(|block| Box::new(self.check_expr(block)));
let typ = 'br: {
match falsy.as_ref().map(|block| block.typ.clone()) {
Some(falsy_typ) => {
if !self.compatible(&truthy.typ, &falsy_typ) {
self.error("incompatible types #2", pos.clone());
break 'br Type::Error;
}
falsy_typ
}
None => Type::Unit,
}
};
self.node(
NodeKind::If {
cond,
truthy,
falsy,
},
typ,
)
}
parsed::NodeKind::Loop { body } => {
self.syms.enter_scope();
let body = Box::new(self.check_expr(&body));
let typ = body.typ.clone();
self.node(NodeKind::Loop { body }, typ)
}
parsed::NodeKind::Break => self.node(NodeKind::Break, Type::Unit),
parsed::NodeKind::Assign { subject, value } => {
let subject = Box::new(self.check_expr(&subject));
let value = Box::new(self.check_expr(&value));
match subject.kind {
NodeKind::Error => {
return *subject;
}
NodeKind::Id(_) => {}
_ => {
self.error("cannot assign to expr", pos.clone());
return self.node(NodeKind::Error, Type::Error);
}
}
let _typ = if !self.compatible(&subject.typ, &value.typ) {
self.error("incompatible types #3", pos.clone());
Type::Error
} else {
subject.typ.clone()
};
self.node(NodeKind::Assign { subject, value }, Type::Unit)
}
parsed::NodeKind::Let { subject, value } => {
let (subject, subject_typ) = match &subject.as_ref().kind {
parsed::NodeKind::Param { subject, typ } => {
(subject, typ.as_ref().map(|typ| self.check_type(typ)))
}
_ => unreachable!(),
};
let value = Box::new(self.check_expr(&value));
let typ = value.typ.clone();
if subject_typ
.as_ref()
.map(|subject_typ| !self.compatible(subject_typ, &typ))
.unwrap_or(false)
{
self.error("incompatible types #1", pos.clone());
return self.node(NodeKind::Error, Type::Error);
}
let subject = match subject.as_ref().kind {
parsed::NodeKind::Id(id) => {
if self.syms.defined_locally(id) {
self.error("redefinition", pos.clone());
return self.node(NodeKind::Error, Type::Error);
}
self.syms.define(id, typ.clone());
Box::new(self.node(
NodeKind::Param {
subject: Box::new(self.node(NodeKind::Id(id), Type::Unit)),
typ: Some(Type::Unit),
},
Type::Unit,
))
}
_ => unreachable!(),
};
self.node(NodeKind::Let { subject, value }, Type::Unit)
}
parsed::NodeKind::Fn {
subject,
params,
return_typ: _,
body,
} => {
let parsed::NodeKind::Id(id) = subject.as_ref().kind else { unreachable!() };
let Some(sym) = self.syms.get(id).cloned() else {
// rejected in fn scanner
return self.node(NodeKind::Error,Type::Error);
};
let Type::Fn { id: fn_id, params: param_typs, return_typ } = sym.typ else {
self.error("redefintion", pos.clone());
return self.node(NodeKind::Error,Type::Error);
};
self.syms.enter_scope();
let params = params
.iter()
.zip(param_typs)
.map(|(param, typ)| {
let parsed::NodeKind::Param { subject, .. } = &param.kind else { unreachable!() };
let parsed::NodeKind::Id(id) = subject.as_ref().kind else { unreachable!() };
self.node(
NodeKind::Param {
subject: Box::new(self.node(NodeKind::Id(id), Type::Unit)),
typ: Some(typ),
},
Type::Unit,
)
})
.collect::<Vec<_>>();
for param in &params {
let NodeKind::Param { ref subject, ref typ } = param.kind else { unreachable!() };
let NodeKind::Id(id) = subject.kind else { unreachable!() };
self.syms.define(id, typ.as_ref().cloned().unwrap());
}
let body = Box::new(self.check_expr(&body));
if !self.compatible(&return_typ, &body.typ) {
self.error("return type violated", pos.clone());
}
self.syms.leave_scope().unwrap();
self.node(
NodeKind::Fn {
subject: Box::new(self.node(NodeKind::Id(id), Type::Unit)),
params,
return_typ: *return_typ,
body,
id: fn_id,
},
Type::Unit,
)
}
parsed::NodeKind::Return { value } => {
let value = value.as_ref().map(|value| Box::new(self.check_expr(value)));
let typ = value
.as_ref()
.map(|value| value.typ.clone())
.unwrap_or(Type::Unit);
self.node(NodeKind::Return { value }, typ)
}
parsed::NodeKind::Param { .. } => unreachable!("handle elsewhere"),
}
}
fn check_type(&self, node: &parsed::Node) -> Type {
match node.kind {
parsed::NodeKind::Error => Type::Error,
parsed::NodeKind::Id(value) => {
if value == hash("i32") {
Type::I32
} else if value == hash("u32") {
Type::U32
} else {
todo!("symbol lookup idk")
}
}
_ => unreachable!(),
}
}
fn compatible(&self, typ_a: &Type, typ_b: &Type) -> bool {
typ_a == typ_b
}
fn node(&self, kind: NodeKind, typ: Type) -> Node {
Node {
kind,
typ,
table_id: self.syms.table_id(),
}
}
fn error<S: Into<String>>(&mut self, msg: S, pos: Pos) {
let msg = msg.into();
self.error_acc.lock().unwrap().add(Error {
kind: crate::pos::ErrorKind::CheckerError,
pos: Some(pos),
msg,
});
}
}
#[test]
fn test_checker() {
use crate::parser::Parser;
use pretty_assertions::assert_eq;
use NodeKind::{Block, Call, Error, Fn, Id, Int, Let, Param, Return};
use Type::{Unit, I32};
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 check = |text| {
let error_acc = Rc::new(Mutex::new(ErrorAcc::new()));
Checker::<SeqIdGen>::new_with_fn_id_gen(error_acc.clone())
.check(&Parser::new(text, error_acc).parse())
};
assert_eq!(
check("let a = 5; a;"),
vec![
Node {
kind: Let {
subject: Box::new(Node {
kind: Param {
subject: Box::new(Node {
kind: Id(hash("a")),
typ: Unit,
table_id: 0,
}),
typ: Some(Unit)
},
typ: Unit,
table_id: 0,
}),
value: Box::new(Node {
kind: Int(5),
typ: I32,
table_id: 0,
})
},
typ: Unit,
table_id: 0,
},
Node {
kind: Id(hash("a")),
typ: I32,
table_id: 0,
}
]
);
assert_eq!(
check("let a = 5; { a; }"),
vec![
Node {
kind: Let {
subject: Box::new(Node {
kind: Param {
subject: Box::new(Node {
kind: Id(hash("a")),
typ: Unit,
table_id: 0,
}),
typ: Some(Unit)
},
typ: Unit,
table_id: 0,
}),
value: Box::new(Node {
kind: Int(5),
typ: I32,
table_id: 0,
})
},
typ: Unit,
table_id: 0,
},
Node {
kind: Block(vec![Node {
kind: Id(hash("a")),
typ: I32,
table_id: 1,
},]),
typ: I32,
table_id: 0,
},
]
);
println!("intentionally undefined");
assert_eq!(
check("let a = 5; a; { a; let b = 5; b; } a; b;"),
vec![
Node {
kind: Let {
subject: Box::new(Node {
kind: Param {
subject: Box::new(Node {
kind: Id(hash("a")),
typ: Unit,
table_id: 0,
}),
typ: Some(Unit)
},
typ: Unit,
table_id: 0,
}),
value: Box::new(Node {
kind: Int(5),
typ: I32,
table_id: 0,
})
},
typ: Unit,
table_id: 0,
},
Node {
kind: Id(hash("a")),
typ: I32,
table_id: 0,
},
Node {
kind: Block(vec![
Node {
kind: Id(hash("a")),
typ: I32,
table_id: 1,
},
Node {
kind: Let {
subject: Box::new(Node {
kind: Param {
subject: Box::new(Node {
kind: Id(hash("b")),
typ: Unit,
table_id: 1,
}),
typ: Some(Unit)
},
typ: Unit,
table_id: 1,
}),
value: Box::new(Node {
kind: Int(5),
typ: I32,
table_id: 1,
})
},
typ: Unit,
table_id: 1,
},
Node {
kind: Id(hash("b")),
typ: I32,
table_id: 1,
}
]),
typ: I32,
table_id: 0,
},
Node {
kind: Id(hash("a")),
typ: I32,
table_id: 0,
},
Node {
kind: Error,
typ: Type::Error,
table_id: 0,
}
]
);
assert_eq!(
check("fn a() -> i32 { return 0; } \n a();"),
vec![
Node {
kind: Fn {
subject: Box::new(Node {
kind: Id(hash("a")),
typ: Unit,
table_id: 0,
}),
params: vec![],
return_typ: I32,
body: Box::new(Node {
kind: Block(vec![Node {
kind: Return {
value: Some(Box::new(Node {
kind: Int(0),
typ: I32,
table_id: 2,
}),),
},
typ: I32,
table_id: 2,
},],),
typ: I32,
table_id: 1,
}),
id: 0,
},
typ: Unit,
table_id: 0,
},
Node {
kind: Call {
subject: Box::new(Node {
kind: Id(hash("a")),
typ: Type::Fn {
id: 0,
params: vec![],
return_typ: Box::new(I32)
},
table_id: 0
}),
args: vec![]
},
typ: I32,
table_id: 0,
},
]
);
}

View File

@ -1,9 +1,5 @@
#![allow(dead_code)] #![allow(dead_code)]
mod checked;
mod checker;
mod hir;
mod hir_compiler;
mod lexer; mod lexer;
mod parsed; mod parsed;
mod parser; mod parser;