Compare commits

...

3 Commits

11 changed files with 286 additions and 297 deletions

View File

@@ -6,6 +6,7 @@ orcxdb = "xtask orcxdb"
[env] [env]
CARGO_WORKSPACE_DIR = { value = "", relative = true } CARGO_WORKSPACE_DIR = { value = "", relative = true }
ORCHID_EXTENSIONS = "target/debug/orchid_std" ORCHID_EXTENSIONS = "target/debug/orchid_std"
#ORCHID_EXTENSIONS = "target/debug/orchid-std-piped"
ORCHID_DEFAULT_SYSTEMS = "orchid::std;orchid::macros" ORCHID_DEFAULT_SYSTEMS = "orchid::std;orchid::macros"
ORCHID_LOG_BUFFERS = "true" ORCHID_LOG_BUFFERS = "true"
RUST_BACKTRACE = "1" RUST_BACKTRACE = "1"

View File

@@ -24,6 +24,8 @@ jobs:
- name: Run tests - name: Run tests
run: $HOME/.cargo/bin/cargo test --verbose run: $HOME/.cargo/bin/cargo test --verbose
- name: Clippy - name: Clippy
run: cargo clippy run: $HOME/.cargo/bin/cargo clippy
- name: Formatting - name: Formatting
run: cargo fmt +nightly --check run: $HOME/.cargo/bin/cargo +nightly fmt --check
- name: No unqualified imports from orchid_api
run: $HOME/.cargo/bin/cargo xtask check-api-refs

13
.github/FUNDING.yml vendored
View File

