split up frontend file

main
NotAFile 2022-04-05 16:08:10 +02:00
parent 86e3bf4d32
commit 5dca566cca
3 changed files with 198 additions and 187 deletions

View File

@ -8,6 +8,8 @@ pub use types::{Type, TypeStruct, TypingContext};
mod callable;
pub mod lowering;
mod pretty_ir;
mod type_infer;
pub mod typed_ir;
pub mod types;
@ -323,191 +325,4 @@ impl Context {
}
Ok(typed_module)
}
pub fn infer_expr_types(&mut self, expr: &typed_ir::Expr) -> typed_ir::Expr {
if self.types.is_fully_typed(expr.typ) {
// there is nothing more to infer
return expr.clone();
}
match &expr.kind {
typed_ir::ExprKind::Literal(lit) => expr.clone().with_type(lit.typ),
// we can not see beyond this expression right now
typed_ir::ExprKind::Path(_) => expr.clone(),
typed_ir::ExprKind::Call(call) => {
let args_typed: Vec<_> = call
.args
.iter()
.map(|ex| self.infer_expr_types(ex))
.collect();
let callee_def = self.callables.get(call.called);
let param_types: Vec<_> = callee_def.args.iter().map(|param| param.1).collect();
let inferred_args: Vec<_> = param_types
.iter()
.zip(&args_typed)
.map(|(param, arg)| self.types.infer_type(*param, arg.typ))
.collect();
let mut genargs: Vec<_> = callee_def.genargs.iter().map(|a| a.1).collect();
let mut new_type = callee_def.ret_type;
if !genargs.is_empty() {
// need to infer generic arguments
for inf_res in inferred_args {
match inf_res {
types::InferenceResult::First(_) => todo!(),
types::InferenceResult::Second(_) => todo!(),
types::InferenceResult::TypeVar(dbi, tvar, typ) => {
assert_eq!(dbi, 0);
// TODO: type check argument instead of just using it
genargs[tvar as usize] = typ;
}
types::InferenceResult::Incompatible => todo!(),
types::InferenceResult::Ambigous => todo!(),
}
}
// TODO: HACKY HACKY HACK
new_type = genargs[0];
}
let mut new_expr = expr.clone();
new_expr.typ = new_type;
new_expr.kind = typed_ir::ExprKind::Call(typed_ir::Call {
called: call.called,
args: args_typed,
genargs,
});
new_expr
}
typed_ir::ExprKind::Match(match_) => {
let new_arms: Vec<_> = match_
.arms
.iter()
.map(|(pat, val)| (self.infer_expr_types(pat), self.infer_expr_types(val)))
.collect();
// TODO: hacky hacky hacky
let res_type = new_arms.first().unwrap().1.typ;
let new_match = typed_ir::Match {
expr: self.infer_expr_types(&match_.expr),
arms: new_arms,
};
let mut new_expr = expr.clone().with_type(res_type);
new_expr.kind = typed_ir::ExprKind::Match(Box::new(new_match));
new_expr
}
}
}
pub fn infer_types(&mut self, mut block: typed_ir::Block) -> typed_ir::Block {
let new_root = self.infer_expr_types(&block.expr);
block.expr = new_root;
block
}
pub fn pretty_typed_block(
&self,
w: &mut dyn std::fmt::Write,
block: &typed_ir::Block,
) -> std::fmt::Result {
let callsig = self.callables.get(block.signature);
{
// TODO: ugly copy paste job
let args = callsig
.args
.iter()
.map(|(_name, typ)| {
let mut out = String::new();
self.types.pretty_type(&mut out, *typ)?;
Ok(out)
})
.collect::<Result<Vec<String>, std::fmt::Error>>()?;
let genargs = callsig
.genargs
.iter()
.map(|(_name, typ)| {
let mut type_str = String::new();
self.types.pretty_type(&mut type_str, *typ)?;
Ok(type_str)
})
.collect::<Result<Vec<String>, std::fmt::Error>>()?;
writeln!(
w,
"block {}<{}>({})",
callsig.name(),
genargs.join(", "),
args.join(", ")
)?;
}
for sig in &block.signals {
let mut typ_pretty = String::new();
self.types.pretty_type(&mut typ_pretty, sig.typ)?;
writeln!(w, "sig_{}: {}", sig.id.0, typ_pretty)?
}
self.pretty_typed_expr(w, &block.expr)?;
Ok(())
}
pub fn pretty_typed_expr(
&self,
w: &mut dyn std::fmt::Write,
expr: &typed_ir::Expr,
) -> std::fmt::Result {
let expr_pretty = match &expr.kind {
typed_ir::ExprKind::Literal(lit) => {
let mut lit_str = String::new();
self.types.pretty_value(&mut lit_str, lit)?;
lit_str
}
typed_ir::ExprKind::Path(path) => format!("sig_{}", path.0),
typed_ir::ExprKind::Call(call) => {
let args = call
.args
.iter()
.map(|arg| {
self.pretty_typed_expr(w, arg)?;
Ok(format!("_{}", arg.id.0))
})
.collect::<Result<Vec<_>, std::fmt::Error>>()?;
let callable = self.callables.get(call.called);
let genargs = call
.genargs
.iter()
.map(|param| {
let mut type_str = String::new();
self.types.pretty_type(&mut type_str, *param)?;
Ok(type_str)
})
.collect::<Result<Vec<_>, std::fmt::Error>>()?;
format!(
"{}<{}>({})",
callable.name(),
genargs.join(", "),
args.join(", ")
)
}
typed_ir::ExprKind::Match(match_) => {
self.pretty_typed_expr(w, &match_.expr)?;
let arms = match_
.arms
.iter()
.map(|(pat, val)| {
self.pretty_typed_expr(w, pat)?;
self.pretty_typed_expr(w, val)?;
Ok(format!(" _{} => _{}", pat.id.0, val.id.0))
})
.collect::<Result<Vec<_>, _>>()?;
format!(
"match (_{}) {{\n{}\n}}",
&match_.expr.id.0,
arms.join(",\n")
)
}
};
let mut type_pretty = String::new();
self.types.pretty_type(&mut type_pretty, expr.typ)?;
writeln!(w, "let _{}: {} = {}", expr.id.0, type_pretty, expr_pretty)?;
Ok(())
}
}

