mirror of
https://github.com/HigherOrderCO/Kind1.git
synced 2024-10-26 12:08:29 +03:00
feat: simple inline
This commit is contained in:
parent
0b16e63eed
commit
4357ec0078
@ -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()));
|
||||
|
@ -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 = "*"
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
96
crates/kind-pass/src/inline/mod.rs
Normal file
96
crates/kind-pass/src/inline/mod.rs
Normal 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);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
@ -9,3 +9,4 @@ pub mod erasure;
|
||||
mod errors;
|
||||
pub mod expand;
|
||||
pub mod unbound;
|
||||
pub mod inline;
|
||||
|
@ -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>>,
|
||||
|
||||
|
101
crates/kind-pass/src/unbound/subst.rs
Normal file
101
crates/kind-pass/src/unbound/subst.rs
Normal 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);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user