feat: simple inline

This commit is contained in:
felipegchi 2022-11-28 14:24:28 -03:00
parent 0b16e63eed
commit 4357ec0078
9 changed files with 476 additions and 17 deletions

View File

@ -149,7 +149,6 @@ pub fn compile_in_session<T>(
Log::Checked(start.elapsed())
},
);
eprintln!();
res
} else {
render_to_stderr(&render_config, &session, &Log::Failed(start.elapsed()));

View File

@ -9,4 +9,5 @@ edition = "2021"
kind-span = { path = "../kind-span" }
kind-tree = { path = "../kind-tree" }
kind-report = { path = "../kind-report" }
fxhash = "0.2.1"
fxhash = "0.2.1"
im = "*"

View File

@ -1,22 +1,275 @@
use fxhash::FxHashMap;
use kind_tree::{
concrete::{expr::Expr, visitor::Visitor},
symbol::Symbol,
};
use kind_span::Range;
use kind_tree::concrete::expr::{Binding, Case, CaseBinding, Destruct, Expr, ExprKind, SttmKind};
use kind_tree::concrete::pat::{Pat, PatIdent, PatKind};
use kind_tree::concrete::visitor::Visitor;
use kind_tree::symbol::{Ident, QualifiedIdent, Symbol};
use kind_tree::visit_vec;
pub struct Subst<'a> {
pub context_vars: Vec<(Range, String)>,
pub names: &'a FxHashMap<String, String>,
}
impl<'a> Visitor for Subst<'a> {
fn visit_ident(&mut self, ident: &mut kind_tree::symbol::Ident) {
if let Some(res) = self.names.get(ident.to_str()) {
ident.data = Symbol::new(res.clone());
fn visit_attr(&mut self, _: &mut kind_tree::concrete::Attribute) {}
fn visit_ident(&mut self, ident: &mut Ident) {
let name = ident.to_str();
if self.context_vars.iter().all(|x| x.1 != name) {
if let Some(res) = self.names.get(name) {
ident.data = Symbol::new(res.clone())
}
}
}
fn visit_pat_ident(&mut self, ident: &mut PatIdent) {
self.visit_ident(&mut ident.0)
}
fn visit_destruct(&mut self, destruct: &mut Destruct) {
match destruct {
Destruct::Destruct(range, ty, bindings, _) => {
self.visit_qualified_ident(
&mut QualifiedIdent::add_segment(ty, "open").to_generated(),
);
self.visit_range(range);
self.visit_qualified_ident(ty);
for bind in bindings {
self.visit_case_binding(bind)
}
}
Destruct::Ident(ident) => self.context_vars.push((ident.range, ident.to_string())),
}
}
fn visit_sttm(&mut self, sttm: &mut kind_tree::concrete::expr::Sttm) {
match &mut sttm.data {
SttmKind::Ask(ident, val, next) => {
self.visit_expr(val);
let vars = self.context_vars.clone();
self.visit_destruct(ident);
self.visit_sttm(next);
self.context_vars = vars;
}
SttmKind::Let(ident, val, next) => {
self.visit_expr(val);
let vars = self.context_vars.clone();
self.visit_destruct(ident);
self.visit_sttm(next);
self.context_vars = vars;
}
SttmKind::Expr(expr, next) => {
self.visit_expr(expr);
self.visit_sttm(next);
}
SttmKind::Return(expr) => {
self.visit_expr(expr);
}
SttmKind::RetExpr(expr) => {
self.visit_expr(expr);
}
}
}
fn visit_pat(&mut self, pat: &mut Pat) {
match &mut pat.data {
PatKind::Var(ident) => self.visit_pat_ident(ident),
PatKind::Str(_) => (),
PatKind::Num(_) => (),
PatKind::Hole => (),
PatKind::List(ls) => {
for pat in ls {
self.visit_pat(pat)
}
}
PatKind::Pair(fst, snd) => {
self.visit_pat(fst);
self.visit_pat(snd);
}
PatKind::App(t, ls) => {
self.visit_qualified_ident(t);
for pat in ls {
self.visit_pat(pat)
}
}
}
}
fn visit_case_binding(&mut self, case_binding: &mut CaseBinding) {
match case_binding {
CaseBinding::Field(ident) | CaseBinding::Renamed(_, ident) => {
self.context_vars.push((ident.range, ident.to_string()))
}
}
}
fn visit_case(&mut self, case: &mut Case) {
let vars = self.context_vars.clone();
for binding in &mut case.bindings {
self.visit_case_binding(binding);
}
self.visit_expr(&mut case.value);
self.context_vars = vars;
}
fn visit_match(&mut self, matcher: &mut kind_tree::concrete::expr::Match) {
self.visit_expr(&mut matcher.scrutinizer);
for case in &mut matcher.cases {
self.visit_case(case);
}
match &mut matcher.motive {
Some(x) => self.visit_expr(x),
None => (),
}
}
fn visit_binding(&mut self, binding: &mut Binding) {
match binding {
Binding::Positional(e) => self.visit_expr(e),
Binding::Named(_, _, e) => self.visit_expr(e),
}
}
fn visit_expr(&mut self, expr: &mut Expr) {
match &mut expr.data {
ExprKind::Var { name } => self.visit_ident(name),
ExprKind::Constr { name, args } => {
self.visit_qualified_ident(name);
visit_vec!(args.iter_mut(), arg => self.visit_binding(arg));
}
ExprKind::All {
param: None,
typ,
body,
..
} => {
self.visit_expr(typ);
self.visit_expr(body);
}
ExprKind::All {
param: Some(ident),
typ,
body,
..
} => {
self.visit_expr(typ);
self.context_vars.push((ident.range, ident.to_string()));
self.visit_expr(body);
self.context_vars.pop();
}
ExprKind::Lambda {
param, typ, body, ..
} => {
match typ {
Some(x) => self.visit_expr(x),
None => (),
}
self.context_vars.push((param.range, param.to_string()));
self.visit_expr(body);
self.context_vars.pop();
}
ExprKind::App { fun, args } => {
self.visit_expr(fun);
visit_vec!(args.iter_mut(), arg => self.visit_expr(&mut arg.data));
}
ExprKind::Ann { val, typ } => {
self.visit_expr(val);
self.visit_expr(typ);
}
ExprKind::Lit { lit } => self.visit_literal(lit),
ExprKind::Binary { op: _, fst, snd } => {
self.visit_expr(fst);
self.visit_expr(snd);
}
ExprKind::Let { name, val, next } => {
self.visit_expr(val);
let vars = self.context_vars.clone();
self.visit_destruct(name);
self.visit_expr(next);
self.context_vars = vars;
}
ExprKind::Sigma {
param: None,
fst,
snd,
} => {
self.visit_qualified_ident(&mut QualifiedIdent::new_static(
"Sigma", None, expr.range,
));
self.visit_expr(fst);
self.visit_expr(snd);
}
ExprKind::Sigma {
param: Some(ident),
fst,
snd,
} => {
self.visit_qualified_ident(&mut QualifiedIdent::new_static(
"Sigma", None, expr.range,
));
self.visit_expr(fst);
self.context_vars.push((ident.range, ident.to_string()));
self.visit_expr(snd);
self.context_vars.pop();
}
ExprKind::Match(matcher) => {
self.visit_qualified_ident(&mut matcher.typ.add_segment("match"));
self.visit_match(matcher)
}
ExprKind::Subst(subst) => {
self.visit_ident(&mut subst.name);
if let Some(pos) = self
.context_vars
.iter()
.position(|x| x.1 == subst.name.to_string())
{
subst.indx = pos;
}
self.visit_expr(&mut subst.expr)
}
ExprKind::Hole => {}
ExprKind::Do { typ, sttm } => {
self.visit_qualified_ident(&mut typ.add_segment("pure").to_generated());
self.visit_qualified_ident(&mut typ.add_segment("bind").to_generated());
self.visit_sttm(sttm)
}
ExprKind::If { cond, then_, else_ } => {
self.visit_qualified_ident(&mut QualifiedIdent::new_sugared(
"Bool", "if", expr.range,
));
self.visit_expr(cond);
self.visit_expr(then_);
self.visit_expr(else_);
}
ExprKind::Pair { fst, snd } => {
self.visit_qualified_ident(&mut QualifiedIdent::new_sugared(
"Pair", "new", expr.range,
));
self.visit_expr(fst);
self.visit_expr(snd);
}
ExprKind::List { args } => {
self.visit_qualified_ident(&mut QualifiedIdent::new_sugared(
"List", "nil", expr.range,
));
self.visit_qualified_ident(&mut QualifiedIdent::new_sugared(
"List", "cons", expr.range,
));
visit_vec!(args.iter_mut(), arg => self.visit_expr(arg));
}
}
}
}
pub fn substitute_in_expr(expr: &mut Expr, names: &FxHashMap<String, String>) {
let mut session = Subst { names };
let mut session = Subst {
context_vars: Default::default(),
names,
};
session.visit_expr(expr)
}

View File

@ -1,6 +1,6 @@
use checker::eval;
use errors::DriverError;
use kind_pass::{desugar, erasure, expand};
use kind_pass::{desugar, erasure, expand, inline::inline_book};
use kind_report::report::FileCache;
use kind_span::SyntaxCtxIndex;
@ -33,7 +33,10 @@ pub fn type_check_book(session: &mut Session, path: &PathBuf) -> Option<untyped:
return None;
}
todo!()
let mut book = erasure::erase_book(&desugared_book, session.diagnostic_sender.clone())?;
inline_book(&mut book);
Some(book)
}
pub fn to_book(session: &mut Session, path: &PathBuf) -> Option<concrete::Book> {
@ -56,7 +59,10 @@ pub fn erase_book(
) -> Option<untyped::Book> {
let concrete_book = to_book(session, path)?;
let desugared_book = desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book)?;
erasure::erase_book(&desugared_book, session.diagnostic_sender.clone())
let mut book = erasure::erase_book(&desugared_book, session.diagnostic_sender.clone())?;
inline_book(&mut book);
Some(book)
}
pub fn desugar_book(session: &mut Session, path: &PathBuf) -> Option<desugared::Book> {
@ -82,7 +88,10 @@ pub fn compile_book_to_kdl(
) -> Option<kind_target_kdl::File> {
let concrete_book = to_book(session, path)?;
let desugared_book = desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book)?;
let book = erasure::erase_book(&desugared_book, session.diagnostic_sender.clone())?;
let mut book = erasure::erase_book(&desugared_book, session.diagnostic_sender.clone())?;
inline_book(&mut book);
kind_target_kdl::compile_book(book, session.diagnostic_sender.clone(), namespace)
}