@@ -1,13 +0,0 @@
# These are supported funding model platforms
github: lbfalvy
patreon: lbfalvy
open_collective: # Replace with a single Open Collective username
ko_fi: lbfalvy
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -18,7 +18,7 @@ use memo_map::MemoMap;
use never::Never; use never::Never;
use orchid_api_traits::{Decode, Encode, enc_vec}; use orchid_api_traits::{Decode, Encode, enc_vec};
use orchid_base::error::OrcRes; use orchid_base::error::OrcRes;
use orchid_base::format::{FmtCtx, FmtCtxImpl, FmtUnit, take_first}; use orchid_base::format::{FmtCtx, FmtCtxImpl, FmtUnit, Format, take_first};
use orchid_base::logging::log; use orchid_base::logging::log;
use orchid_base::name::Sym; use orchid_base::name::Sym;
use task_local::task_local; use task_local::task_local;
@@ -93,10 +93,28 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
}) })
} }
fn call(&self, AtomCtx(_, id): AtomCtx, arg: Expr) -> LocalBoxFuture<'_, GExpr> { fn call(&self, AtomCtx(_, id): AtomCtx, arg: Expr) -> LocalBoxFuture<'_, GExpr> {
Box::pin(async move { take_atom(id.unwrap()).await.dyn_call(arg).await }) Box::pin(async move {
writeln!(
log("msg"),
"owned call {} {}",
take_first(&AtomReadGuard::new(id.unwrap()).await.dyn_print().await, false),
take_first(&arg.print(&FmtCtxImpl::default()).await, true),
)
.await;
take_atom(id.unwrap()).await.dyn_call(arg).await
})
} }
fn call_ref<'a>(&'a self, AtomCtx(_, id): AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr> { fn call_ref<'a>(&'a self, AtomCtx(_, id): AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr> {
Box::pin(async move { AtomReadGuard::new(id.unwrap()).await.dyn_call_ref(arg).await }) Box::pin(async move {
writeln!(
log("msg"),
"owned call_ref {} {}",
take_first(&AtomReadGuard::new(id.unwrap()).await.dyn_print().await, false),
take_first(&arg.print(&FmtCtxImpl::default()).await, true),
)
.await;
AtomReadGuard::new(id.unwrap()).await.dyn_call_ref(arg).await
})
} }
fn print(&self, AtomCtx(_, id): AtomCtx<'_>) -> LocalBoxFuture<'_, FmtUnit> { fn print(&self, AtomCtx(_, id): AtomCtx<'_>) -> LocalBoxFuture<'_, FmtUnit> {
Box::pin(async move { AtomReadGuard::new(id.unwrap()).await.dyn_print().await }) Box::pin(async move { AtomReadGuard::new(id.unwrap()).await.dyn_print().await })

View File

@@ -34,10 +34,7 @@ impl BuilderCoroutine {
None => panic!("Before the stream ends, we should have gotten a Halt"), None => panic!("Before the stream ends, we should have gotten a Halt"),
Some(Command::Halt(expr)) => expr, Some(Command::Halt(expr)) => expr,
Some(Command::Execute(expr, reply)) => call( Some(Command::Execute(expr, reply)) => call(
lambda(0, [seq( lambda(0, [seq([arg(0)], call(Replier { reply, builder: self }.to_gen().await, [arg(0)]))]),
[arg(0)],
call(Replier { reply, builder: self }.to_gen().await, [arg(0)]),
)]),
[expr], [expr],
), ),
Some(Command::Register(expr, reply)) => Some(Command::Register(expr, reply)) =>
@@ -67,8 +64,8 @@ impl OwnedAtom for Replier {
pub async fn exec<R: ToExpr>(f: impl for<'a> AsyncFnOnce(ExecHandle<'a>) -> R + 'static) -> GExpr { pub async fn exec<R: ToExpr>(f: impl for<'a> AsyncFnOnce(ExecHandle<'a>) -> R + 'static) -> GExpr {
let (cmd_snd, cmd_recv) = channel(0); let (cmd_snd, cmd_recv) = channel(0);
let halt = async { Command::Halt(f(ExecHandle(cmd_snd, PhantomData)).await.to_gen().await) } let halt =
.into_stream(); async { Command::Halt(f(ExecHandle(cmd_snd, PhantomData)).await.to_gen().await) }.into_stream();
let coro = BuilderCoroutine(Rc::new(BuilderCoroutineData { let coro = BuilderCoroutine(Rc::new(BuilderCoroutineData {
receiver: Mutex::new(stream::select(halt, cmd_recv).boxed_local()), receiver: Mutex::new(stream::select(halt, cmd_recv).boxed_local()),
})); }));

View File

@@ -3,6 +3,7 @@ use orchid_api as api;
pub mod atom; pub mod atom;
pub mod atom_owned; pub mod atom_owned;
pub mod atom_thin; pub mod atom_thin;
pub mod binary;
pub mod conv; pub mod conv;
pub mod coroutine_exec; pub mod coroutine_exec;
pub mod entrypoint; pub mod entrypoint;
@@ -20,4 +21,3 @@ pub mod system;
pub mod system_ctor; pub mod system_ctor;
pub mod tokio; pub mod tokio;
pub mod tree; pub mod tree;
pub mod binary;

View File

@@ -103,18 +103,24 @@ impl Expr {
} }
impl Format for Expr { impl Format for Expr {
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit { async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
return print_expr(self, c, Substack::Bottom).await; return print_expr(self, c, Substack::Bottom, &[]).await;
} }
} }
async fn print_expr<'a>( pub async fn print_expr<'a>(
expr: &'a Expr, expr: &'a Expr,
c: &'a (impl FmtCtx + ?Sized + 'a), c: &'a (impl FmtCtx + ?Sized + 'a),
visited: Substack<'_, api::ExprTicket>, visited: Substack<'_, api::ExprTicket>,
id_only: &[api::ExprTicket],
) -> FmtUnit { ) -> FmtUnit {
if visited.iter().any(|id| id == &expr.id()) { if visited.iter().any(|id| id == &expr.id()) {
return "CYCLIC_EXPR".to_string().into(); return "CYCLIC_EXPR".to_string().into();
} }
print_exprkind(&*expr.kind().read().await, c, visited.push(expr.id())).boxed_local().await if id_only.iter().any(|id| id == &expr.id()) {
return format!("{:?}", expr.id()).into();
}
print_exprkind(&*expr.kind().read().await, c, visited.push(expr.id()), id_only)
.boxed_local()
.await
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -138,13 +144,14 @@ impl ExprKind {
} }
impl Format for ExprKind { impl Format for ExprKind {
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit { async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
print_exprkind(self, c, Substack::Bottom).await print_exprkind(self, c, Substack::Bottom, &[]).await
} }
} }
async fn print_exprkind<'a>( async fn print_exprkind<'a>(
ek: &ExprKind, ek: &ExprKind,
c: &'a (impl FmtCtx + ?Sized + 'a), c: &'a (impl FmtCtx + ?Sized + 'a),
visited: Substack<'_, api::ExprTicket>, visited: Substack<'_, api::ExprTicket>,
id_only: &[api::ExprTicket],
) -> FmtUnit { ) -> FmtUnit {
match &ek { match &ek {
ExprKind::Arg => "Arg".to_string().into(), ExprKind::Arg => "Arg".to_string().into(),
@@ -156,10 +163,10 @@ async fn print_exprkind<'a>(
ExprKind::Call(f, x) => tl_cache!(Rc<Variants>: Rc::new(Variants::default() ExprKind::Call(f, x) => tl_cache!(Rc<Variants>: Rc::new(Variants::default()
.unbounded("{0b} {1l}") .unbounded("{0b} {1l}")
.bounded("({0b} {1})"))) .bounded("({0b} {1})")))
.units([print_expr(f, c, visited).await, print_expr(x, c, visited).await]), .units([print_expr(f, c, visited, id_only).await, print_expr(x, c, visited, id_only).await]),
ExprKind::Identity(id) => ExprKind::Identity(id) =>
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("{{{0}}}"))).units([print_expr( tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("{{{0}}}"))).units([print_expr(
id, c, visited, id, c, visited, id_only,
) )
.boxed_local() .boxed_local()
.await]), .await]),
@@ -167,14 +174,14 @@ async fn print_exprkind<'a>(
ExprKind::Lambda(None, body) => tl_cache!(Rc<Variants>: Rc::new(Variants::default() ExprKind::Lambda(None, body) => tl_cache!(Rc<Variants>: Rc::new(Variants::default()
// .unbounded("\\.{0l}") // .unbounded("\\.{0l}")
.bounded("(\\.{0b})"))) .bounded("(\\.{0b})")))
.units([print_expr(body, c, visited).await]), .units([print_expr(body, c, visited, id_only).await]),
ExprKind::Lambda(Some(path), body) => tl_cache!(Rc<Variants>: Rc::new(Variants::default() ExprKind::Lambda(Some(path), body) => tl_cache!(Rc<Variants>: Rc::new(Variants::default()
// .unbounded("\\{0b}. {1l}") // .unbounded("\\{0b}. {1l}")
.bounded("(\\{0b}. {1b})"))) .bounded("(\\{0b}. {1b})")))
.units([format!("{path}").into(), print_expr(body, c, visited).await]), .units([format!("{path}").into(), print_expr(body, c, visited, id_only).await]),
ExprKind::Seq(l, r) => ExprKind::Seq(l, r) =>
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("[{0b}]{1l}"))) tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("[{0b}]{1l}")))
.units([print_expr(l, c, visited).await, print_expr(r, c, visited).await]), .units([print_expr(l, c, visited, id_only).await, print_expr(r, c, visited, id_only).await]),
} }
} }