109
src/frontend/pretty_ir.rs Normal file
View File

@ -0,0 +1,109 @@
use super::typed_ir;
use super::Context;
impl Context {
pub fn pretty_typed_block(
&self,
w: &mut dyn std::fmt::Write,
block: &typed_ir::Block,
) -> std::fmt::Result {
let callsig = self.callables.get(block.signature);
{
// TODO: ugly copy paste job
let args = callsig
.args
.iter()
.map(|(_name, typ)| {
let mut out = String::new();
self.types.pretty_type(&mut out, *typ)?;
Ok(out)
})
.collect::<Result<Vec<String>, std::fmt::Error>>()?;
let genargs = callsig
.genargs
.iter()
.map(|(_name, typ)| {
let mut type_str = String::new();
self.types.pretty_type(&mut type_str, *typ)?;
Ok(type_str)
})
.collect::<Result<Vec<String>, std::fmt::Error>>()?;
writeln!(
w,
"block {}<{}>({})",
callsig.name(),
genargs.join(", "),
args.join(", ")
)?;
}
for sig in &block.signals {
let mut typ_pretty = String::new();
self.types.pretty_type(&mut typ_pretty, sig.typ)?;
writeln!(w, "sig_{}: {}", sig.id.0, typ_pretty)?
}
self.pretty_typed_expr(w, &block.expr)?;
Ok(())
}
pub fn pretty_typed_expr(
&self,
w: &mut dyn std::fmt::Write,
expr: &typed_ir::Expr,
) -> std::fmt::Result {
let expr_pretty = match &expr.kind {
typed_ir::ExprKind::Literal(lit) => {
let mut lit_str = String::new();
self.types.pretty_value(&mut lit_str, lit)?;
lit_str
}
typed_ir::ExprKind::Path(path) => format!("sig_{}", path.0),
typed_ir::ExprKind::Call(call) => {
let args = call
.args
.iter()
.map(|arg| {
self.pretty_typed_expr(w, arg)?;
Ok(format!("_{}", arg.id.0))
})
.collect::<Result<Vec<_>, std::fmt::Error>>()?;
let callable = self.callables.get(call.called);
let genargs = call
.genargs
.iter()
.map(|param| {
let mut type_str = String::new();
self.types.pretty_type(&mut type_str, *param)?;
Ok(type_str)
})
.collect::<Result<Vec<_>, std::fmt::Error>>()?;
format!(
"{}<{}>({})",
callable.name(),
genargs.join(", "),
args.join(", ")
)
}
typed_ir::ExprKind::Match(match_) => {
self.pretty_typed_expr(w, &match_.expr)?;
let arms = match_
.arms
.iter()
.map(|(pat, val)| {
self.pretty_typed_expr(w, pat)?;
self.pretty_typed_expr(w, val)?;
Ok(format!(" _{} => _{}", pat.id.0, val.id.0))
})
.collect::<Result<Vec<_>, _>>()?;
format!(
"match (_{}) {{\n{}\n}}",
&match_.expr.id.0,
arms.join(",\n")
)
}
};
let mut type_pretty = String::new();
self.types.pretty_type(&mut type_pretty, expr.typ)?;
writeln!(w, "let _{}: {} = {}", expr.id.0, type_pretty, expr_pretty)?;
Ok(())
}
}

