mirror of
https://github.com/HigherOrderCO/Kind1.git
synced 2024-10-26 14:48:27 +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 matching;
|
||||||
pub mod open;
|
pub mod open;
|
||||||
pub mod subst;
|
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
|
.name
|
||||||
.add_segment(rec.constructor.to_str())
|
.add_segment(rec.constructor.to_str())
|
||||||
.add_segment("open");
|
.add_segment("open");
|
||||||
|
|
||||||
|
name.range = rec.constructor.range;
|
||||||
|
|
||||||
let mut types = Telescope::default();
|
let mut types = Telescope::default();
|
||||||
|
|
||||||
for arg in rec.parameters.iter() {
|
for arg in rec.parameters.iter() {
|
||||||
@ -146,7 +148,7 @@ pub fn derive_open(range: Range, rec: &RecordDecl) -> concrete::Entry {
|
|||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
pats,
|
pats,
|
||||||
body,
|
body,
|
||||||
range,
|
range: rec.constructor.range,
|
||||||
})];
|
})];
|
||||||
|
|
||||||
let entry = Entry {
|
let entry = Entry {
|
||||||
@ -155,7 +157,7 @@ pub fn derive_open(range: Range, rec: &RecordDecl) -> concrete::Entry {
|
|||||||
args: types,
|
args: types,
|
||||||
typ: ret_ty,
|
typ: ret_ty,
|
||||||
rules,
|
rules,
|
||||||
range,
|
range: rec.constructor.range,
|
||||||
attrs: Vec::new(),
|
attrs: Vec::new(),
|
||||||
generated_by: Some(rec.name.to_string().clone()),
|
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 std::sync::mpsc::Sender;
|
||||||
|
|
||||||
use fxhash::FxHashMap;
|
use fxhash::FxHashMap;
|
||||||
|
use kind_derive::getters::derive_getters;
|
||||||
use kind_derive::matching::derive_match;
|
use kind_derive::matching::derive_match;
|
||||||
use kind_derive::open::derive_open;
|
use kind_derive::open::derive_open;
|
||||||
|
use kind_derive::setters::derive_setters;
|
||||||
use kind_report::data::Diagnostic;
|
use kind_report::data::Diagnostic;
|
||||||
use kind_span::Locatable;
|
use kind_span::Locatable;
|
||||||
use kind_span::Range;
|
use kind_span::Range;
|
||||||
@ -23,6 +25,8 @@ pub mod uses;
|
|||||||
pub enum Derive {
|
pub enum Derive {
|
||||||
Match,
|
Match,
|
||||||
Open,
|
Open,
|
||||||
|
Getters,
|
||||||
|
Setters
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Derive {
|
impl Display for Derive {
|
||||||
@ -30,6 +34,8 @@ impl Display for Derive {
|
|||||||
match self {
|
match self {
|
||||||
Derive::Match => write!(f, "match"),
|
Derive::Match => write!(f, "match"),
|
||||||
Derive::Open => write!(f, "open"),
|
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 name {
|
||||||
"match" => Some(Derive::Match),
|
"match" => Some(Derive::Match),
|
||||||
"open" => Some(Derive::Open),
|
"open" => Some(Derive::Open),
|
||||||
|
"getters" => Some(Derive::Getters),
|
||||||
|
"setters" => Some(Derive::Setters),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,6 +168,18 @@ pub fn expand_book(error_channel: Sender<Box<dyn Diagnostic>>, book: &mut Book)
|
|||||||
let info = res.extract_book_info();
|
let info = res.extract_book_info();
|
||||||
entries.insert(res.name.to_string(), (res, 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 => {
|
other => {
|
||||||
error_channel
|
error_channel
|
||||||
.send(Box::new(PassError::CannotDerive(other.to_string(), val)))
|
.send(Box::new(PassError::CannotDerive(other.to_string(), val)))
|
||||||
|
Loading…
Reference in New Issue
Block a user