View File

@@ -102,11 +102,7 @@ impl Extension {
this.0.ctx.exprs.give_expr(target) this.0.ctx.exprs.give_expr(target)
}, },
api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => { api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => {
if this.is_own_sys(rel.0).await {
this.0.ctx.exprs.take_expr(rel.1); this.0.ctx.exprs.take_expr(rel.1);
} else {
writeln!(log("warn"), "Not our system {:?}", rel.0).await
}
}, },
api::ExtHostNotif::Log(api::Log { category, message }) => api::ExtHostNotif::Log(api::Log { category, message }) =>
write!(log(&es(category).await), "{message}").await, write!(log(&es(category).await), "{message}").await,
@@ -130,7 +126,7 @@ impl Extension {
// Atom printing and interning is never reported because it generates too much // Atom printing and interning is never reported because it generates too much
// noise // noise
if !matches!(req, api::ExtHostReq::ExtAtomPrint(_)) if !matches!(req, api::ExtHostReq::ExtAtomPrint(_))
|| matches!(req, api::ExtHostReq::IntReq(_)) && !matches!(req, api::ExtHostReq::IntReq(_))
{ {
writeln!(log("msg"), "Host received request {req:?}").await; writeln!(log("msg"), "Host received request {req:?}").await;
} }
@@ -299,14 +295,6 @@ impl Extension {
pub fn ctx(&self) -> &Ctx { &self.0.ctx } pub fn ctx(&self) -> &Ctx { &self.0.ctx }
pub fn system_ctors(&self) -> impl Iterator<Item = &SystemCtor> { self.0.systems.iter() } pub fn system_ctors(&self) -> impl Iterator<Item = &SystemCtor> { self.0.systems.iter() }
#[must_use] #[must_use]
pub async fn is_own_sys(&self, id: api::SysId) -> bool {
let Some(sys) = self.ctx().system_inst(id).await else {
writeln!(log("warn"), "Invalid system ID {id:?}").await;
return false;
};
Rc::ptr_eq(&self.0, &sys.ext().0)
}
#[must_use]
pub fn next_pars(&self) -> NonZeroU64 { pub fn next_pars(&self) -> NonZeroU64 {
let mut next_pars = self.0.next_pars.borrow_mut(); let mut next_pars = self.0.next_pars.borrow_mut();
*next_pars = next_pars.checked_add(1).unwrap_or(NonZeroU64::new(1).unwrap()); *next_pars = next_pars.checked_add(1).unwrap_or(NonZeroU64::new(1).unwrap());

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[[bin]] [[bin]]
name = "orchid-std-dbg" name = "orchid-std-piped"
path = "src/main.rs" path = "src/main.rs"
[lib] [lib]

View File

@@ -35,7 +35,9 @@ impl OwnedAtom for MacroBodyArgCollector {
type Refs = Never; type Refs = Never;
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
async fn call_ref(&self, arg: orchid_extension::expr::Expr) -> GExpr { async fn call_ref(&self, arg: orchid_extension::expr::Expr) -> GExpr {
if !self.args.is_empty() {
eprintln!("This is an intermediary value. It should never be copied"); eprintln!("This is an intermediary value. It should never be copied");
}
self.clone().call(arg).await self.clone().call(arg).await
} }
async fn call(mut self, arg: orchid_extension::expr::Expr) -> GExpr { async fn call(mut self, arg: orchid_extension::expr::Expr) -> GExpr {

View File

@@ -111,10 +111,7 @@ fn get_all_extensions<'a>(
for ext_path in args.extension.iter() { for ext_path in args.extension.iter() {
let init = if cfg!(windows) { let init = if cfg!(windows) {
if ext_path.with_extension("dll").exists() { if ext_path.with_extension("dll").exists() {
let dylib = ext_dylib(ext_path.with_extension("dll").as_std_path(), ctx.clone()).await.unwrap()
ext_dylib(ext_path.with_extension("dll").as_std_path(), ctx.clone()).await.unwrap();
eprintln!("Loaded DLL {ext_path}.dll");
dylib
} else if ext_path.with_extension("exe").exists() { } else if ext_path.with_extension("exe").exists() {
ext_command(Command::new(ext_path.with_extension("exe").as_os_str()), ctx.clone()).await? ext_command(Command::new(ext_path.with_extension("exe").as_os_str()), ctx.clone()).await?
} else { } else {
@@ -190,11 +187,9 @@ async fn main() -> io::Result<ExitCode> {
let logger = get_logger(&args); let logger = get_logger(&args);
let logger2 = logger.clone(); let logger2 = logger.clone();
unsafe { STARTUP = Some(Instant::now()) }; unsafe { STARTUP = Some(Instant::now()) };
local_set.spawn_local(async move { local_set.spawn_local(with_stash(async move {
let ctx = &Ctx::new(SpawnerImpl, logger2); let ctx = &Ctx::new(SpawnerImpl, logger2);
with_stash(async { let extensions = get_all_extensions(&args, ctx).try_collect::<Vec<Extension>>().await.unwrap();
let extensions =
get_all_extensions(&args, ctx).try_collect::<Vec<Extension>>().await.unwrap();
time_print(&args, "Extensions loaded"); time_print(&args, "Extensions loaded");
match args.command { match args.command {
Commands::Lex { file } => { Commands::Lex { file } => {
@@ -260,8 +255,7 @@ async fn main() -> io::Result<ExitCode> {
let snippet = Snippet::new(&lexemes[0], lexemes); let snippet = Snippet::new(&lexemes[0], lexemes);
let parse_ctx = let parse_ctx =
HostParseCtxImpl { ctx: ctx.clone(), src: path.clone(), systems: &systems[..] }; HostParseCtxImpl { ctx: ctx.clone(), src: path.clone(), systems: &systems[..] };
match try_with_reporter(parse_item(&parse_ctx, Substack::Bottom, vec![], snippet)) match try_with_reporter(parse_item(&parse_ctx, Substack::Bottom, vec![], snippet)).await
.await
{ {
Ok(items) => Some(items), Ok(items) => Some(items),
Err(e) => { Err(e) => {
@@ -271,8 +265,7 @@ async fn main() -> io::Result<ExitCode> {
} }
}; };
let add_imports = |items: &mut Vec<Item>, imports: &[Import]| { let add_imports = |items: &mut Vec<Item>, imports: &[Import]| {
items items.extend(imports.iter().map(|import| Item::new(import.sr.clone(), import.clone())));
.extend(imports.iter().map(|import| Item::new(import.sr.clone(), import.clone())));
}; };
if discr.is_kw(is("import").await) { if discr.is_kw(is("import").await) {
let Some(import_lines) = process_lexemes(&lexemes).await else { continue }; let Some(import_lines) = process_lexemes(&lexemes).await else { continue };
@@ -294,11 +287,7 @@ async fn main() -> io::Result<ExitCode> {
_ => panic!("Expected exactly one constant declaration from let"), _ => panic!("Expected exactly one constant declaration from let"),
}; };
add_imports(&mut new_lines, &imports); add_imports(&mut new_lines, &imports);
imports.push(Import::new( imports.push(Import::new(input_sr.clone(), VPath::new(path.segs()), const_name.clone()));
input_sr.clone(),
VPath::new(path.segs()),
const_name.clone(),
));
let new_module = ParsedModule::new(true, new_lines); let new_module = ParsedModule::new(true, new_lines);
match with_reporter(root.add_parsed(&new_module, path.clone())).await { match with_reporter(root.add_parsed(&new_module, path.clone())).await {
Ok(new) => root = new, Ok(new) => root = new,
@@ -442,9 +431,7 @@ async fn main() -> io::Result<ExitCode> {
} }
}, },
} }
}) }));
.await;
});
with_interner(local_interner(), with_logger(logger, local_set)).await; with_interner(local_interner(), with_logger(logger, local_set)).await;
let x = *exit_code.borrow(); let x = *exit_code.borrow();
Ok(x) Ok(x)