mirror of
https://github.com/HigherOrderCO/Kind1.git
synced 2024-08-15 19:30:41 +03:00
feat: added getter and setter derivings
This commit is contained in:
parent
b7b15e7590
commit
6844cc2735
117
crates/kind-derive/src/getters.rs
Normal file
117
crates/kind-derive/src/getters.rs
Normal file
@ -0,0 +1,117 @@
|
||||
//! Module to derive a "open" function for records.
|
||||
|
||||
use kind_span::Range;
|
||||
|
||||
use kind_tree::concrete::expr::Expr;
|
||||
use kind_tree::concrete::pat::{Pat, PatIdent};
|
||||
use kind_tree::concrete::*;
|
||||
use kind_tree::concrete::{self};
|
||||
use kind_tree::symbol::{Ident, QualifiedIdent};
|
||||
|
||||
pub fn derive_getters(range: Range, rec: &RecordDecl) -> Vec<concrete::Entry> {
|
||||
let mk_var = |name: Ident| -> Box<Expr> {
|
||||
Box::new(Expr {
|
||||
data: ExprKind::Var { name },
|
||||
range,
|
||||
})
|
||||
};
|
||||
|
||||
let mk_cons = |name: QualifiedIdent, args: Vec<Binding>| -> Box<Expr> {
|
||||
Box::new(Expr {
|
||||
data: ExprKind::Constr { name, args },
|
||||
range,
|
||||
})
|
||||
};
|
||||
|
||||
let mut types = Telescope::default();
|
||||
|
||||
for arg in rec.parameters.iter() {
|
||||
types.push(arg.to_implicit())
|
||||
}
|
||||
|
||||
// The type
|
||||
|
||||
let all_args = rec.parameters.clone();
|
||||
|
||||
let res_motive_ty = mk_cons(
|
||||
rec.name.clone(),
|
||||
all_args
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|x| Binding::Positional(mk_var(x.name)))
|
||||
.collect(),
|
||||
);
|
||||
|
||||
// Sccrutinzies
|
||||
|
||||
types.push(Argument {
|
||||
hidden: false,
|
||||
erased: false,
|
||||
name: Ident::generate("scrutinizer"),
|
||||
typ: Some(res_motive_ty),
|
||||
range,
|
||||
});
|
||||
|
||||
// Motive with indices
|
||||
|
||||
let mut pats: Vec<Box<Pat>> = Vec::new();
|
||||
|
||||
let spine: Vec<_> = rec
|
||||
.fields
|
||||
.iter()
|
||||
.map(|(name, _, ty)| (name, ty))
|
||||
.collect();
|
||||
|
||||
pats.push(Box::new(Pat {
|
||||
data: concrete::pat::PatKind::App(
|
||||
rec.name.add_segment(rec.constructor.to_str()),
|
||||
spine
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|x| {
|
||||
Box::new(Pat {
|
||||
data: concrete::pat::PatKind::Var(PatIdent(x.0.clone().with_name(|f| format!("{}_", f)))),
|
||||
range,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
range,
|
||||
}));
|
||||
|
||||
let mut entries = vec![];
|
||||
|
||||
for (arg, typ) in spine {
|
||||
let body = mk_var(arg.with_name(|f| format!("{}_", f)).clone());
|
||||
|
||||
let mut name = rec
|
||||
.name
|
||||
.add_segment(arg.to_str())
|
||||
.add_segment("get");
|
||||
|
||||
name.range = rec.constructor.range;
|
||||
|
||||
|
||||
let rules = vec![Box::new(Rule {
|
||||
name: name.clone(),
|
||||
pats: pats.clone(),
|
||||
body,
|
||||
range: rec.constructor.range,
|
||||
})];
|
||||
|
||||
let entry = Entry {
|
||||
name: name.clone(),
|
||||
docs: Vec::new(),
|
||||
args: types.clone(),
|
||||
typ: typ.clone(),
|
||||
rules,
|
||||
range: rec.constructor.range,
|
||||
attrs: Vec::new(),
|
||||
generated_by: Some(rec.name.to_string().clone()),
|
||||
};
|
||||
|
||||
entries.push(entry)
|
||||
}
|
||||
|
||||
entries
|
||||
}
|
@ -4,3 +4,5 @@ pub mod errors;
|
||||
pub mod matching;
|
||||
pub mod open;
|
||||
pub mod subst;
|
||||
pub mod getters;
|
||||
pub mod setters;
|
@ -42,11 +42,13 @@ pub fn derive_open(range: Range, rec: &RecordDecl) -> concrete::Entry {
|
||||
})
|
||||
};
|
||||
|
||||
let name = rec
|
||||
let mut name = rec
|
||||
.name
|
||||
.add_segment(rec.constructor.to_str())
|
||||
.add_segment("open");
|
||||
|
||||
name.range = rec.constructor.range;
|
||||
|
||||
let mut types = Telescope::default();
|
||||
|
||||
for arg in rec.parameters.iter() {
|
||||
@ -146,7 +148,7 @@ pub fn derive_open(range: Range, rec: &RecordDecl) -> concrete::Entry {
|
||||
name: name.clone(),
|
||||
pats,
|
||||
body,
|
||||
range,
|
||||
range: rec.constructor.range,
|
||||
})];
|
||||
|
||||
let entry = Entry {
|
||||
@ -155,7 +157,7 @@ pub fn derive_open(range: Range, rec: &RecordDecl) -> concrete::Entry {
|
||||
args: types,
|
||||
typ: ret_ty,
|
||||
rules,
|
||||
range,
|
||||
range: rec.constructor.range,
|
||||
attrs: Vec::new(),
|
||||
generated_by: Some(rec.name.to_string().clone()),
|
||||
};
|
||||
|
@ -1,3 +0,0 @@
|
||||
//! Derives getters and setters for record
|
||||
//! types.
|
||||
|
174
crates/kind-derive/src/setters.rs
Normal file
174
crates/kind-derive/src/setters.rs
Normal file
@ -0,0 +1,174 @@
|
||||
//! Module to derive a "open" function for records.
|
||||
|
||||
use kind_span::Range;
|
||||
|
||||
use kind_tree::concrete::expr::Expr;
|
||||
use kind_tree::concrete::pat::{Pat, PatIdent};
|
||||
use kind_tree::concrete::*;
|
||||
use kind_tree::concrete::{self};
|
||||
use kind_tree::symbol::{Ident, QualifiedIdent};
|
||||
|
||||
pub fn derive_setters(range: Range, rec: &RecordDecl) -> Vec<concrete::Entry> {
|
||||
let mk_var = |name: Ident| -> Box<Expr> {
|
||||
Box::new(Expr {
|
||||
data: ExprKind::Var { name },
|
||||
range,
|
||||
})
|
||||
};
|
||||
|
||||
let mk_cons = |name: QualifiedIdent, args: Vec<Binding>| -> Box<Expr> {
|
||||
Box::new(Expr {
|
||||
data: ExprKind::Constr { name, args },
|
||||
range,
|
||||
})
|
||||
};
|
||||
|
||||
let typ = |range: Range| -> Box<Expr> {
|
||||
Box::new(Expr {
|
||||
data: ExprKind::Lit { lit: Literal::Type },
|
||||
range,
|
||||
})
|
||||
};
|
||||
|
||||
let mk_pat_var = |name: Ident| {
|
||||
Box::new(Pat {
|
||||
range: name.range,
|
||||
data: concrete::pat::PatKind::Var(PatIdent(name)),
|
||||
})
|
||||
};
|
||||
|
||||
let mut types = Telescope::default();
|
||||
|
||||
for arg in rec.parameters.iter() {
|
||||
types.push(arg.to_implicit())
|
||||
}
|
||||
|
||||
// The type
|
||||
|
||||
let all_args = rec.parameters.clone();
|
||||
|
||||
let res_motive_ty = mk_cons(
|
||||
rec.name.clone(),
|
||||
all_args
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|x| Binding::Positional(mk_var(x.name)))
|
||||
.collect(),
|
||||
);
|
||||
|
||||
// Sccrutinzies
|
||||
|
||||
types.push(Argument {
|
||||
hidden: false,
|
||||
erased: false,
|
||||
name: Ident::generate("scrutinizer"),
|
||||
typ: Some(res_motive_ty.clone()),
|
||||
range,
|
||||
});
|
||||
|
||||
// Motive with indices
|
||||
|
||||
let mut pats: Vec<Box<Pat>> = Vec::new();
|
||||
|
||||
let fields_spine: Vec<_> = rec
|
||||
.fields
|
||||
.iter()
|
||||
.map(|(name, _, typ)| (name.clone(), typ.clone()))
|
||||
.collect();
|
||||
|
||||
let params_spine: Vec<_> = rec
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
(
|
||||
arg.name.clone(),
|
||||
arg.typ.clone().unwrap_or_else(|| typ(arg.range.clone())),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let spine = [params_spine.as_slice(), fields_spine.as_slice()].concat();
|
||||
|
||||
pats.push(Box::new(Pat {
|
||||
data: concrete::pat::PatKind::App(
|
||||
rec.name.add_segment(rec.constructor.to_str()),
|
||||
spine
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|(name, _)| mk_pat_var(name))
|
||||
.collect(),
|
||||
),
|
||||
range,
|
||||
}));
|
||||
|
||||
let mut entries = vec![];
|
||||
|
||||
let mut cons_name = rec.name.add_segment(rec.constructor.to_str());
|
||||
|
||||
cons_name.range = rec.constructor.range;
|
||||
|
||||
for (i, (arg, cons_typ)) in fields_spine.iter().enumerate() {
|
||||
let mut types = types.clone();
|
||||
|
||||
let place = rec.parameters.len() + i;
|
||||
|
||||
types.push(Argument {
|
||||
hidden: false,
|
||||
erased: false,
|
||||
name: Ident::generate("set"),
|
||||
typ: Some(cons_typ.clone()),
|
||||
range,
|
||||
});
|
||||
|
||||
let new_var = Ident::generate("_new_var");
|
||||
|
||||
let mut pats = pats.clone();
|
||||
|
||||
pats.push(Box::new(Pat {
|
||||
data: concrete::pat::PatKind::Var(PatIdent(new_var.clone())),
|
||||
range,
|
||||
}));
|
||||
|
||||
let mut args: Vec<_> = spine
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|x| Binding::Positional(mk_var(x.0)))
|
||||
.collect();
|
||||
|
||||
args[place] = Binding::Positional(mk_var(new_var));
|
||||
|
||||
let body = Box::new(Expr {
|
||||
data: ExprKind::Constr {
|
||||
name: cons_name.clone(),
|
||||
args,
|
||||
},
|
||||
range,
|
||||
});
|
||||
|
||||
let mut name = rec.name.add_segment(arg.to_str()).add_segment("set");
|
||||
|
||||
name.range = rec.constructor.range;
|
||||
|
||||
let rules = vec![Box::new(Rule {
|
||||
name: name.clone(),
|
||||
pats: pats.clone(),
|
||||
body,
|
||||
range: rec.constructor.range,
|
||||
})];
|
||||
|
||||
let entry = Entry {
|
||||
name: name.clone(),
|
||||
docs: Vec::new(),
|
||||
args: types.clone(),
|
||||
typ: res_motive_ty.clone(),
|
||||
rules,
|
||||
range: rec.constructor.range,
|
||||
attrs: Vec::new(),
|
||||
generated_by: Some(rec.name.to_string().clone()),
|
||||
};
|
||||
|
||||
entries.push(entry)
|
||||
}
|
||||
|
||||
entries
|
||||
}
|
@ -6,8 +6,10 @@ use std::fmt::Display;
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
use fxhash::FxHashMap;
|
||||
use kind_derive::getters::derive_getters;
|
||||
use kind_derive::matching::derive_match;
|
||||
use kind_derive::open::derive_open;
|
||||
use kind_derive::setters::derive_setters;
|
||||
use kind_report::data::Diagnostic;
|
||||
use kind_span::Locatable;
|
||||
use kind_span::Range;
|
||||
@ -23,6 +25,8 @@ pub mod uses;
|
||||
pub enum Derive {
|
||||
Match,
|
||||
Open,
|
||||
Getters,
|
||||
Setters
|
||||
}
|
||||
|
||||
impl Display for Derive {
|
||||
@ -30,6 +34,8 @@ impl Display for Derive {
|
||||
match self {
|
||||
Derive::Match => write!(f, "match"),
|
||||
Derive::Open => write!(f, "open"),
|
||||
Derive::Getters => write!(f, "getters"),
|
||||
Derive::Setters => write!(f, "setters"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,6 +65,8 @@ fn string_to_derive(name: &str) -> Option<Derive> {
|
||||
match name {
|
||||
"match" => Some(Derive::Match),
|
||||
"open" => Some(Derive::Open),
|
||||
"getters" => Some(Derive::Getters),
|
||||
"setters" => Some(Derive::Setters),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -160,6 +168,18 @@ pub fn expand_book(error_channel: Sender<Box<dyn Diagnostic>>, book: &mut Book)
|
||||
let info = res.extract_book_info();
|
||||
entries.insert(res.name.to_string(), (res, info));
|
||||
}
|
||||
Derive::Getters => {
|
||||
for res in derive_getters(rec.name.range, rec) {
|
||||
let info = res.extract_book_info();
|
||||
entries.insert(res.name.to_string(), (res, info));
|
||||
}
|
||||
}
|
||||
Derive::Setters => {
|
||||
for res in derive_setters(rec.name.range, rec) {
|
||||
let info = res.extract_book_info();
|
||||
entries.insert(res.name.to_string(), (res, info));
|
||||
}
|
||||
}
|
||||
other => {
|
||||
error_channel
|
||||
.send(Box::new(PassError::CannotDerive(other.to_string(), val)))
|
||||
|
Loading…
Reference in New Issue
Block a user