forked from Orchid/orchid
Compiles again after command subsystem
terrified to start testing
This commit is contained in:
@@ -13,13 +13,16 @@ use substack::Substack;
|
||||
use task_local::task_local;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
use crate::conv::ToExpr;
|
||||
use crate::expr::{BorrowedExprStore, Expr, ExprHandle};
|
||||
use crate::func_atom::{ExprFunc, Fun};
|
||||
use crate::gen_expr::{GExpr, new_atom};
|
||||
use crate::{BorrowedExprStore, Expr, ExprFunc, ExprHandle, Fun, ToExpr, api};
|
||||
|
||||
/// Tokens generated by lexers and parsers
|
||||
///
|
||||
/// See: [GenTok], [Token], [crate::Lexer], [crate::Parser]
|
||||
pub type GenTokTree = TokTree<Expr, GExpr>;
|
||||
/// Tokens generated by lexers and parsers - without location data
|
||||
///
|
||||
/// See: [GenTokTree], [Token], [crate::Lexer], [crate::Parser]
|
||||
pub type GenTok = Token<Expr, GExpr>;
|
||||
|
||||
impl TokenVariant<api::Expression> for GExpr {
|
||||
@@ -41,9 +44,15 @@ impl TokenVariant<api::ExprTicket> for Expr {
|
||||
async fn into_api(self, (): &mut Self::ToApiCtx<'_>) -> api::ExprTicket { self.handle().ticket() }
|
||||
}
|
||||
|
||||
/// Embed a literal value in generated syntax.
|
||||
pub async fn x_tok(x: impl ToExpr) -> GenTok { GenTok::NewExpr(x.to_gen().await) }
|
||||
/// Embed a reference to a constant in generated syntax. The constant doesn't
|
||||
/// need to be visible per export rules, and if it doesn't exist, the expression
|
||||
/// will raise a runtime error
|
||||
pub async fn ref_tok(path: Sym) -> GenTok { GenTok::NewExpr(path.to_gen().await) }
|
||||
|
||||
/// Create a new subtree that is evaluated as-needed, asynchronously, and can
|
||||
/// use its own path to determine its value
|
||||
pub fn lazy(
|
||||
public: bool,
|
||||
name: &str,
|
||||
@@ -51,30 +60,32 @@ pub fn lazy(
|
||||
) -> Vec<GenMember> {
|
||||
vec![GenMember {
|
||||
name: name.to_string(),
|
||||
kind: MemKind::Lazy(LazyMemberFactory::new(cb)),
|
||||
kind: LazyMemKind::Lazy(LazyMemberFactory::new(cb)),
|
||||
comments: vec![],
|
||||
public,
|
||||
}]
|
||||
}
|
||||
/// A constant node in the module tree
|
||||
pub fn cnst(public: bool, name: &str, value: impl ToExpr + Clone + 'static) -> Vec<GenMember> {
|
||||
lazy(public, name, async |_| MemKind::Const(value.to_gen().await))
|
||||
}
|
||||
/// A module in the tree. These can be merged by [merge_trivial]
|
||||
pub fn module(
|
||||
public: bool,
|
||||
name: &str,
|
||||
mems: impl IntoIterator<Item = Vec<GenMember>>,
|
||||
) -> Vec<GenMember> {
|
||||
let (name, kind) = root_mod(name, mems);
|
||||
let (name, kind) = (name.to_string(), LazyMemKind::Mod(mems.into_iter().flatten().collect()));
|
||||
vec![GenMember { name, kind, public, comments: vec![] }]
|
||||
}
|
||||
pub fn root_mod(name: &str, mems: impl IntoIterator<Item = Vec<GenMember>>) -> (String, MemKind) {
|
||||
(name.to_string(), MemKind::module(mems))
|
||||
}
|
||||
/// A Rust function that is passed to Orchid via [Fun]
|
||||
pub fn fun<I, O>(public: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenMember> {
|
||||
let fac =
|
||||
LazyMemberFactory::new(async move |sym| MemKind::Const(new_atom(Fun::new(sym, xf).await)));
|
||||
vec![GenMember { name: name.to_string(), kind: MemKind::Lazy(fac), public, comments: vec![] }]
|
||||
vec![GenMember { name: name.to_string(), kind: LazyMemKind::Lazy(fac), public, comments: vec![] }]
|
||||
}
|
||||
/// A chain of nested modules with names taken from the duble::colon::delimited
|
||||
/// path ultimately containing the elements
|
||||
pub fn prefix(path: &str, items: impl IntoIterator<Item = Vec<GenMember>>) -> Vec<GenMember> {
|
||||
let mut items = items.into_iter().flatten().collect_vec();
|
||||
for step in path.split("::").collect_vec().into_iter().rev() {
|
||||
@@ -82,7 +93,7 @@ pub fn prefix(path: &str, items: impl IntoIterator<Item = Vec<GenMember>>) -> Ve
|
||||
}
|
||||
items
|
||||
}
|
||||
|
||||
/// Add comments to a set of members
|
||||
pub fn comments<'a>(
|
||||
cmts: impl IntoIterator<Item = &'a str>,
|
||||
mut val: Vec<GenMember>,
|
||||
@@ -101,20 +112,20 @@ pub fn comments<'a>(
|
||||
/// - Duplicate constants result in an error
|
||||
/// - A combination of lazy and anything results in an error
|
||||
pub fn merge_trivial(trees: impl IntoIterator<Item = Vec<GenMember>>) -> Vec<GenMember> {
|
||||
let mut all_members = HashMap::<String, (MemKind, Vec<String>)>::new();
|
||||
let mut all_members = HashMap::<String, (LazyMemKind, Vec<String>)>::new();
|
||||
for mem in trees.into_iter().flatten() {
|
||||
assert!(mem.public, "Non-trivial merge in {}", mem.name);
|
||||
match mem.kind {
|
||||
unit @ (MemKind::Const(_) | MemKind::Lazy(_)) => {
|
||||
unit @ (LazyMemKind::Const(_) | LazyMemKind::Lazy(_)) => {
|
||||
let prev = all_members.insert(mem.name.clone(), (unit, mem.comments.into_iter().collect()));
|
||||
assert!(prev.is_none(), "Conflict in trivial tree merge on {}", mem.name);
|
||||
},
|
||||
MemKind::Mod(members) => match all_members.entry(mem.name.clone()) {
|
||||
LazyMemKind::Mod(members) => match all_members.entry(mem.name.clone()) {
|
||||
hashbrown::hash_map::Entry::Vacant(slot) => {
|
||||
slot.insert((MemKind::Mod(members), mem.comments.into_iter().collect()));
|
||||
slot.insert((LazyMemKind::Mod(members), mem.comments.into_iter().collect()));
|
||||
},
|
||||
hashbrown::hash_map::Entry::Occupied(mut old) => match old.get_mut() {
|
||||
(MemKind::Mod(old_items), old_cmts) => {
|
||||
(LazyMemKind::Mod(old_items), old_cmts) => {
|
||||
let mut swap = vec![];
|
||||
std::mem::swap(&mut swap, old_items);
|
||||
*old_items = merge_trivial([swap, members]);
|
||||
@@ -135,7 +146,7 @@ trait_set! {
|
||||
trait LazyMemberCallback =
|
||||
FnOnce(Sym) -> LocalBoxFuture<'static, MemKind> + DynClone
|
||||
}
|
||||
pub struct LazyMemberFactory(Box<dyn LazyMemberCallback>);
|
||||
pub(crate) struct LazyMemberFactory(Box<dyn LazyMemberCallback>);
|
||||
impl LazyMemberFactory {
|
||||
pub fn new(cb: impl AsyncFnOnce(Sym) -> MemKind + Clone + 'static) -> Self {
|
||||
Self(Box::new(|s| cb(s).boxed_local()))
|
||||
@@ -147,10 +158,10 @@ impl Clone for LazyMemberFactory {
|
||||
}
|
||||
|
||||
pub struct GenMember {
|
||||
pub name: String,
|
||||
pub kind: MemKind,
|
||||
pub public: bool,
|
||||
pub comments: Vec<String>,
|
||||
pub(crate) name: String,
|
||||
pub(crate) kind: LazyMemKind,
|
||||
pub(crate) public: bool,
|
||||
pub(crate) comments: Vec<String>,
|
||||
}
|
||||
impl GenMember {
|
||||
pub(crate) async fn into_api(self, tia_cx: &mut impl TreeIntoApiCtx) -> api::Member {
|
||||
@@ -161,16 +172,24 @@ impl GenMember {
|
||||
}
|
||||
}
|
||||
|
||||
/// Items in the tree after deferrals have been resolved
|
||||
pub enum MemKind {
|
||||
Const(GExpr),
|
||||
Mod(Vec<GenMember>),
|
||||
Lazy(LazyMemberFactory),
|
||||
}
|
||||
impl MemKind {
|
||||
pub async fn cnst(val: impl ToExpr) -> Self { Self::Const(val.to_gen().await) }
|
||||
pub fn module(mems: impl IntoIterator<Item = Vec<GenMember>>) -> Self {
|
||||
Self::Mod(mems.into_iter().flatten().collect())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum LazyMemKind {
|
||||
Const(GExpr),
|
||||
Mod(Vec<GenMember>),
|
||||
Lazy(LazyMemberFactory),
|
||||
}
|
||||
impl LazyMemKind {
|
||||
pub(crate) async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MemberKind {
|
||||
match self {
|
||||
Self::Lazy(lazy) => api::MemberKind::Lazy(add_lazy(ctx, lazy)),
|
||||
@@ -189,7 +208,7 @@ impl MemKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MemberRecord {
|
||||
pub(crate) enum MemberRecord {
|
||||
Gen(Vec<IStr>, LazyMemberFactory),
|
||||
Res,
|
||||
}
|
||||
@@ -201,7 +220,7 @@ task_local! {
|
||||
static LAZY_MEMBERS: LazyMemberStore;
|
||||
}
|
||||
|
||||
pub fn with_lazy_member_store<'a>(fut: LocalBoxFuture<'a, ()>) -> LocalBoxFuture<'a, ()> {
|
||||
pub(crate) fn with_lazy_member_store<'a>(fut: LocalBoxFuture<'a, ()>) -> LocalBoxFuture<'a, ()> {
|
||||
Box::pin(LAZY_MEMBERS.scope(LazyMemberStore::default(), fut))
|
||||
}
|
||||
|
||||
@@ -215,7 +234,7 @@ fn add_lazy(cx: &impl TreeIntoApiCtx, fac: LazyMemberFactory) -> api::TreeId {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_lazy(id: api::TreeId) -> (Sym, MemKind) {
|
||||
pub(crate) async fn get_lazy(id: api::TreeId) -> (Sym, LazyMemKind) {
|
||||
let (path, cb) =
|
||||
LAZY_MEMBERS.with(|tbl| match tbl.0.borrow_mut().insert(id, MemberRecord::Res) {
|
||||
None => panic!("Tree for ID not found"),
|
||||
@@ -223,7 +242,10 @@ pub async fn get_lazy(id: api::TreeId) -> (Sym, MemKind) {
|
||||
Some(MemberRecord::Gen(path, cb)) => (path, cb),
|
||||
});
|
||||
let path = Sym::new(path).await.unwrap();
|
||||
(path.clone(), cb.build(path).await)
|
||||
(path.clone(), match cb.build(path).await {
|
||||
MemKind::Const(c) => LazyMemKind::Const(c),
|
||||
MemKind::Mod(m) => LazyMemKind::Mod(m),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) trait TreeIntoApiCtx {
|
||||
@@ -231,7 +253,7 @@ pub(crate) trait TreeIntoApiCtx {
|
||||
fn path(&self) -> impl Iterator<Item = IStr>;
|
||||
}
|
||||
|
||||
pub struct TreeIntoApiCtxImpl<'a> {
|
||||
pub(crate) struct TreeIntoApiCtxImpl<'a> {
|
||||
pub basepath: &'a [IStr],
|
||||
pub path: Substack<'a, IStr>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user