View File

@ -0,0 +1,87 @@
use super::typed_ir;
use super::types;
use super::Context;
impl Context {
pub fn infer_types(&mut self, mut block: typed_ir::Block) -> typed_ir::Block {
let new_root = self.infer_expr_types(&block.expr);
block.expr = new_root;
block
}
pub fn infer_expr_types(&mut self, expr: &typed_ir::Expr) -> typed_ir::Expr {
if self.types.is_fully_typed(expr.typ) {
// there is nothing more to infer
return expr.clone();
}
match &expr.kind {
typed_ir::ExprKind::Literal(lit) => expr.clone().with_type(lit.typ),
// we can not see beyond this expression right now
typed_ir::ExprKind::Path(_) => expr.clone(),
typed_ir::ExprKind::Call(call) => {
let args_typed: Vec<_> = call
.args
.iter()
.map(|ex| self.infer_expr_types(ex))
.collect();
let callee_def = self.callables.get(call.called);
let param_types: Vec<_> = callee_def.args.iter().map(|param| param.1).collect();
let inferred_args: Vec<_> = param_types
.iter()
.zip(&args_typed)
.map(|(param, arg)| self.types.infer_type(*param, arg.typ))
.collect();
let mut genargs: Vec<_> = callee_def.genargs.iter().map(|a| a.1).collect();
let mut new_type = callee_def.ret_type;
if !genargs.is_empty() {
// need to infer generic arguments
for inf_res in inferred_args {
match inf_res {
types::InferenceResult::First(_) => todo!(),
types::InferenceResult::Second(_) => todo!(),
types::InferenceResult::TypeVar(dbi, tvar, typ) => {
assert_eq!(dbi, 0);
// TODO: type check argument instead of just using it
genargs[tvar as usize] = typ;
}
types::InferenceResult::Incompatible => todo!(),
types::InferenceResult::Ambigous => todo!(),
}
}
// TODO: HACKY HACKY HACK
new_type = genargs[0];
}
let mut new_expr = expr.clone();
new_expr.typ = new_type;
new_expr.kind = typed_ir::ExprKind::Call(typed_ir::Call {
called: call.called,
args: args_typed,
genargs,
});
new_expr
}
typed_ir::ExprKind::Match(match_) => {
let new_arms: Vec<_> = match_
.arms
.iter()
.map(|(pat, val)| (self.infer_expr_types(pat), self.infer_expr_types(val)))
.collect();
// TODO: hacky hacky hacky
let res_type = new_arms.first().unwrap().1.typ;
let new_match = typed_ir::Match {
expr: self.infer_expr_types(&match_.expr),
arms: new_arms,
};
let mut new_expr = expr.clone().with_type(res_type);
new_expr.kind = typed_ir::ExprKind::Match(Box::new(new_match));
new_expr
}
}
}
}