View File

@ -0,0 +1,96 @@
use fxhash::FxHashMap;
use kind_tree::untyped;
use crate::unbound::subst::subst_on_expr;
struct Inlinable {
names: Vec<String>,
body: Box<untyped::Expr>,
}
struct InlineState {
funs: FxHashMap<String, Inlinable>
}
fn inlinable(entry: &untyped::Entry) -> Option<Inlinable> {
if entry.rules.len() == 1 {
let mut names = Vec::new();
for pat in &entry.rules[0].pats {
match &pat.data {
untyped::ExprKind::Var { name } => {
names.push(name.to_string())
},
_ => return None
}
}
// TODO: Check if is recursive
Some(Inlinable { names, body: entry.rules[0].body.clone() })
} else {
None
}
}
pub fn inline_book(book: &mut untyped::Book) {
let mut funs = FxHashMap::default();
let mut to_remove = Vec::new();
for entr in book.entrs.values() {
if entr.attrs.inlined {
if let Some(inlinable) = inlinable(&entr) {
funs.insert(entr.name.to_string(), inlinable);
to_remove.push(entr.name.to_string());
}
}
}
for name in &to_remove {
book.entrs.remove(name);
}
let mut state = InlineState { funs };
for entr in &mut book.entrs {
state.inline_entry(entr.1)
}
}
impl InlineState {
fn inline_entry(&mut self, entry: &mut untyped::Entry) {
for rule in &mut entry.rules {
self.inline_expr(&mut rule.body)
}
}
fn inline_expr(&mut self, expr: &mut Box<untyped::Expr>) {
use untyped::ExprKind::*;
match &mut expr.data {
Lambda { body, .. } => self.inline_expr(body),
App { fun, args } => {
self.inline_expr(fun);
for arg in args {
self.inline_expr(arg);
}
}
Fun { name, args } | Ctr { name, args } => {
if let Some(inlinable) = self.funs.get(name.to_str()) {
let subst = FxHashMap::from_iter(inlinable.names.iter().cloned().zip(args.clone()));
*expr = inlinable.body.clone();
subst_on_expr(expr, subst);
}else {
for arg in args {
self.inline_expr(arg);
}
}
}
Let { val, next, .. } => {
self.inline_expr(val);
self.inline_expr(next);
}
Binary { left, right, .. } => {
self.inline_expr(left);
self.inline_expr(right);
}
_ => (),
}
}
}

View File

@ -9,3 +9,4 @@ pub mod erasure;
mod errors;
pub mod expand;
pub mod unbound;
pub mod inline;

View File

@ -21,6 +21,8 @@ use kind_tree::{visit_opt, visit_vec};
use crate::errors::PassError;
pub mod subst;
pub struct UnboundCollector {
pub errors: Sender<Box<dyn Diagnostic>>,

View File

@ -0,0 +1,101 @@
use fxhash::FxHashMap;
use kind_tree::untyped::*;
pub struct Subst {
vars: FxHashMap<String, Box<Expr>>,
ctx: im::HashSet<String>
}
pub fn subst_on_expr(expr: &mut Box<Expr>, vars: FxHashMap<String, Box<Expr>>) {
let mut state = Subst {
vars,
ctx: Default::default(),
};
state.subst_expr(expr)
}
impl Subst {
pub fn subst_entry(&mut self, entry: &mut Entry) {
let backup = self.ctx.clone();
self.ctx = backup;
for rule in &mut entry.rules {
self.subst_rule(rule);
}
}
pub fn subst_rule(&mut self, rule: &mut Rule) {
let backup = self.ctx.clone();
for pat in &mut rule.pats {
self.subst_expr(pat)
}
self.subst_expr(&mut rule.body);
self.ctx = backup;
}
pub fn subst_pat(&mut self, expr: &mut Box<Expr>) {
use ExprKind::*;
match &mut expr.data {
Var { name } => {
self.ctx.insert(name.to_string());
}
Fun { name: _, args } | Ctr { name: _, args } => {
for arg in args {
self.subst_pat(arg);
}
}
_ => ()
}
}
pub fn subst_expr(&mut self, expr: &mut Box<Expr>) {
use ExprKind::*;
match &mut expr.data {
Var { name } => {
if self.ctx.contains(name.to_str()) {
return;
}
if let Some(res) = self.vars.get(name.to_str()) {
*expr = res.clone().clone();
}
},
Lambda { param, body, .. } => {
let backup = self.ctx.clone();
self.ctx.insert(param.to_string());
self.subst_expr(body);
self.ctx = backup;
}
App { fun, args } => {
self.subst_expr(fun);
for arg in args {
self.subst_expr(arg);
}
}
Fun { name: _, args } | Ctr { name: _, args } => {
for arg in args {
self.subst_expr(arg);
}
}
Let { name, val, next } => {
let backup = self.ctx.clone();
self.ctx.insert(name.to_string());
self.subst_expr(val);
self.subst_expr(next);
self.ctx = backup;
}
Binary { left, right, .. } => {
self.subst_expr(left);
self.subst_expr(right);
}
_ => ()
}
}
}

View File

@ -17,12 +17,9 @@ pub fn compile_book(
sender: Sender<Box<dyn Diagnostic>>,
namespace: &str,
) -> Option<compile::File> {
// TODO: Inlining
// TODO: Remove kdl_states (maybe check if they're ever called?)
// TODO: Don't erase kdl_state functions
// TODO: Convert to some sort of Kindelia.Contract
let flattened = flatten(book);
let file = compile::compile_book(&flattened, sender, namespace)?;
let file = linearize::linearize_file(file);