partway towards commands

I got very confused and started mucking about with "spawn" when in fact all I needed was the "inline" extension type in orcx that allows the interpreter to expose custom constants.
This commit is contained in:
2026-03-13 16:48:42 +01:00
parent cdcca694c5
commit 09cfcb1839
146 changed files with 3582 additions and 2822 deletions

View File

@@ -13,8 +13,10 @@ name = "orchid_std"
path = "src/lib.rs"
[dependencies]
async-event = "0.2.1"
async-fn-stream = { version = "0.1.0", path = "../async-fn-stream" }
async-once-cell = "0.5.4"
chrono = "0.4.43"
futures = { version = "0.3.31", features = ["std"], default-features = false }
hashbrown = "0.16.1"
itertools = "0.14.0"

View File

@@ -17,7 +17,7 @@ use orchid_extension::dylib_main;
use orchid_extension::entrypoint::ExtensionBuilder;
pub fn builder() -> ExtensionBuilder {
ExtensionBuilder::new("orchid-std::main").system(StdSystem).system(MacroSystem)
ExtensionBuilder::new("orchid-std::main").system(StdSystem::default()).system(MacroSystem)
}
dylib_main! { builder() }

View File

@@ -1,13 +1,12 @@
use std::borrow::Cow;
use never::Never;
use orchid_base::format::fmt;
use orchid_extension::atom::{Atomic, TAtom};
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
use orchid_base::fmt;
use orchid_extension::conv::ToExpr;
use orchid_extension::coroutine_exec::exec;
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::{GExpr, new_atom};
use orchid_extension::gen_expr::new_atom;
use orchid_extension::{Atomic, OwnedAtom, OwnedVariant, TAtom};
use crate::macros::mactree::{MacTok, MacTree};
@@ -25,7 +24,7 @@ impl OwnedAtom for InstantiateTplCall {
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
type Refs = Never;
// Technically must be supported but shouldn't actually ever be called
async fn call_ref(&self, arg: Expr) -> GExpr {
async fn call_ref(&self, arg: Expr) -> impl ToExpr {
if !self.argv.is_empty() {
eprintln!(
"Copying partially applied instantiate_tpl call. This is an internal value.\
@@ -34,11 +33,11 @@ impl OwnedAtom for InstantiateTplCall {
}
self.clone().call(arg).await
}
async fn call(mut self, arg: Expr) -> GExpr {
async fn call(mut self, arg: Expr) -> impl ToExpr {
exec(async move |mut h| {
match h.exec::<TAtom<MacTree>>(arg.clone()).await {
Err(_) => panic!("Expected a macro param, found {}", fmt(&arg).await),
Ok(t) => self.argv.push(own(&t).await),
Ok(t) => self.argv.push(t.own().await),
};
if self.argv.len() < self.argc {
return new_atom(self);
@@ -52,7 +51,5 @@ impl OwnedAtom for InstantiateTplCall {
new_atom(ret)
})
.await
.to_gen()
.await
}
}

View File

@@ -3,15 +3,13 @@ use std::pin::pin;
use futures::{FutureExt, StreamExt, stream};
use hashbrown::HashMap;
use itertools::Itertools;
use orchid_base::error::{OrcRes, report, with_reporter};
use orchid_base::interner::is;
use orchid_base::name::Sym;
use orchid_base::parse::{Comment, Parsed, Snippet, expect_tok, token_errv, try_pop_no_fluff};
use orchid_base::sym;
use orchid_base::tree::Paren;
use orchid_extension::atom::TAtom;
use orchid_base::{
Comment, OrcRes, Paren, Parsed, Snippet, Sym, expect_tok, is, report, sym, token_errv,
try_pop_no_fluff, with_reporter,
};
use orchid_extension::TAtom;
use orchid_extension::conv::TryFromExpr;
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
use orchid_extension::gen_expr::{call, new_atom};
use orchid_extension::parser::{ConstCtx, PSnippet, PTok, PTokTree, ParsCtx, ParsedLine, Parser};
use crate::macros::mactree::{MacTok, MacTree, MacTreeSeq};
@@ -40,7 +38,7 @@ impl Parser for LetLine {
Ok(vec![ParsedLine::cnst(&line.sr(), &comments, exported, name, async move |ctx| {
let macro_input =
MacTok::S(Paren::Round, with_reporter(dealias_mac_v(&aliased, &ctx)).await?).at(sr.pos());
Ok(call(sym_ref(sym!(macros::resolve)), [new_atom(macro_input)]))
Ok(call(sym!(macros::resolve), new_atom(macro_input)))
})])
}
}
@@ -66,7 +64,7 @@ pub async fn dealias_mac_v(aliased: &MacTreeSeq, ctx: &ConstCtx) -> MacTreeSeq {
pub async fn parse_tokv(line: PSnippet<'_>) -> MacTreeSeq {
if let Some((idx, arg)) = line.iter().enumerate().find_map(|(i, x)| Some((i, x.as_lambda()?))) {
let (head, lambda) = line.split_at(idx as u32);
let (_, body) = lambda.pop_front().unwrap();
let (_, body) = lambda.split_first().unwrap();
let body = parse_tokv(body).boxed_local().await;
let mut all = parse_tokv_no_lambdas(&head).await;
match parse_tok(arg).await {

View File

@@ -1,8 +1,7 @@
use orchid_base::sym;
use orchid_extension::atom::TAtom;
use orchid_extension::atom_owned::own;
use orchid_extension::TAtom;
use orchid_extension::coroutine_exec::exec;
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
use orchid_extension::gen_expr::{call, new_atom};
use orchid_extension::tree::{GenMember, fun, prefix};
use crate::macros::mactree::MacTree;
@@ -12,37 +11,37 @@ use crate::{HomoTpl, UntypedTuple};
pub async fn gen_macro_lib() -> Vec<GenMember> {
prefix("macros", [
fun(true, "resolve", async |tpl: TAtom<MacTree>| resolve(own(&tpl).await).await),
fun(true, "resolve", async |tpl: TAtom<MacTree>| resolve(tpl.own().await).await),
prefix("common", [
build_macro(None, ["..", "_", "="]).finish(),
build_macro(Some(1), ["+"])
.rule(mactreev!("...$" lhs 1 macros::common::+ "...$" rhs 0), [async |[lhs, rhs]| {
call(sym_ref(sym!(std::ops::add::resolve)), [resolve(lhs).await, resolve(rhs).await])
call(sym!(std::ops::add::resolve), (resolve(lhs).await, resolve(rhs).await)).await
}])
.finish(),
build_macro(Some(1), ["-"])
.rule(mactreev!("...$" lhs 1 macros::common::- "...$" rhs 0), [async |[lhs, rhs]| {
call(sym_ref(sym!(std::ops::sub::resolve)), [resolve(lhs).await, resolve(rhs).await])
call(sym!(std::ops::sub::resolve), (resolve(lhs).await, resolve(rhs).await)).await
}])
.finish(),
build_macro(Some(2), ["*"])
.rule(mactreev!("...$" lhs 1 macros::common::* "...$" rhs 0), [async |[lhs, rhs]| {
call(sym_ref(sym!(std::ops::mul::resolve)), [resolve(lhs).await, resolve(rhs).await])
call(sym!(std::ops::mul::resolve), (resolve(lhs).await, resolve(rhs).await)).await
}])
.finish(),
build_macro(Some(2), ["/"])
.rule(mactreev!("...$" lhs 1 macros::common::/ "...$" rhs 0), [async |[lhs, rhs]| {
call(sym_ref(sym!(std::ops::div::resolve)), [resolve(lhs).await, resolve(rhs).await])
call(sym!(std::ops::div::resolve), (resolve(lhs).await, resolve(rhs).await)).await
}])
.finish(),
build_macro(Some(2), ["%"])
.rule(mactreev!("...$" lhs 1 macros::common::% "...$" rhs 0), [async |[lhs, rhs]| {
call(sym_ref(sym!(std::ops::mod::resolve)), [resolve(lhs).await, resolve(rhs).await])
call(sym!(std::ops::mod::resolve), (resolve(lhs).await, resolve(rhs).await)).await
}])
.finish(),
build_macro(Some(3), ["."])
.rule(mactreev!("...$" lhs 1 macros::common::. "...$" rhs 0), [async |[lhs, rhs]| {
call(sym_ref(sym!(std::ops::get::resolve)), [resolve(lhs).await, resolve(rhs).await])
call(sym!(std::ops::get::resolve), (resolve(lhs).await, resolve(rhs).await)).await
}])
.finish(),
build_macro(None, ["comma_list", ","])

View File

@@ -4,16 +4,13 @@ use async_fn_stream::stream;
use async_once_cell::OnceCell;
use futures::StreamExt;
use itertools::Itertools;
use orchid_base::error::{OrcRes, mk_errv, report, with_reporter};
use orchid_base::interner::is;
use orchid_base::parse::{
Comment, Parsed, Snippet, expect_end, expect_tok, line_items, token_errv, try_pop_no_fluff,
use orchid_base::{
Comment, OrcRes, Paren, Parsed, Snippet, Token, clone, expect_end, expect_tok, is, line_items,
mk_errv, report, sym, token_errv, try_pop_no_fluff, with_reporter,
};
use orchid_base::tree::{Paren, Token};
use orchid_base::{clone, sym};
use orchid_extension::atom::TAtom;
use orchid_extension::TAtom;
use orchid_extension::conv::{ToExpr, TryFromExpr};
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
use orchid_extension::gen_expr::{call, new_atom};
use orchid_extension::parser::{PSnippet, ParsCtx, ParsedLine, Parser};
use crate::macros::let_line::{dealias_mac_v, parse_tokv};
@@ -133,7 +130,7 @@ impl Parser for MacroLine {
let macro_input =
MacTok::S(Paren::Round, with_reporter(dealias_mac_v(&body_mactree, &ctx)).await?)
.at(body_sr.pos());
Ok(call(sym_ref(sym!(macros::resolve)), [new_atom(macro_input)]))
Ok(call(sym!(macros::resolve), new_atom(macro_input)))
}))
}
let mac_cell = Rc::new(OnceCell::new());

View File

@@ -1,8 +1,6 @@
use never::Never;
use orchid_base::name::Sym;
use orchid_base::reqnot::{Receipt, ReqHandle};
use orchid_base::sym;
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
use orchid_base::{Receipt, ReqHandle, Sym, sym};
use orchid_extension::{AtomOps, AtomicFeatures};
use orchid_extension::lexer::LexerObj;
use orchid_extension::other_system::SystemHandle;
use orchid_extension::parser::ParserObj;
@@ -34,20 +32,22 @@ impl SystemCtor for MacroSystem {
impl SystemCard for MacroSystem {
type Ctor = Self;
type Req = Never;
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomDynfo>>> {
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomOps>>> {
[
Some(InstantiateTplCall::dynfo()),
Some(MacTree::dynfo()),
Some(Macro::dynfo()),
Some(PhAtom::dynfo()),
Some(MacroBodyArgCollector::dynfo()),
Some(MatcherAtom::dynfo()),
Some(InstantiateTplCall::ops()),
Some(MacTree::ops()),
Some(Macro::ops()),
Some(PhAtom::ops()),
Some(MacroBodyArgCollector::ops()),
Some(MatcherAtom::ops()),
]
}
}
impl System for MacroSystem {
async fn request<'a>(_: Box<dyn ReqHandle<'a> + 'a>, req: Never) -> Receipt<'a> { match req {} }
async fn prelude() -> Vec<Sym> {
async fn request<'a>(&self, _: Box<dyn ReqHandle<'a> + 'a>, req: Never) -> Receipt<'a> {
match req {}
}
async fn prelude(&self) -> Vec<Sym> {
vec![
sym!(macros::common::+),
sym!(macros::common::*),
@@ -65,9 +65,9 @@ impl System for MacroSystem {
sym!(std::fn::[|>]),
]
}
fn lexers() -> Vec<LexerObj> { vec![&MacTreeLexer, &PhLexer] }
fn parsers() -> Vec<ParserObj> { vec![&LetLine, &MacroLine] }
async fn env() -> Vec<GenMember> {
fn lexers(&self) -> Vec<LexerObj> { vec![&MacTreeLexer, &PhLexer] }
fn parsers(&self) -> Vec<ParserObj> { vec![&LetLine, &MacroLine] }
async fn env(&self) -> Vec<GenMember> {
merge_trivial([gen_macro_lib().await, gen_std_macro_lib().await, gen_match_macro_lib().await])
}
}

View File

@@ -2,10 +2,10 @@ use std::borrow::Cow;
use std::rc::Rc;
use never::Never;
use orchid_base::interner::IStr;
use orchid_base::name::Sym;
use orchid_extension::atom::Atomic;
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
use orchid_base::IStr;
use orchid_base::Sym;
use orchid_extension::Atomic;
use orchid_extension::{OwnedAtom, OwnedVariant};
use crate::macros::mactree::MacTreeSeq;
use crate::macros::rule::matcher::Matcher;

View File

@@ -6,16 +6,12 @@ use futures::FutureExt;
use futures::future::join_all;
use hashbrown::HashSet;
use orchid_api_derive::Coding;
use orchid_base::error::OrcErrv;
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
use orchid_base::interner::IStr;
use orchid_base::location::Pos;
use orchid_base::name::Sym;
use orchid_base::tl_cache;
use orchid_base::tree::{Paren, indent};
use orchid_extension::atom::Atomic;
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
use orchid_base::{
FmtCtx, FmtUnit, Format, IStr, OrcErrv, Paren, Pos, Sym, Variants, indent, tl_cache,
};
use orchid_extension::Atomic;
use orchid_extension::expr::Expr;
use orchid_extension::{OwnedAtom, OwnedVariant};
fn union_rc_sets(seq: impl IntoIterator<Item = Rc<HashSet<Sym>>>) -> Rc<HashSet<Sym>> {
let mut acc = Rc::<HashSet<Sym>>::default();
@@ -190,8 +186,10 @@ impl Format for MacTok {
}
.units([body.print(c).await]),
Self::Slot => "$SLOT".into(),
Self::Bottom(err) if err.len() == 1 => format!("Bottom({}) ", err.one().unwrap()).into(),
Self::Bottom(err) => format!("Botttom(\n{}) ", indent(&err.to_string())).into(),
Self::Bottom(err) => match err.one() {
Some(err) => format!("Bottom({err}) ").into(),
None => format!("Botttom(\n{}) ", indent(&err.to_string())).into(),
},
}
}
}
@@ -200,7 +198,7 @@ pub async fn mtreev_fmt<'b>(
v: impl IntoIterator<Item = &'b MacTree>,
c: &(impl FmtCtx + ?Sized),
) -> FmtUnit {
FmtUnit::sequence("", " ", "", None, join_all(v.into_iter().map(|t| t.print(c))).await)
FmtUnit::sequence("", " ", "", true, join_all(v.into_iter().map(|t| t.print(c))).await)
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]

View File

@@ -2,10 +2,8 @@ use std::ops::RangeInclusive;
use futures::FutureExt;
use itertools::chain;
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::interner::is;
use orchid_base::tokens::PARENS;
use orchid_base::tree::Paren;
use orchid_base::Paren;
use orchid_base::{OrcRes, PARENS, is, mk_errv};
use orchid_extension::gen_expr::new_atom;
use orchid_extension::lexer::{LexContext, Lexer, err_not_applicable};
use orchid_extension::parser::p_tree2gen;

View File

@@ -5,18 +5,13 @@ use futures::future::join_all;
use futures::{Stream, StreamExt, stream};
use never::Never;
use orchid_api_derive::Coding;
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::format::fmt;
use orchid_base::interner::is;
use orchid_base::name::Sym;
use orchid_base::sym;
use orchid_extension::atom::{Atomic, TAtom};
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
use orchid_base::{OrcRes, Sym, fmt, is, mk_errv, sym};
use orchid_extension::conv::ToExpr;
use orchid_extension::coroutine_exec::{ExecHandle, exec};
use orchid_extension::expr::{Expr, ExprHandle};
use orchid_extension::gen_expr::{GExpr, arg, bot, call, lambda, new_atom, sym_ref};
use orchid_extension::gen_expr::{GExpr, arg, bot, call, call_v, lam, new_atom};
use orchid_extension::tree::{GenMember, fun, prefix};
use orchid_extension::{Atomic, OwnedAtom, OwnedVariant, TAtom};
use crate::macros::resolve::resolve;
use crate::macros::utils::{build_macro, mactree, mactreev};
@@ -35,8 +30,7 @@ impl MatcherData {
h: &mut ExecHandle<'_>,
val: impl ToExpr,
) -> OrcRes<OrcOpt<HomoTpl<Expr>>> {
h.exec::<OrcOpt<HomoTpl<Expr>>>(call(self.matcher().await.to_gen().await, [val.to_gen().await]))
.await
h.exec::<OrcOpt<HomoTpl<Expr>>>(call(self.matcher().await, val)).await
}
pub fn keys(&self) -> impl Stream<Item = Sym> {
stream(async |mut h| {
@@ -75,8 +69,7 @@ pub async fn gen_match_macro_lib() -> Vec<GenMember> {
"match_one",
async |mat: TAtom<MatcherAtom>, value: Expr, then: Expr, default: Expr| {
exec(async move |mut h| match mat.run_matcher(&mut h, value).await? {
OrcOpt(Some(values)) =>
Ok(call(then.to_gen().await, join_all(values.0.into_iter().map(|x| x.to_gen())).await)),
OrcOpt(Some(values)) => Ok(call_v(then, values.0).await),
OrcOpt(None) => Ok(default.to_gen().await),
})
.await
@@ -93,35 +86,34 @@ pub async fn gen_match_macro_lib() -> Vec<GenMember> {
async |[value, rules]| {
exec(async move |mut h| {
let rule_lines = h
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(sym!(macros::resolve)), [new_atom(
mactree!(macros::common::semi_list "push" rules.clone();),
)]))
.exec::<HomoTpl<TAtom<MacTree>>>(call(
sym!(macros::resolve),
new_atom(mactree!(macros::common::semi_list "push" rules.clone();)),
))
.await?;
let mut rule_atoms = Vec::<(TAtom<MatcherAtom>, Expr)>::new();
for line_mac in rule_lines.0.iter() {
let Tpl((matcher, body)) = h
.exec(call(sym_ref(sym!(macros::resolve)), [new_atom(
mactree!(pattern::_row "push" own(line_mac).await ;),
)]))
.exec(call(
sym!(macros::resolve),
new_atom(mactree!(pattern::_row "push" line_mac.own().await ;)),
))
.await?;
rule_atoms.push((matcher, body));
}
let base_case = lambda(0, [bot(mk_errv(
let base_case = lam::<0>(bot(mk_errv(
is("No branches match").await,
"None of the patterns matches this value",
[rules.pos()],
))]);
)))
.await;
let match_expr = stream::iter(rule_atoms.into_iter().rev())
.fold(base_case, async |tail, (mat, body)| {
lambda(0, [call(sym_ref(sym!(pattern::match_one)), [
mat.to_gen().await,
arg(0),
body.to_gen().await,
call(tail, [arg(0)]),
])])
lam::<0>(call(sym!(pattern::match_one), (mat, arg(0), body, call(tail, arg(0)))))
.await
})
.await;
Ok(call(match_expr, [resolve(value).await]))
Ok(call(match_expr, resolve(value).await))
})
.await
},
@@ -132,16 +124,17 @@ pub async fn gen_match_macro_lib() -> Vec<GenMember> {
.rule(mactreev!(pattern::match_rule ( macros::common::_ )), [async |[]| {
Ok(new_atom(MatcherAtom {
keys: Vec::new(),
matcher: lambda(0, [OrcOpt(Some(Tpl(()))).to_gen().await]).create().await,
matcher: lam::<0>(OrcOpt(Some(Tpl(())))).await.create().await,
}))
}])
.rule(mactreev!(pattern::_row ( "...$" pattern 0 pattern::=> "...$" value 1 )), [
async |[pattern, mut value]| {
exec(async move |mut h| -> OrcRes<Tpl<(TAtom<MatcherAtom>, GExpr)>> {
let Ok(pat) = h
.exec::<TAtom<MatcherAtom>>(call(sym_ref(sym!(macros::resolve)), [new_atom(
mactree!(pattern::match_rule "push" pattern.clone();),
)]))
.exec::<TAtom<MatcherAtom>>(call(
sym!(macros::resolve),
new_atom(mactree!(pattern::match_rule "push" pattern.clone();)),
))
.await
else {
return Err(mk_errv(
@@ -175,7 +168,7 @@ pub async fn gen_match_macro_lib() -> Vec<GenMember> {
};
Ok(new_atom(MatcherAtom {
keys: vec![name.clone()],
matcher: sym_ref(sym!(pattern::ref_body)).to_expr().await,
matcher: sym!(pattern::ref_body).to_expr().await,
}))
}])
.finish(),

View File

@@ -1,13 +1,10 @@
use orchid_api_derive::Coding;
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::format::FmtUnit;
use orchid_base::interner::{es, is};
use orchid_base::parse::{name_char, name_start};
use orchid_extension::atom::Atomic;
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
use orchid_base::{FmtUnit, OrcRes, es, is, mk_errv, name_char, name_start};
use orchid_extension::Atomic;
use orchid_extension::gen_expr::new_atom;
use orchid_extension::lexer::{LexContext, Lexer, err_not_applicable};
use orchid_extension::tree::{GenTokTree, x_tok};
use orchid_extension::{ThinAtom, ThinVariant};
use crate::macros::mactree::{Ph, PhKind};

View File

@@ -1,21 +1,15 @@
use std::collections::VecDeque;
use std::ops::{Add, Range};
use async_fn_stream::stream;
use futures::{FutureExt, StreamExt};
use futures::{FutureExt, StreamExt, stream};
use hashbrown::{HashMap, HashSet};
use itertools::Itertools;
use orchid_base::error::mk_errv;
use orchid_base::format::fmt;
use orchid_base::interner::is;
use orchid_base::location::Pos;
use orchid_base::logging::log;
use orchid_base::name::{NameLike, Sym, VPath};
use orchid_base::tree::Paren;
use orchid_extension::atom::TAtom;
use orchid_extension::atom_owned::own;
use orchid_base::{NameLike, Paren, Pos, Sym, VPath, fmt, is, log, mk_errv};
use orchid_extension::TAtom;
use orchid_extension::conv::ToExpr;
use orchid_extension::coroutine_exec::{ExecHandle, exec};
use orchid_extension::gen_expr::{GExpr, arg, bot, call, lambda, new_atom, sym_ref};
use orchid_extension::coroutine_exec::exec;
use orchid_extension::gen_expr::{GExpr, arg, bot, call, call_v, dyn_lambda, new_atom};
use orchid_extension::reflection::{ReflMemKind, refl};
use subslice_offset::SubsliceOffset;
use substack::Substack;
@@ -37,8 +31,8 @@ pub async fn resolve(val: MacTree) -> GExpr {
.to_sym()
.await;
if let Ok(ReflMemKind::Const) = root.get_by_path(&new_name).await.map(|m| m.kind()) {
let Ok(mac) = h.exec::<TAtom<Macro>>(sym_ref(new_name)).await else { continue };
let mac = own(&mac).await;
let Ok(mac) = h.exec::<TAtom<Macro>>(new_name).await else { continue };
let mac = mac.own().await;
macros.entry(mac.0.canonical_name.clone()).or_insert(mac);
}
}
@@ -63,7 +57,7 @@ pub async fn resolve(val: MacTree) -> GExpr {
}
}
}
let mut rctx = ResolveCtx { h, exclusive, priod };
let mut rctx = ResolveCtx { exclusive, priod };
let gex = resolve_one(&mut rctx, Substack::Bottom, &val).await;
writeln!(
log("debug"),
@@ -85,7 +79,6 @@ pub struct FilteredMacroRecord<'a> {
}
struct ResolveCtx<'a> {
pub h: ExecHandle<'a>,
/// If these overlap, that's a compile-time error
pub exclusive: Vec<FilteredMacroRecord<'a>>,
/// If these overlap, the priorities decide the order. In case of a tie, the
@@ -104,7 +97,7 @@ async fn resolve_one(
MacTok::Value(v) => v.clone().to_gen().await,
MacTok::Name(n) => match arg_stk.iter().position(|arg| arg == n) {
Some(de_bruijn) => arg((arg_stk.len() - 1 - de_bruijn).try_into().unwrap()),
None => sym_ref(n.clone()),
None => n.clone().to_gen().await,
},
MacTok::Lambda(arg, body) => {
let MacTok::Name(name) = &*arg.tok else {
@@ -116,7 +109,7 @@ async fn resolve_one(
};
let arg_pos = arg_stk.len() as u64;
let arg_stk = arg_stk.push(name.clone());
lambda(arg_pos, [resolve_seq(ctx, arg_stk, body.clone(), value.pos()).await])
dyn_lambda(arg_pos, resolve_seq(ctx, arg_stk, body.clone(), value.pos()).await).await
},
MacTok::S(Paren::Round, body) => resolve_seq(ctx, arg_stk, body.clone(), value.pos()).await,
MacTok::S(..) => bot(mk_errv(
@@ -243,7 +236,7 @@ async fn resolve_seq(
// backwards so that the non-overlapping ranges remain valid
let pos = (state.names().flat_map(|r| r.1).cloned().reduce(Pos::add))
.expect("All macro rules must contain at least one locally defined name");
let subex = ctx.h.register(mk_body_call(mac, rule, &state, pos.clone()).await).await;
let subex = mk_body_call(mac, rule, &state, pos.clone()).await.to_expr().await;
new_val.splice(range, [MacTok::Value(subex).at(pos)]);
}
};
@@ -261,22 +254,23 @@ async fn resolve_seq(
let range = pre.len()..new_val.len() - suf.len();
let pos = (state.names().flat_map(|pair| pair.1).cloned().reduce(Pos::add))
.expect("All macro rules must contain at least one locally defined name");
let subex = ctx.h.register(mk_body_call(mac, rule, &state, pos.clone()).await).await;
let subex = mk_body_call(mac, rule, &state, pos.clone()).await.to_expr().await;
std::mem::drop(state);
new_val.splice(range, [MacTok::Value(subex).at(pos)]);
}
}
let exprs = stream(async |mut h| {
let mut exprs = stream(async |mut h| {
for mt in new_val {
h.emit(resolve_one(ctx, arg_stk.clone(), &mt).await).await
}
})
.collect::<Vec<_>>()
.collect::<VecDeque<_>>()
.boxed_local()
.await;
exprs.into_iter().reduce(|f, x| call(f, [x])).expect(
let first = exprs.pop_front().expect(
"We checked first that it isn't empty, and named macros get replaced with their results",
)
);
stream::iter(exprs).fold(first, async |f, x| call(f, x).await).await
}
async fn mk_body_call(mac: &Macro, rule: &Rule, state: &MatchState<'_>, pos: Pos) -> GExpr {
@@ -288,5 +282,5 @@ async fn mk_body_call(mac: &Macro, rule: &Rule, state: &MatchState<'_>, pos: Pos
new_atom(MacTok::S(Paren::Round, MacTreeSeq::new(vec.iter().cloned())).at(Pos::None)),
});
}
call(sym_ref(mac.0.module.suffix([rule.body.clone()]).await), call_args).at(pos.clone())
call_v(mac.0.module.suffix([rule.body.clone()]).await, call_args).await.at(pos.clone())
}

View File

@@ -1,4 +1,4 @@
use orchid_base::name::Sym;
use orchid_base::Sym;
use super::scal_match::scalv_match;
use super::shared::AnyMatcher;

View File

@@ -1,10 +1,7 @@
use futures::FutureExt;
use futures::future::join_all;
use itertools::Itertools;
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::interner::{IStr, is};
use orchid_base::join_ok;
use orchid_base::side::Side;
use orchid_base::{IStr, OrcRes, Side, is, join_ok, mk_errv};
use super::shared::{AnyMatcher, ScalMatcher, VecMatcher};
use super::vec_attrs::vec_attrs;
@@ -137,11 +134,8 @@ async fn mk_scalar(pattern: &MacTree) -> OrcRes<ScalMatcher> {
#[cfg(test)]
mod test {
use orchid_base::interner::local_interner::local_interner;
use orchid_base::interner::{is, with_interner};
use orchid_base::location::SrcRange;
use orchid_base::sym;
use orchid_base::tokens::Paren;
use orchid_base::local_interner::local_interner;
use orchid_base::{Paren, SrcRange, is, sym, with_interner};
use test_executors::spin_on;
use super::mk_any;

View File

@@ -1,9 +1,8 @@
use std::fmt;
use std::rc::Rc;
use orchid_base::error::OrcRes;
use orchid_base::interner::is;
use orchid_base::name::Sym;
use orchid_base::Sym;
use orchid_base::{OrcRes, is};
use super::any_match::any_match;
use super::build::mk_any;

View File

@@ -1,4 +1,4 @@
use orchid_base::name::Sym;
use orchid_base::Sym;
use super::any_match::any_match;
use super::shared::ScalMatcher;

View File

@@ -3,10 +3,8 @@
use std::fmt;
use itertools::Itertools;
use orchid_base::interner::IStr;
use orchid_base::name::Sym;
use orchid_base::side::Side;
use orchid_base::tokens::{PARENS, Paren};
use orchid_base::{PARENS, Paren};
use orchid_base::{IStr, Side, Sym};
pub enum ScalMatcher {
Name(Sym),

View File

@@ -2,11 +2,9 @@
use std::any::Any;
use hashbrown::HashMap;
use orchid_base::interner::IStr;
use orchid_base::join::join_maps;
use orchid_base::location::Pos;
use orchid_base::match_mapping;
use orchid_base::name::Sym;
use orchid_base::Pos;
use orchid_base::Sym;
use orchid_base::{IStr, join_maps, match_mapping};
use crate::macros::MacTree;

View File

@@ -1,4 +1,4 @@
use orchid_base::interner::IStr;
use orchid_base::IStr;
use crate::macros::mactree::{Ph, PhKind};
use crate::macros::{MacTok, MacTree};

View File

@@ -1,7 +1,7 @@
use std::cmp::Ordering;
use itertools::Itertools;
use orchid_base::name::Sym;
use orchid_base::Sym;
use super::scal_match::scalv_match;
use super::shared::VecMatcher;

View File

@@ -1,10 +1,10 @@
use futures::StreamExt;
use orchid_base::sym;
use orchid_extension::atom::TAtom;
use orchid_extension::TAtom;
use orchid_extension::conv::ToExpr;
use orchid_extension::coroutine_exec::exec;
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
use orchid_extension::gen_expr::{call, new_atom};
use orchid_extension::tree::{GenMember, fun, prefix};
use crate::macros::match_macros::MatcherAtom;
@@ -36,19 +36,15 @@ pub async fn gen_option_macro_lib() -> Vec<GenMember> {
.await?;
Ok(new_atom(MatcherAtom {
keys: sub.keys().collect().await,
matcher: h
.register(call(sym_ref(sym!(std::option::is_some_body)), [sub.to_gen().await]))
.await,
matcher: call(sym!(std::option::is_some_body), sub).await.create().await,
}))
})
},
])
.rule(mactreev!(pattern::match_rule(std::option::none)), [|[]: [_; _]| {
exec(async |mut h| {
Ok(new_atom(MatcherAtom {
keys: vec![],
matcher: h.register(sym_ref(sym!(std::option::is_none_body))).await,
}))
.rule(mactreev!(pattern::match_rule(std::option::none)), [async |[]: [_; _]| {
new_atom(MatcherAtom {
keys: vec![],
matcher: sym!(std::option::is_none_body).to_expr().await,
})
}])
.finish(),

View File

@@ -1,10 +1,9 @@
use orchid_base::sym;
use orchid_extension::atom::TAtom;
use orchid_extension::atom_owned::own;
use orchid_extension::TAtom;
use orchid_extension::conv::ToExpr;
use orchid_extension::coroutine_exec::exec;
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
use orchid_extension::gen_expr::{call, new_atom};
use orchid_extension::tree::{GenMember, prefix};
use crate::macros::resolve::resolve;
@@ -17,22 +16,19 @@ pub async fn gen_record_macro_lib() -> Vec<GenMember> {
.rule(mactreev!(std::record::r[ "...$" elements 0 ]), [async |[elements]: [_; _]| {
exec(async move |mut h| {
let tup = h
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(sym!(macros::resolve)), [new_atom(
mactree!((macros::common::comma_list "push" elements ;)),
)]))
.exec::<HomoTpl<TAtom<MacTree>>>(call(
sym!(macros::resolve),
new_atom(mactree!((macros::common::comma_list "push" elements ;))),
))
.await?;
let mut record = sym_ref(sym!(std::record::empty));
let mut record = sym!(std::record::empty).to_gen().await;
for item_exprh in tup.0 {
let Tpl((key, value)) = h
.exec::<Tpl<(TAtom<IntStrAtom>, Expr)>>(
resolve(mactree!(std::record::_row "push" own(&item_exprh).await ;)).await,
resolve(mactree!(std::record::_row "push" item_exprh.own().await ;)).await,
)
.await?;
record = call(sym_ref(sym!(std::record::set)), [
record.to_gen().await,
key.to_gen().await,
value.to_gen().await,
]);
record = call(sym!(std::record::set), (record, key, value)).await;
}
Ok(record)
})

View File

@@ -1,12 +1,10 @@
use futures::{StreamExt, stream};
use orchid_base::error::OrcRes;
use orchid_base::sym;
use orchid_extension::atom::TAtom;
use orchid_extension::atom_owned::own;
use orchid_base::{OrcRes, sym};
use orchid_extension::TAtom;
use orchid_extension::conv::ToExpr;
use orchid_extension::coroutine_exec::exec;
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::{GExpr, call, new_atom, sym_ref};
use orchid_extension::gen_expr::{GExpr, call, new_atom};
use orchid_extension::tree::{GenMember, fun, prefix};
use crate::macros::match_macros::MatcherAtom;
@@ -19,19 +17,19 @@ pub async fn gen_tuple_macro_lib() -> Vec<GenMember> {
.rule(mactreev!(std::tuple::t [ "...$" elements 0 ]), [|[elements]: [_; _]| {
exec(async move |mut h| {
let tup = h
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(sym!(macros::resolve)), [
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym!(macros::resolve),
new_atom(mactree!((macros::common::comma_list "push" elements ;))),
]))
))
.await?;
let val = stream::iter(&tup.0[..])
.fold(sym_ref(sym!(std::tuple::empty)), async |head, new| {
call(sym_ref(sym!(std::tuple::cat)), [
.fold(sym!(std::tuple::empty).to_gen().await, async |head, new| {
call(sym!(std::tuple::cat), (
head,
call(sym_ref(sym!(std::tuple::one)), [call(
sym_ref(sym!(macros::resolve)),
[new.clone().to_gen().await],
)]),
])
call(sym!(std::tuple::one), call(
sym!(macros::resolve),
new.clone(),
)),
)).await
})
.await;
Ok(val)
@@ -58,25 +56,24 @@ pub async fn gen_tuple_macro_lib() -> Vec<GenMember> {
fn parse_tpl(elements: MacTree, tail_matcher: Option<MacTree>) -> impl Future<Output = GExpr> {
exec(async move |mut h| -> OrcRes<GExpr> {
let tup = h
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(sym!(macros::resolve)), [new_atom(
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym!(macros::resolve), new_atom(
mactree!((macros::common::comma_list "push" elements ;)),
)]))
)))
.await?;
let mut subs = Vec::with_capacity(tup.0.len());
for mac_a in &tup.0[..] {
let mac = own(mac_a).await;
let sub = h
.exec::<TAtom<MatcherAtom>>(call(sym_ref(sym!(macros::resolve)), [new_atom(
mactree!(pattern::match_rule ("push" mac ;)),
)]))
.exec::<TAtom<MatcherAtom>>(call(sym!(macros::resolve), new_atom(
mactree!(pattern::match_rule ("push" mac_a.own().await ;)),
)))
.await?;
subs.push(sub);
}
let tail_matcher = match tail_matcher {
Some(mac) => Some(
h.exec::<TAtom<MatcherAtom>>(call(sym_ref(sym!(macros::resolve)), [new_atom(
h.exec::<TAtom<MatcherAtom>>(call(sym!(macros::resolve), new_atom(
mactree!(pattern::match_rule "push" mac ;),
)]))
)))
.await?,
),
None => None,
@@ -87,10 +84,10 @@ fn parse_tpl(elements: MacTree, tail_matcher: Option<MacTree>) -> impl Future<Ou
.chain(stream::iter(&tail_matcher).flat_map(|mat| mat.keys()))
.collect()
.await,
matcher: call(sym_ref(sym!(std::tuple::matcher_body)), [
HomoTpl(subs).to_gen().await,
OrcOpt(tail_matcher).to_gen().await,
])
matcher: call(sym!(std::tuple::matcher_body), (
HomoTpl(subs),
OrcOpt(tail_matcher),
))
.to_expr()
.await,
}))
@@ -118,8 +115,8 @@ fn tuple_matcher_body(
None => (),
Some(tail_mat) => {
let tail_tpl = stream::iter(&value.0[children.0.len()..])
.fold(sym_ref(sym!(std::tuple::empty)), async |prefix, new| {
call(sym_ref(sym!(std::tuple::cat)), [prefix, new.clone().to_gen().await])
.fold(sym!(std::tuple::empty).to_gen().await, async |prefix, new| {
call(sym!(std::tuple::cat), (prefix, new.clone())).await
})
.await;
match tail_mat.run_matcher(&mut h, tail_tpl).await? {

View File

@@ -6,13 +6,11 @@ use futures::StreamExt;
use futures::future::LocalBoxFuture;
use itertools::{Itertools, chain};
use never::Never;
use orchid_base::interner::is;
use orchid_base::name::{NameLike, Sym, VPath};
use orchid_extension::atom::{Atomic, TAtom};
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
use orchid_base::{NameLike, Sym, VPath, is};
use orchid_extension::conv::ToExpr;
use orchid_extension::gen_expr::{GExpr, new_atom, sym_ref};
use orchid_extension::gen_expr::{GExpr, new_atom};
use orchid_extension::tree::{GenMember, MemKind, cnst, lazy};
use orchid_extension::{Atomic, OwnedAtom, OwnedVariant, TAtom};
use crate::macros::macro_value::{Macro, MacroData, Rule};
use crate::macros::mactree::MacTreeSeq;
@@ -41,10 +39,10 @@ impl OwnedAtom for MacroBodyArgCollector {
self.clone().call(arg).await
}
async fn call(mut self, arg: orchid_extension::expr::Expr) -> GExpr {
let atom = (TAtom::downcast(arg.handle()).await).unwrap_or_else(|_| {
let atom = (TAtom::<MacTree>::downcast(arg.handle()).await).unwrap_or_else(|_| {
panic!("This is an intermediary value, the argument types are known in advance")
});
self.args.push(own(&atom).await);
self.args.push(atom.own().await);
if self.argc == self.args.len() {
(self.cb)(self.args).await.to_gen().await
} else {
@@ -142,7 +140,7 @@ impl MacroBuilder {
.name_with_suffix(is(&format!("__macro__{name}")).await)
.to_sym()
.await;
MemKind::Const(sym_ref(main_const_name))
MemKind::Const(main_const_name.to_gen().await)
})
});
chain!(main_const, kw_consts, body_consts).collect()
@@ -159,29 +157,29 @@ macro_rules! mactreev_impl {
(@RECUR $ret:ident) => {};
(@RECUR $ret:ident "..$" $name:ident $prio:literal $($tail:tt)*) => {
$ret.push($crate::macros::mactree::MacTok::Ph($crate::macros::mactree::Ph{
name: orchid_base::interner::is(stringify!($name)).await,
name: orchid_base::is(stringify!($name)).await,
kind: $crate::macros::mactree::PhKind::Vector{ at_least_one: false, priority: $prio }
}).at(orchid_base::location::Pos::Inherit));
}).at(orchid_base::Pos::Inherit));
$crate::macros::utils::mactreev_impl!(@RECUR $ret $($tail)*);
};
(@RECUR $ret:ident "...$" $name:ident $prio:literal $($tail:tt)*) => {
$ret.push($crate::macros::mactree::MacTok::Ph($crate::macros::mactree::Ph{
name: orchid_base::interner::is(stringify!($name)).await,
name: orchid_base::is(stringify!($name)).await,
kind: $crate::macros::mactree::PhKind::Vector{ at_least_one: true, priority: $prio }
}).at(orchid_base::location::Pos::Inherit));
}).at(orchid_base::Pos::Inherit));
$crate::macros::utils::mactreev_impl!(@RECUR $ret $($tail)*);
};
(@RECUR $ret:ident "$" $name:ident $($tail:tt)*) => {
$ret.push($crate::macros::mactree::MacTok::Ph($crate::macros::mactree::Ph{
name: orchid_base::interner::is(stringify!(name)).await,
name: orchid_base::is(stringify!(name)).await,
kind: $crate::macros::mactree::PhKind::Scalar
}).at(orchid_base::location::Pos::Inherit));
}).at(orchid_base::Pos::Inherit));
$crate::macros::utils::mactreev_impl!(@RECUR $ret $($tail)*);
};
(@RECUR $ret:ident "Val" $arg:expr ; $($tail:tt)*) => {
$ret.push(
$crate::macros::mactree::MacTok::Value($arg)
.at(orchid_base::location::Pos::Inherit)
.at(orchid_base::Pos::Inherit)
);
$crate::macros::utils::mactreev_impl!(@RECUR $ret $($tail)*);
};
@@ -200,16 +198,16 @@ macro_rules! mactreev_impl {
};
(@RECUR $ret:ident "l_" $arg:expr ; ($($body:tt)*) $($tail:tt)*) => {
$ret.push(MacTok::Lambda(
MacTok::Name($arg).at(orchid_base::location::Pos::Inherit),
MacTok::Name($arg).at(orchid_base::Pos::Inherit),
$crate::macros::utils::mactreev!($($body)*)
).at(orchid_base::location::Pos::Inherit));
).at(orchid_base::Pos::Inherit));
$crate::macros::utils::mactreev_impl!(@RECUR $ret $($tail)*);
};
(@RECUR $ret:ident "l" $argh:tt $(:: $arg:tt)+ ($($body:tt)*) $($tail:tt)*) => {
$ret.push(MacTok::Lambda(
MacTok::Name(sym!($argh $(:: $arg)+).await).at(orchid_base::location::Pos::Inherit),
MacTok::Name(sym!($argh $(:: $arg)+).await).at(orchid_base::Pos::Inherit),
$crate::macros::utils::mactreev!($($body)*)
).at(orchid_base::location::Pos::Inherit));
).at(orchid_base::Pos::Inherit));
$crate::macros::utils::mactreev_impl!(@RECUR $ret $($tail)*);
};
(@RECUR $ret:ident $name:literal $($tail:tt)*) => {
@@ -218,42 +216,42 @@ macro_rules! mactreev_impl {
"{} was treated as a name, but it doesn't have a namespace prefix",
$name
);
let sym = orchid_base::name::Sym::parse(
let sym = orchid_base::Sym::parse(
$name
).await.expect("Empty string in sym literal in Rust");
$ret.push(
$crate::macros::mactree::MacTok::Name(sym)
.at(orchid_base::location::Pos::Inherit)
.at(orchid_base::Pos::Inherit)
);
$crate::macros::utils::mactreev_impl!(@RECUR $ret $($tail)*);
};
(@RECUR $ret:ident ( $($body:tt)* ) $($tail:tt)*) => {
$ret.push(
$crate::macros::mactree::MacTok::S(
orchid_base::tree::Paren::Round,
orchid_base::Paren::Round,
$crate::macros::utils::mactreev!($($body)*)
)
.at(orchid_base::location::Pos::Inherit)
.at(orchid_base::Pos::Inherit)
);
$crate::macros::utils::mactreev_impl!(@RECUR $ret $($tail)*);
};
(@RECUR $ret:ident [ $($body:tt)* ] $($tail:tt)*) => {
$ret.push(
$crate::macros::mactree::MacTok::S(
orchid_base::tree::Paren::Square,
orchid_base::Paren::Square,
$crate::macros::utils::mactreev!($($body)*)
)
.at(orchid_base::location::Pos::Inherit)
.at(orchid_base::Pos::Inherit)
);
$crate::macros::utils::mactreev_impl!(@RECUR $ret $($tail)*);
};
(@RECUR $ret:ident { $($body:tt)* } $($tail:tt)*) => {
$ret.push(
$crate::macros::mactree::MacTok::S(
orchid_base::tree::Paren::Curly,
orchid_base::Paren::Curly,
$crate::macros::utils::mactreev!($($body)*)
)
.at(orchid_base::location::Pos::Inherit)
.at(orchid_base::Pos::Inherit)
);
$crate::macros::utils::mactreev_impl!(@RECUR $ret $($tail)*);
};
@@ -267,7 +265,7 @@ macro_rules! mactreev_impl {
let sym = orchid_base::sym!($($munched)*);
$ret.push(
$crate::macros::mactree::MacTok::Name(sym)
.at(orchid_base::location::Pos::Inherit)
.at(orchid_base::Pos::Inherit)
);
$crate::macros::utils::mactreev_impl!(@RECUR $ret $($tail)*);
};

View File

@@ -4,8 +4,8 @@ use std::rc::Rc;
use futures::AsyncWrite;
use orchid_api_traits::Encode;
use orchid_extension::atom::Atomic;
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
use orchid_extension::Atomic;
use orchid_extension::{DeserializeCtx, OwnedAtom, OwnedVariant};
#[derive(Clone)]
pub struct BlobAtom(pub(crate) Rc<Vec<u8>>);

View File

@@ -1,9 +1,7 @@
use std::rc::Rc;
use orchid_base::error::{OrcErrv, mk_errv};
use orchid_base::interner::is;
use orchid_extension::atom::TAtom;
use orchid_extension::atom_owned::own;
use orchid_base::{OrcErrv, is, mk_errv};
use orchid_extension::TAtom;
use orchid_extension::func_atom::get_arg_posv;
use orchid_extension::gen_expr::new_atom;
use orchid_extension::tree::{GenMember, comments, fun, prefix};
@@ -32,7 +30,7 @@ pub fn gen_binary_lib() -> Vec<GenMember> {
["Appends a binary blob to another", "|type: Blob -> Blob -> Blob|"],
fun(true, "concat", async |a: TAtom<BlobAtom>, b: TAtom<BlobAtom>| {
new_atom(BlobAtom(Rc::new(
own(&a).await.0.iter().chain(&own(&b).await.0[..]).copied().collect(),
a.own().await.0.iter().chain(&b.own().await.0[..]).copied().collect(),
)))
}),
),
@@ -43,7 +41,7 @@ pub fn gen_binary_lib() -> Vec<GenMember> {
"|type: Blob -> Int -> Int -> Blob|",
],
fun(true, "slice", async |a: TAtom<BlobAtom>, Int(start): Int, Int(len): Int| {
let blob = own(&a).await;
let blob = a.own().await;
if start + len > blob.0.len() as i64 {
return Err(bounds_error(format!("{start}+{len}"), &blob, 0..3).await);
}
@@ -57,8 +55,8 @@ pub fn gen_binary_lib() -> Vec<GenMember> {
"|type: Blob -> Blob -> std::option Int|",
],
fun(true, "find", async |haystack: TAtom<BlobAtom>, needle: TAtom<BlobAtom>| {
let haystack_vec = own(&haystack).await;
let needle_vec = own(&needle).await;
let haystack_vec = haystack.own().await;
let needle_vec = needle.own().await;
for i in 0..haystack_vec.0.len() - needle_vec.0.len() {
if haystack_vec.0[i..].starts_with(&needle_vec.0) {
return OrcOpt(Some(Int(i as i64)));
@@ -73,7 +71,7 @@ pub fn gen_binary_lib() -> Vec<GenMember> {
"|type: Blob -> Int -> std::tuple Blob Blob|",
],
fun(true, "split", async |a: TAtom<BlobAtom>, i: Int| {
let v = own(&a).await;
let v = a.own().await;
if v.0.len() < i.0 as usize {
return Err(bounds_error(i.0.to_string(), &v, 1..2).await);
}
@@ -95,7 +93,7 @@ pub fn gen_binary_lib() -> Vec<GenMember> {
true,
"get_int",
async |bin: TAtom<BlobAtom>, Int(start): Int, Int(len): Int, Bool(le): Bool| {
let vec = own(&bin).await;
let vec = bin.own().await;
if start + len > vec.0.len() as i64 {
return Err(bounds_error(format!("{start}+{len}"), &vec, 1..3).await);
}
@@ -139,7 +137,7 @@ pub fn gen_binary_lib() -> Vec<GenMember> {
),
comments(
["Returns the number of bytes in a binary", "|type: Blob -> Int|"],
fun(true, "size", async |blob: TAtom<BlobAtom>| Int(own(&blob).await.0.len() as i64)),
fun(true, "size", async |blob: TAtom<BlobAtom>| Int(blob.own().await.0.len() as i64)),
),
]),
)])

View File

@@ -1,13 +1,10 @@
use orchid_api_derive::Coding;
use orchid_base::error::OrcRes;
use orchid_base::format::FmtUnit;
use orchid_base::sym;
use orchid_extension::atom::{Atomic, TAtom};
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
use orchid_base::{FmtUnit, OrcRes, sym};
use orchid_extension::conv::{ToExpr, TryFromExpr};
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::{GExpr, sym_ref};
use orchid_extension::gen_expr::GExpr;
use orchid_extension::tree::{GenMember, cnst, comments, fun, prefix};
use orchid_extension::{Atomic, TAtom, ThinAtom, ThinVariant};
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Coding)]
pub struct Bool(pub bool);
@@ -28,7 +25,7 @@ impl TryFromExpr for Bool {
}
impl ToExpr for Bool {
async fn to_gen(self) -> GExpr {
sym_ref(if self.0 { sym!(std::true) } else { sym!(std::false) })
if self.0 { sym!(std::true) } else { sym!(std::false) }.to_gen().await
}
}

View File

@@ -0,0 +1,350 @@
use std::borrow::Cow;
use std::cell::RefCell;
use std::cmp::{Ordering, Reverse};
use std::collections::{BinaryHeap, VecDeque};
use std::fmt::Debug;
use std::mem;
use std::num::NonZeroU64;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll, Waker};
use std::time::Instant;
use async_event::Event;
use chrono::TimeDelta;
use futures::channel::{mpsc, oneshot};
use futures::{FutureExt, select};
use hashbrown::HashMap;
use never::Never;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use orchid_base::{FmtCtxImpl, OrcRes};
use orchid_extension::conv::ToExpr;
use orchid_extension::entrypoint::spawn;
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::{GExpr, IntoGExprStream, call, new_atom};
use orchid_extension::system::cted;
use orchid_extension::tree::{GenMember, cnst, comments, fun, prefix};
use orchid_extension::{
Atomic, CmdResult, Continuation, ForeignAtom, Next, OwnedAtom, OwnedVariant, err_not_callable,
err_not_command,
};
use rust_decimal::prelude::Zero;
use tokio::task::{JoinHandle, spawn_local};
use tokio::time::sleep;
use crate::std::std_system::StdReq;
use crate::std::time::OrcDT;
use crate::{StdSystem, api};
#[derive(Clone, Copy, Coding, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct AsyncTaskId(NonZeroU64);
/// Signals to the scheduler that some async work is in progress, and to take
/// ownership of this expression representing the progress of that work. This
/// doesn't have to be called before [FinishAsyncWork] if keeping the work and
/// thus the requesting system alive is not necessary
#[derive(Debug, Clone, Coding, Hierarchy)]
#[extends(FutureReq, StdReq)]
pub struct AddAsyncWork(pub api::ExprTicket);
impl Request for AddAsyncWork {
type Response = AsyncTaskId;
}
/// Signals to the scheduler that some async work has been finished, and to
/// return this expression from a future `std::future::yield` call.
/// If [AddAsyncWork] was called before this, include the [AsyncTaskId] you
/// received to unlink the work from the scheduler so that cleanup is not
/// blocked.
#[derive(Debug, Clone, Coding, Hierarchy)]
#[extends(FutureReq, StdReq)]
pub struct FinishAsyncWork(pub Option<AsyncTaskId>, pub api::ExprTicket);
impl Request for FinishAsyncWork {
type Response = Result<(), SchedulerError>;
}
#[derive(Debug, Clone, Coding)]
pub struct SchedulerError;
#[derive(Debug, Clone, Coding, Hierarchy)]
#[extendable]
#[extends(StdReq)]
pub enum FutureReq {
AddAsyncWork(AddAsyncWork),
FinishAsyncWork(FinishAsyncWork),
}
#[derive(Clone)]
struct Timer {
set_at: Instant,
delay: TimeDelta,
repetition: Option<u64>,
cancelled: Rc<Event>,
action: Expr,
}
impl Timer {
pub fn next_occurrence(&self) -> Instant {
let delay_mult = i32::try_from(self.repetition.unwrap_or(0) + 1).unwrap();
self.set_at + (self.delay * delay_mult).to_std().unwrap()
}
}
impl PartialEq for Timer {
fn eq(&self, other: &Self) -> bool { self.next_occurrence().eq(&other.next_occurrence()) }
}
impl Eq for Timer {}
impl PartialOrd for Timer {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl Ord for Timer {
fn cmp(&self, other: &Self) -> Ordering { self.next_occurrence().cmp(&other.next_occurrence()) }
}
impl Atomic for Timer {
type Variant = OwnedVariant;
type Data = ();
}
impl OwnedAtom for Timer {
type Refs = Never;
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
async fn command(mut self) -> CmdResult {
let sleep_until =
self.set_at + (self.delay * self.repetition.unwrap_or(1) as i32).to_std().unwrap();
let (timer_ready, on_timer_ready) = oneshot::channel();
let task = spawn(self.delay.to_std().unwrap(), async move { mem::drop(timer_ready.send(())) });
let res =
self.cancelled.wait_until_or_timeout(|| Some(()), on_timer_ready.map(mem::drop)).await;
task.abort();
// cancelled
if let Some(()) = res {
return Continuation::default().into();
}
// TODO: add binary API for sleep and
let mut ret = Continuation::default().into();
let mut ret = vec![self.action.to_gen().await];
if let Some(rep) = self.repetition.as_mut() {
*rep = *rep + 1;
ret.push(new_atom(self));
}
Ok(ret)
}
}
struct SchedulerState {
/// Waker to call when async work finishes
finish_waker: Waker,
timer_task: Option<(Instant, JoinHandle<()>)>,
id: NonZeroU64,
background: HashMap<AsyncTaskId, Expr>,
ready: VecDeque<Expr>,
timers: BinaryHeap<Reverse<Timer>>,
}
impl SchedulerState {
fn activate_timers(&mut self, now: Instant) {
while let Some(t) = self.timers.peek()
&& t.0.next_occurrence() < now
{
let mut timer = self.timers.pop().unwrap().0;
let work = timer.action.clone();
self.ready.push_back(work);
if let Some(count) = timer.repetition {
timer.repetition = Some(count + 1);
self.timers.push(Reverse(timer));
}
}
}
}
impl Debug for SchedulerState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SchedulerState").finish_non_exhaustive()
}
}
impl Default for SchedulerState {
fn default() -> Self {
SchedulerState {
background: HashMap::new(),
finish_waker: Waker::noop().clone(),
id: NonZeroU64::MIN,
timer_task: None,
ready: VecDeque::new(),
timers: BinaryHeap::new(),
}
}
}
#[derive(Clone, Debug, Default)]
pub struct Scheduler(Rc<RefCell<SchedulerState>>);
impl Scheduler {
pub(crate) async fn add(&self, req: &AddAsyncWork) -> <AddAsyncWork as Request>::Response {
let expr = Expr::deserialize(req.0).await;
let mut this = self.0.borrow_mut();
let id = AsyncTaskId(this.id);
this.background.insert(id, expr);
this.id = this.id.checked_add(1).unwrap();
id
}
pub(crate) async fn finish(
&self,
req: &FinishAsyncWork,
) -> <FinishAsyncWork as Request>::Response {
let expr = Expr::deserialize(req.1).await;
let mut g = self.0.borrow_mut();
if let Some(id) = req.0 {
g.background.remove(&id);
}
g.ready.push_back(expr);
g.finish_waker.wake_by_ref();
Ok(())
}
}
#[derive(Clone)]
struct Yield;
impl Atomic for Yield {
type Variant = OwnedVariant;
type Data = ();
}
impl OwnedAtom for Yield {
type Refs = Never;
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
async fn command(self) -> OrcRes<()> { Ok(()) }
}
#[derive(Clone)]
struct Spawn(ForeignAtom, ForeignAtom);
impl Atomic for Spawn {
type Variant = OwnedVariant;
type Data = [api::ExprTicket; 2];
}
impl OwnedAtom for Spawn {
type Refs = Never;
async fn val(&self) -> Cow<'_, Self::Data> {
Cow::Owned([self.0.clone().ex().handle().ticket(), self.1.clone().ex().handle().ticket()])
}
async fn command(self) -> OrcRes<impl IntoGExprStream> { Ok((self.1, self.0)) }
}
#[derive(Clone)]
struct Canceller {
cont: Option<Expr>,
cancel: Rc<RefCell<Option<oneshot::Sender<()>>>>,
}
impl Atomic for Canceller {
type Variant = OwnedVariant;
type Data = ();
}
impl OwnedAtom for Canceller {
type Refs = Never;
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
async fn call_ref(&self, arg: Expr) -> impl ToExpr {
match &self.cont {
Some(_) => Err(err_not_callable(&self.print_atom(&FmtCtxImpl::default()).await).await),
None => Ok(new_atom(Self { cont: Some(arg), cancel: self.cancel.clone() })),
}
}
async fn command(self) -> OrcRes<impl IntoGExprStream> {
let Some(cont) = self.cont else {
return Err(err_not_command(&self.print_atom(&FmtCtxImpl::default()).await).await);
};
if let Some(canceller) = self.cancel.borrow_mut().take() {
canceller.send(());
}
Ok(cont)
}
}
#[derive(Clone)]
struct SetTimer {
delay: TimeDelta,
recurring: bool,
action: Expr,
cont: Expr,
}
impl Atomic for SetTimer {
type Variant = OwnedVariant;
type Data = ();
}
impl OwnedAtom for SetTimer {
type Refs = Never;
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
async fn command(self) -> OrcRes<impl IntoGExprStream> {
let (send, recv) = oneshot::channel();
Ok((
new_atom(Timer {
set_at: Instant::now(),
delay: self.delay,
cancelled: Rc::new(recv),
repetition: self.recurring.then_some(1),
action: self.action,
}),
call(
self.cont,
new_atom(Canceller { cont: None, cancel: Rc::new(RefCell::new(Some(send))) }),
),
))
}
}
pub fn gen_future_lib() -> Vec<GenMember> {
prefix("std", [comments(
[
"This library exposes a futures executor, and tools for timing and cooperative multitasking. \
The use of these tools is only possible in a command trampoline, i.e. a caller that always \
defers to the command implementation of an atom.",
"Any command that correctly integrates with this library should return `std::future::yield` \
as its final value on all codepaths, which is the (re)entry point of the trampoline. \
Returning any other command, especially the ones in `std::exit_code` causes the program to \
immediately exit.",
"Cancellers take a continuation, stop whatever process they are associated with from \
proceeding, and call the continuation with information about the cancelled work.",
"|type canceller: \\T ((T -> cmd) -> cmd)|",
],
prefix("future", [
comments(
[
"A command without a continuation that defers control to the queued set of commands.",
"|type: cmd|",
],
cnst(true, "yield", new_atom(Yield)),
),
comments(
[
"Takes two commands and queues both to be executed one after the other.",
"|type: cmd -> cmd -> cmd|",
],
fun(true, "spawn", async |left: ForeignAtom, right: ForeignAtom| {
new_atom(Spawn(left, right))
}),
),
comments(
[
"Takes a time amount to wait, the command to perform after waiting, and a continuation, \
and returns a command that sets a single-fire timeout. The continuation will be \
called with a canceller, which reports true if the task has not yet run.",
"|type: Duration -> cmd -> (canceller bool -> cmd) -> cmd|",
],
fun(true, "timeout", async |OrcDT(delay): OrcDT, action: Expr, cont: Expr| {
new_atom(SetTimer { delay, action, cont, recurring: false })
}),
),
comments(
[
"Takes a time amount to wait between repetitions, the command to perform periodically, \
and a continuation, and returns a command. The continuation will be called with a \
canceller, which reports how many times the interval has run.",
"|type: Duration -> cmd -> (canceller Int -> cmd) -> cmd|",
],
fun(true, "interval", async |OrcDT(delay): OrcDT, action: Expr, cont: Expr| {
new_atom(SetTimer { delay, action, cont, recurring: true })
}),
),
]),
)])
}
fn get_scheduler() -> Scheduler {
let cted = cted();
let std = cted.as_any().downcast_ref::<StdSystem>().unwrap();
let sched = std.sched.get_or_init(Scheduler::default);
sched.clone()
}
pub struct AsyncTaskAtom {}

View File

@@ -0,0 +1 @@
pub mod future_lib;

View File

@@ -1,5 +1,6 @@
pub mod binary;
pub mod boolean;
pub mod future;
pub mod number;
pub mod ops;
pub mod option;
@@ -7,5 +8,7 @@ pub mod protocol;
pub mod record;
pub mod reflection;
pub mod std_system;
pub mod stream;
pub mod string;
pub mod time;
pub mod tuple;

View File

@@ -2,18 +2,11 @@ use std::io;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use orchid_base::error::OrcRes;
use orchid_base::format::FmtUnit;
use orchid_base::name::Sym;
use orchid_base::number::Numeric;
use orchid_base::reqnot::{Receipt, ReqHandle, ReqHandleExt};
use orchid_base::sym;
use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports, TAtom};
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
use orchid_base::{FmtUnit, Numeric, OrcRes, Receipt, ReqHandle, ReqHandleExt, Sym, sym};
use orchid_extension::conv::{ToExpr, TryFromExpr};
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::sym_ref;
use orchid_extension::system::sys_req;
use orchid_extension::{Atomic, MethodSetBuilder, Supports, TAtom, ThinAtom, ThinVariant};
use ordered_float::NotNan;
use rust_decimal::prelude::Zero;
@@ -34,7 +27,7 @@ pub struct Int(pub i64);
impl Atomic for Int {
type Variant = ThinVariant;
type Data = Self;
fn reg_reqs() -> MethodSetBuilder<Self> {
fn reg_methods() -> MethodSetBuilder<Self> {
MethodSetBuilder::new().handle::<ProtocolMethod>().handle::<ToStringMethod>()
}
}
@@ -62,19 +55,19 @@ impl Supports<ProtocolMethod> for Int {
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::add) {
sym_ref(sym!(std::number::add))
sym!(std::number::add)
} else if name == sym!(std::ops::sub) {
sym_ref(sym!(std::number::sub))
sym!(std::number::sub)
} else if name == sym!(std::ops::mul) {
sym_ref(sym!(std::number::mul))
sym!(std::number::mul)
} else if name == sym!(std::ops::div) {
sym_ref(sym!(std::number::idiv))
sym!(std::number::idiv)
} else if name == sym!(std::ops::mod) {
sym_ref(sym!(std::number::imod))
sym!(std::number::imod)
} else {
return hand.reply(req, &None).await;
};
hand.reply(req, &Some(val.create().await.serialize().await)).await
hand.reply(req, &Some(val.to_expr().await.serialize().await)).await
},
}
}
@@ -101,7 +94,7 @@ pub struct Float(pub NotNan<f64>);
impl Atomic for Float {
type Variant = ThinVariant;
type Data = Self;
fn reg_reqs() -> MethodSetBuilder<Self> {
fn reg_methods() -> MethodSetBuilder<Self> {
MethodSetBuilder::new().handle::<ProtocolMethod>().handle::<ToStringMethod>()
}
}
@@ -129,19 +122,19 @@ impl Supports<ProtocolMethod> for Float {
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::add) {
sym_ref(sym!(std::number::add))
sym!(std::number::add)
} else if name == sym!(std::ops::sub) {
sym_ref(sym!(std::number::sub))
sym!(std::number::sub)
} else if name == sym!(std::ops::mul) {
sym_ref(sym!(std::number::mul))
sym!(std::number::mul)
} else if name == sym!(std::ops::div) {
sym_ref(sym!(std::number::fdiv))
sym!(std::number::fdiv)
} else if name == sym!(std::ops::mod) {
sym_ref(sym!(std::number::fmod))
sym!(std::number::fmod)
} else {
return hand.reply(req, &None).await;
};
hand.reply(req, &Some(val.create().await.serialize().await)).await
hand.reply(req, &Some(val.to_expr().await.serialize().await)).await
},
}
}
@@ -172,11 +165,9 @@ impl TryFromExpr for Num {
impl ToExpr for Num {
async fn to_gen(self) -> orchid_extension::gen_expr::GExpr {
match self.0 {
Numeric::Float(f) => Float(f).to_expr().await,
Numeric::Int(i) => Int(i).to_expr().await,
Numeric::Float(f) => Float(f).to_gen().await,
Numeric::Int(i) => Int(i).to_gen().await,
}
.to_gen()
.await
}
}

View File

@@ -1,7 +1,6 @@
use std::ops::RangeInclusive;
use orchid_base::error::OrcRes;
use orchid_base::number::{num_to_errv, parse_num};
use orchid_base::{OrcRes, num_to_errv, parse_num};
use orchid_extension::conv::ToExpr;
use orchid_extension::lexer::{LexContext, Lexer};
use orchid_extension::tree::{GenTokTree, x_tok};
@@ -16,8 +15,7 @@ impl Lexer for NumLexer {
let ends_at = all.find(|c: char| !c.is_ascii_hexdigit() && !"xX._pP".contains(c));
let (chars, tail) = all.split_at(ends_at.unwrap_or(all.len()));
match parse_num(chars) {
Ok(numeric) =>
Ok((tail, x_tok(Num(numeric).to_gen().await).await.at(lxcx.pos_lt(chars.len(), tail)))),
Ok(numeric) => Ok((tail, x_tok(Num(numeric)).await.at(lxcx.pos_lt(chars.len(), tail)))),
Err(e) => Err(num_to_errv(e, lxcx.pos(all), lxcx.src()).await),
}
}

View File

@@ -1,6 +1,4 @@
use orchid_base::error::mk_errv;
use orchid_base::interner::is;
use orchid_base::number::Numeric;
use orchid_base::{Numeric, is, mk_errv};
use orchid_extension::func_atom::get_arg;
use orchid_extension::tree::{GenMember, fun, prefix};
use ordered_float::NotNan;

View File

@@ -1,6 +1,5 @@
use orchid_base::error::OrcRes;
use orchid_base::interner::is;
use orchid_base::parse::{name_char, name_start};
use orchid_base::{name_char, name_start};
use orchid_base::{OrcRes, is};
use orchid_extension::gen_expr::new_atom;
use orchid_extension::lexer::{LexContext, LexedData, Lexer, err_not_applicable};
use orchid_extension::tree::GenTok;

View File

@@ -3,15 +3,12 @@ use std::pin::Pin;
use futures::AsyncWrite;
use orchid_api_traits::Encode;
use orchid_base::error::mk_errv;
use orchid_base::interner::is;
use orchid_base::sym;
use orchid_extension::atom::{Atomic, ForeignAtom, TAtom};
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
use orchid_base::{is, mk_errv, sym};
use orchid_extension::conv::{ToExpr, TryFromExpr};
use orchid_extension::expr::{Expr, ExprHandle};
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
use orchid_extension::gen_expr::{call, new_atom};
use orchid_extension::tree::{GenMember, cnst, fun, prefix};
use orchid_extension::{Atomic, DeserializeCtx, ForeignAtom, OwnedAtom, OwnedVariant, TAtom};
use crate::{OrcString, api};
@@ -37,7 +34,7 @@ impl OwnedAtom for OptAtom {
pub struct OrcOpt<T>(pub Option<T>);
impl<T: TryFromExpr> TryFromExpr for OrcOpt<T> {
async fn try_from_expr(expr: Expr) -> orchid_base::error::OrcRes<Self> {
async fn try_from_expr(expr: Expr) -> orchid_base::OrcRes<Self> {
let atom = TAtom::<OptAtom>::try_from_expr(expr).await?;
match atom.value {
None => Ok(OrcOpt(None)),
@@ -50,9 +47,9 @@ impl<T: TryFromExpr> TryFromExpr for OrcOpt<T> {
impl<T: ToExpr + 'static> ToExpr for OrcOpt<T> {
async fn to_gen(self) -> orchid_extension::gen_expr::GExpr {
if let Some(val) = self.0 {
call(sym_ref(sym!(std::option::some)), [val.to_gen().await])
call(sym!(std::option::some), val).await
} else {
sym_ref(sym!(std::option::none))
sym!(std::option::none).to_gen().await
}
}
}

View File

@@ -1,11 +1,10 @@
use itertools::{Itertools, chain};
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::interner::{IStr, is};
use orchid_base::name::Sym;
use orchid_base::parse::{
use orchid_base::Sym;
use orchid_base::{
Import, Parsed, Snippet, expect_tok, line_items, parse_multiname, token_errv,
};
use orchid_base::tree::{Paren, Token};
use orchid_base::{Paren, Token};
use orchid_base::{IStr, OrcRes, is, mk_errv};
use orchid_extension::parser::{
PTokTree, ParsCtx, ParsedLine, ParsedLineKind, p_tree2gen, p_v2gen,
};

View File

@@ -1,13 +1,9 @@
use std::rc::Rc;
use hashbrown::HashMap;
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::interner::is;
use orchid_base::parse::{Comment, Parsed, expect_end, try_pop_no_fluff};
use orchid_base::sym;
use orchid_base::tree::Token;
use orchid_extension::coroutine_exec::exec;
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
use orchid_base::{Comment, OrcRes, Parsed, Token, expect_end, is, mk_errv, sym, try_pop_no_fluff};
use orchid_extension::conv::ToExpr;
use orchid_extension::gen_expr::{call, new_atom};
use orchid_extension::parser::{PSnippet, ParsCtx, ParsedLine, Parser};
use crate::std::protocol::parse_impls::parse_impls;
@@ -39,17 +35,14 @@ impl Parser for AsProtoParser {
let proto_tag_name = is("__protocol_tag__").await;
let proto_tag_path = id.suffix([proto_tag_name.clone()]).await;
lines.push(ParsedLine::cnst(&line.sr(), &cmts, true, proto_tag_name, async |_ccx| {
exec(async move |mut h| {
let mut new_impls = HashMap::new();
for (k, v) in impls {
new_impls.insert(k.clone(), h.register(sym_ref(id.suffix([v]).await)).await);
}
new_atom(Tag { id, impls: Rc::new(new_impls) })
})
.await
let mut new_impls = HashMap::new();
for (k, v) in impls {
new_impls.insert(k.clone(), id.suffix([v]).await.to_expr().await);
}
new_atom(Tag { id, impls: Rc::new(new_impls) })
}));
lines.push(ParsedLine::cnst(&line.sr(), [], false, is("resolve").await, async move |_| {
call(sym_ref(sym!(std::protocol::resolve)), [sym_ref(proto_tag_path)])
call(sym!(std::protocol::resolve), proto_tag_path).await
}));
Ok(lines)
}

View File

@@ -1,13 +1,9 @@
use std::rc::Rc;
use hashbrown::HashMap;
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::interner::is;
use orchid_base::parse::{Comment, Parsed, expect_end, try_pop_no_fluff};
use orchid_base::sym;
use orchid_base::tree::Token;
use orchid_extension::coroutine_exec::exec;
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
use orchid_base::{Comment, OrcRes, Parsed, Token, expect_end, is, mk_errv, sym, try_pop_no_fluff};
use orchid_extension::conv::ToExpr;
use orchid_extension::gen_expr::{call, new_atom};
use orchid_extension::parser::{PSnippet, ParsCtx, ParsedLine, Parser};
use crate::std::protocol::parse_impls::parse_impls;
@@ -39,22 +35,19 @@ impl Parser for AsTypeParser {
let type_tag_name = is("__type_tag__").await;
let type_tag_path = id.suffix([type_tag_name.clone()]).await;
lines.push(ParsedLine::cnst(&line.sr(), &cmts, true, type_tag_name, async |_ccx| {
exec(async move |mut h| {
let mut new_impls = HashMap::new();
for (k, v) in impls {
new_impls.insert(k.clone(), h.register(sym_ref(id.suffix([v]).await)).await);
}
new_atom(Tag { id, impls: Rc::new(new_impls) })
})
.await
let mut new_impls = HashMap::new();
for (k, v) in impls {
new_impls.insert(k.clone(), id.suffix([v]).await.to_expr().await);
}
new_atom(Tag { id, impls: Rc::new(new_impls) })
}));
let type_tag_path_1 = type_tag_path.clone();
lines.push(ParsedLine::cnst(&line.sr(), [], false, is("wrap").await, async move |_ccx| {
call(sym_ref(sym!(std::protocol::wrap)), [sym_ref(type_tag_path_1)])
call(sym!(std::protocol::wrap), type_tag_path_1).await
}));
let type_tag_path_1 = type_tag_path.clone();
lines.push(ParsedLine::cnst(&line.sr(), [], false, is("unwrap").await, async move |_ccx| {
call(sym_ref(sym!(std::protocol::unwrap)), [sym_ref(type_tag_path_1)])
call(sym!(std::protocol::unwrap), type_tag_path_1).await
}));
Ok(lines)
}

View File

@@ -10,19 +10,16 @@ use itertools::Itertools;
use never::Never;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::format::fmt;
use orchid_base::interner::{ev, is};
use orchid_base::name::{NameLike, Sym, VName};
use orchid_base::reqnot::ReqHandleExt;
use orchid_extension::atom::{AtomMethod, Atomic, ForeignAtom, MethodSetBuilder, Supports, TAtom};
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
use orchid_base::{NameLike, OrcRes, ReqHandleExt, Sym, VName, ev, fmt, is, mk_errv};
use orchid_extension::conv::{ClonableToExprDyn, ToExpr};
use orchid_extension::coroutine_exec::exec;
use orchid_extension::expr::{Expr, ExprHandle};
use orchid_extension::gen_expr::{GExpr, call, new_atom, sym_ref};
use orchid_extension::gen_expr::{GExpr, call, new_atom};
use orchid_extension::system::sys_req;
use orchid_extension::tree::{GenMember, MemKind, cnst, fun, lazy, prefix};
use orchid_extension::{
AtomMethod, Atomic, ForeignAtom, MethodSetBuilder, OwnedAtom, OwnedVariant, Supports, TAtom,
};
use crate::std::std_system::StdReq;
use crate::{StdSystem, api};
@@ -35,7 +32,7 @@ pub struct Tag {
impl Atomic for Tag {
type Data = api::TStrv;
type Variant = OwnedVariant;
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<ProtocolMethod>() }
fn reg_methods() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<ProtocolMethod>() }
}
impl OwnedAtom for Tag {
type Refs = Never;
@@ -44,9 +41,9 @@ impl OwnedAtom for Tag {
impl Supports<ProtocolMethod> for Tag {
async fn handle<'a>(
&self,
hand: Box<dyn orchid_base::reqnot::ReqHandle<'a> + '_>,
hand: Box<dyn orchid_base::ReqHandle<'a> + '_>,
req: ProtocolMethod,
) -> std::io::Result<orchid_base::reqnot::Receipt<'a>> {
) -> std::io::Result<orchid_base::Receipt<'a>> {
match req {
ProtocolMethod::GetTagId(req) => hand.reply(&req, &self.id.to_api()).await,
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) =>
@@ -95,22 +92,22 @@ impl OwnedAtom for Tagged {
impl Supports<ProtocolMethod> for Tagged {
async fn handle<'a>(
&self,
hand: Box<dyn orchid_base::reqnot::ReqHandle<'a> + '_>,
hand: Box<dyn orchid_base::ReqHandle<'a> + '_>,
req: ProtocolMethod,
) -> io::Result<orchid_base::reqnot::Receipt<'a>> {
) -> io::Result<orchid_base::Receipt<'a>> {
self.tag.handle(hand, req).await
}
}
pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr> {
let Some(proto_id) = proto.request(GetTagId).await else {
let Some(proto_id) = proto.call(GetTagId).await else {
return Err(mk_errv(
is("Not a protocol").await,
format!("Protocol ({}) does not have a tag ID", fmt(&proto).await),
[proto.pos()],
));
};
let Some(impl_val_opt) = receiver.request(GetImpl(proto_id)).await else {
let Some(impl_val_opt) = receiver.call(GetImpl(proto_id)).await else {
return Err(mk_errv(
is("Receiver not tagged").await,
format!("The receiver ({}) does not have a type tag", fmt(&receiver).await),
@@ -120,14 +117,14 @@ pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr>
if let Some(impl_val) = impl_val_opt {
return Ok(Expr::deserialize(impl_val).await);
}
let Some(type_id) = receiver.request(GetTagId).await else {
let Some(type_id) = receiver.call(GetTagId).await else {
return Err(mk_errv(
is("Incorrect protocols implementation in extension").await,
format!("The receiver ({}) provides an impl table but no tag ID", fmt(&receiver).await),
[receiver.pos()],
));
};
let Some(impl_val_opt) = proto.request(GetImpl(type_id)).await else {
let Some(impl_val_opt) = proto.call(GetImpl(type_id)).await else {
return Err(mk_errv(
is("Incorrect protocols implementation in extension").await,
format!("Protocol ({}) provides a tag ID but no impl table", fmt(&proto).await),
@@ -147,16 +144,16 @@ pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr>
pub fn gen_protocol_lib() -> Vec<GenMember> {
prefix("std::protocol", [
fun(false, "resolve", async |tag: ForeignAtom, value: ForeignAtom| {
Ok(call(get_impl(value.clone(), tag).await?.to_gen().await, [value.to_gen().await]))
Ok(call(get_impl(value.clone(), tag).await?, value))
}),
fun(false, "wrap", async |tag: TAtom<Tag>, value: Expr| {
new_atom(Tagged { tag: own(&tag).await, value })
new_atom(Tagged { tag: tag.own().await, value })
}),
fun(false, "unwrap", async |tag: TAtom<Tag>, value: TAtom<Tagged>| {
let own_tag = own(&tag).await;
let own_val = own(&value).await;
let own_tag = tag.own().await;
let own_val = value.own().await;
if own_val.tag.id == own_tag.id {
Ok(own_val.value.to_gen().await)
Ok(own_val.value)
} else {
Err(mk_errv(
is("Type mismatch").await,
@@ -259,14 +256,13 @@ pub fn resolver_for(proto: VName) -> impl AsyncFn(ForeignAtom) -> GExpr + Clone
let proto = match cached_proto {
Some(val) => val,
None => {
let proto: ForeignAtom = h
.exec(sym_ref(proto.clone().suffix([is("__protocol_tag__").await]).to_sym().await))
.await?;
let proto: ForeignAtom =
h.exec(proto.clone().suffix([is("__protocol_tag__").await]).to_sym().await).await?;
*proto_cache.borrow_mut() = Some(proto.clone());
proto
},
};
Ok(call(get_impl(atom.clone(), proto).await?.to_gen().await, [atom.to_gen().await]))
Ok(call(get_impl(atom.clone(), proto).await?, atom))
})
.await
}

View File

@@ -8,14 +8,12 @@ use futures::future::join_all;
use hashbrown::HashMap;
use orchid_api_derive::Coding;
use orchid_api_traits::{Encode, Request};
use orchid_base::interner::{IStr, es};
use orchid_base::name::Sym;
use orchid_base::reqnot::{Receipt, ReqHandle, ReqHandleExt};
use orchid_base::sym;
use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports};
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
use orchid_base::{IStr, Receipt, ReqHandle, ReqHandleExt, Sym, es, sym};
use orchid_extension::conv::ToExpr;
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::sym_ref;
use orchid_extension::{
Atomic, DeserializeCtx, MethodSetBuilder, OwnedAtom, OwnedVariant, Supports,
};
use crate::api;
use crate::std::protocol::types::{GetImpl, ProtocolMethod};
@@ -25,7 +23,7 @@ pub struct RecordAtom(pub Rc<HashMap<IStr, Expr>>);
impl Atomic for RecordAtom {
type Data = ();
type Variant = OwnedVariant;
fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<ProtocolMethod>() }
fn reg_methods() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<ProtocolMethod>() }
}
impl OwnedAtom for RecordAtom {
type Refs = Vec<Expr>;
@@ -54,13 +52,13 @@ impl Supports<ProtocolMethod> for RecordAtom {
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::get) {
sym_ref(sym!(std::record::get))
sym!(std::record::get)
} else if name == sym!(std::ops::set) {
sym_ref(sym!(std::record::set))
sym!(std::record::set)
} else {
return hand.reply(req, &None).await;
};
return hand.reply(req, &Some(val.create().await.serialize().await)).await;
return hand.reply(req, &Some(val.to_expr().await.serialize().await)).await;
},
}
}

View File

@@ -2,10 +2,8 @@ use std::rc::Rc;
use hashbrown::HashMap;
use itertools::Itertools;
use orchid_base::error::mk_errv;
use orchid_base::interner::is;
use orchid_extension::atom::TAtom;
use orchid_extension::atom_owned::own;
use orchid_base::{is, mk_errv};
use orchid_extension::TAtom;
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::{arg, new_atom};
use orchid_extension::tree::{GenMember, cnst, fun, prefix};
@@ -17,12 +15,12 @@ pub fn gen_record_lib() -> Vec<GenMember> {
prefix("std::record", [
cnst(true, "empty", new_atom(RecordAtom(Rc::new(HashMap::new())))),
fun(true, "set", async |map: TAtom<RecordAtom>, key: IntStrAtom, val: Expr| {
let mut map = own(&map).await.0.as_ref().clone();
let mut map = map.own().await.0.as_ref().clone();
map.insert(key.0.clone(), val);
new_atom(RecordAtom(Rc::new(map)))
}),
fun(true, "get", async |map: TAtom<RecordAtom>, key: IntStrAtom| {
let record = own(&map).await;
let record = map.own().await;
match record.0.get(&key.0) {
Some(val) => Ok(val.clone()),
None => Err(mk_errv(
@@ -33,7 +31,7 @@ pub fn gen_record_lib() -> Vec<GenMember> {
}
}),
fun(true, "delete", async |map: TAtom<RecordAtom>, key: IntStrAtom| {
let mut map = own(&map).await.0.as_ref().clone();
let mut map = map.own().await.0.as_ref().clone();
map.remove(&key.0);
new_atom(RecordAtom(Rc::new(map)))
}),

View File

@@ -2,12 +2,9 @@ use std::borrow::Cow;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use orchid_base::error::mk_errv;
use orchid_base::interner::{es, is};
use orchid_base::name::{NameLike, Sym};
use orchid_base::reqnot::ReqHandleExt;
use orchid_extension::atom::{Atomic, Supports, TAtom};
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
use orchid_base::{NameLike, ReqHandleExt, Sym, es, is, mk_errv};
use orchid_extension::{Atomic, Supports, TAtom};
use orchid_extension::{OwnedAtom, OwnedVariant};
use orchid_extension::expr::{Expr, ExprHandle};
use orchid_extension::gen_expr::new_atom;
use orchid_extension::system::sys_req;
@@ -33,9 +30,9 @@ impl OwnedAtom for SymAtom {
impl Supports<ToStringMethod> for SymAtom {
async fn handle<'a>(
&self,
hand: Box<dyn orchid_base::reqnot::ReqHandle<'a> + '_>,
hand: Box<dyn orchid_base::ReqHandle<'a> + '_>,
req: ToStringMethod,
) -> std::io::Result<orchid_base::reqnot::Receipt<'a>> {
) -> std::io::Result<orchid_base::Receipt<'a>> {
hand.reply(&req, &self.0.to_string()).await
}
}
@@ -66,7 +63,7 @@ pub async fn gen_sym_lib() -> Vec<GenMember> {
}
}),
fun(true, "to_tpl", async move |sym: TAtom<SymAtom>| {
HomoTpl(own(&sym).await.0.segs().map(|seg| new_atom(IntStrAtom(seg))).collect())
HomoTpl(sym.own().await.0.segs().map(|seg| new_atom(IntStrAtom(seg))).collect())
}),
])
}

View File

@@ -1,12 +1,10 @@
use std::cell::OnceCell;
use std::rc::Rc;
use futures::future::join_all;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_base::interner::es;
use orchid_base::name::Sym;
use orchid_base::reqnot::{Receipt, ReqHandle, ReqHandleExt};
use orchid_base::sym;
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
use orchid_base::{Receipt, ReqHandle, ReqHandleExt, Sym, es, sym};
use orchid_extension::{AtomOps, AtomicFeatures};
use orchid_extension::conv::ToExpr;
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::new_atom;
@@ -22,6 +20,7 @@ use super::string::str_lib::gen_str_lib;
use crate::std::binary::binary_atom::BlobAtom;
use crate::std::binary::binary_lib::gen_binary_lib;
use crate::std::boolean::gen_bool_lib;
use crate::std::future::future_lib::{FutureReq, Scheduler, gen_future_lib};
use crate::std::number::num_atom::{CreateFloat, CreateInt};
use crate::std::number::num_lexer::NumLexer;
use crate::std::ops::gen_ops_lib;
@@ -33,7 +32,9 @@ use crate::std::protocol::types::{CreateTag, Tag, Tagged, gen_protocol_lib};
use crate::std::record::record_atom::{CreateRecord, RecordAtom};
use crate::std::record::record_lib::gen_record_lib;
use crate::std::reflection::sym_atom::{CreateSymAtom, SymAtom, gen_sym_lib};
use crate::std::stream::stream_lib::gen_stream_lib;
use crate::std::string::str_lexer::StringLexer;
use crate::std::time::{CreateDT, gen_time_lib};
use crate::std::tuple::{CreateTuple, Tuple, TupleBuilder, gen_tuple_lib};
use crate::{Float, Int};
@@ -43,47 +44,61 @@ use crate::{Float, Int};
pub enum StdReq {
CreateInt(CreateInt),
CreateFloat(CreateFloat),
CreateDT(CreateDT),
CreateTag(CreateTag),
CreateTuple(CreateTuple),
CreateRecord(CreateRecord),
CreateSymAtom(CreateSymAtom),
FutureReq(FutureReq),
}
#[derive(Debug, Default)]
pub struct StdSystem;
pub struct StdSystem {
pub(crate) sched: OnceCell<Scheduler>,
}
impl SystemCtor for StdSystem {
type Deps = ();
type Instance = Self;
const NAME: &'static str = "orchid::std";
const VERSION: f64 = 0.00_01;
fn inst(&self, _: ()) -> Self::Instance { Self }
fn inst(&self, _: ()) -> Self::Instance { Self::default() }
}
impl SystemCard for StdSystem {
type Ctor = Self;
type Req = StdReq;
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomDynfo>>> {
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomOps>>> {
[
Some(BlobAtom::dynfo()),
Some(Int::dynfo()),
Some(Float::dynfo()),
Some(StrAtom::dynfo()),
Some(IntStrAtom::dynfo()),
Some(OptAtom::dynfo()),
Some(RecordAtom::dynfo()),
Some(Tuple::dynfo()),
Some(TupleBuilder::dynfo()),
Some(Tag::dynfo()),
Some(Tagged::dynfo()),
Some(BlobAtom::ops()),
Some(Int::ops()),
Some(Float::ops()),
Some(StrAtom::ops()),
Some(IntStrAtom::ops()),
Some(OptAtom::ops()),
Some(RecordAtom::ops()),
Some(Tuple::ops()),
Some(TupleBuilder::ops()),
Some(Tag::ops()),
Some(Tagged::ops()),
]
}
}
impl System for StdSystem {
async fn request<'a>(xreq: Box<dyn ReqHandle<'a> + 'a>, req: Self::Req) -> Receipt<'a> {
async fn request<'a>(&self, xreq: Box<dyn ReqHandle<'a> + 'a>, req: Self::Req) -> Receipt<'a> {
match req {
StdReq::FutureReq(req) => {
let sched = self.sched.get_or_init(Scheduler::default);
match req {
FutureReq::AddAsyncWork(req) => xreq.reply(&req, &sched.add(&req).await).await.unwrap(),
FutureReq::FinishAsyncWork(req) =>
xreq.reply(&req, &sched.finish(&req).await).await.unwrap(),
}
},
StdReq::CreateInt(ref req @ CreateInt(int)) =>
xreq.reply(req, &new_atom(int).to_expr().await.serialize().await).await.unwrap(),
StdReq::CreateFloat(ref req @ CreateFloat(float)) =>
xreq.reply(req, &new_atom(float).to_expr().await.serialize().await).await.unwrap(),
StdReq::CreateDT(ref req @ CreateDT(dt)) =>
xreq.reply(req, &new_atom(dt).to_expr().await.serialize().await).await.unwrap(),
StdReq::CreateTuple(ref req @ CreateTuple(ref items)) => {
let tpl = Tuple(Rc::new(join_all(items.iter().copied().map(Expr::deserialize)).await));
let tk = new_atom(tpl).to_expr().await.serialize().await;
@@ -118,9 +133,11 @@ impl System for StdSystem {
},
}
}
fn lexers() -> Vec<LexerObj> { vec![&StringLexer, &NumLexer, &SubscriptLexer] }
fn parsers() -> Vec<ParserObj> { vec![&AsTypeParser, &TypeParser, &AsProtoParser, &ProtoParser] }
async fn env() -> Vec<GenMember> {
fn lexers(&self) -> Vec<LexerObj> { vec![&StringLexer, &NumLexer, &SubscriptLexer] }
fn parsers(&self) -> Vec<ParserObj> {
vec![&AsTypeParser, &TypeParser, &AsProtoParser, &ProtoParser]
}
async fn env(&self) -> Vec<GenMember> {
merge_trivial([
gen_bool_lib(),
gen_num_lib(),
@@ -132,9 +149,12 @@ impl System for StdSystem {
gen_sym_lib().await,
gen_ops_lib(),
gen_binary_lib(),
gen_stream_lib(),
gen_time_lib(),
gen_future_lib(),
])
}
async fn prelude() -> Vec<Sym> {
async fn prelude(&self) -> Vec<Sym> {
vec![sym!(std), sym!(std::tuple), sym!(std::option), sym!(std::record), sym!(std::string)]
}
}

View File

@@ -0,0 +1,2 @@
pub mod stream_cmds;
pub mod stream_lib;

View File

@@ -0,0 +1,48 @@
use std::borrow::Cow;
use std::rc::Rc;
use never::Never;
use orchid_base::{OrcRes, fmt, is, mk_errv};
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::{GExpr, bot, call, new_atom};
use orchid_extension::stream_reqs::{ReadLimit, ReadReq};
use orchid_extension::{Atomic, ForeignAtom, OwnedAtom, OwnedVariant};
use crate::std::binary::binary_atom::BlobAtom;
#[derive(Clone, Debug)]
pub struct ReadStreamCmd {
pub hand: ForeignAtom,
pub limit: ReadLimit,
pub succ: Expr,
pub fail: Expr,
}
impl Atomic for ReadStreamCmd {
type Variant = OwnedVariant;
type Data = ();
}
impl OwnedAtom for ReadStreamCmd {
type Refs = Never;
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
async fn command(self) -> OrcRes<Option<GExpr>> {
match self.hand.call(ReadReq(self.limit)).await {
None => Err(mk_errv(
is("Atom is not readable").await,
format!("Expected a readable stream handle, found {}", fmt(&self.hand).await),
[self.hand.pos()],
)),
Some(Err(e)) => Ok(Some(
call(
self.fail,
bot(mk_errv(
is(e.kind.message()).await,
format!("An error occurred while reading: {}", e.message),
[self.hand.pos(), self.succ.pos().await],
)),
)
.await,
)),
Some(Ok(v)) => Ok(Some(call(self.succ, new_atom(BlobAtom(Rc::new(v)))).await)),
}
}
}

View File

@@ -0,0 +1,37 @@
use orchid_base::{is, mk_errv};
use orchid_extension::ForeignAtom;
use orchid_extension::expr::Expr;
use orchid_extension::func_atom::get_arg;
use orchid_extension::gen_expr::new_atom;
use orchid_extension::stream_reqs::ReadLimit;
use orchid_extension::tree::{GenMember, comments, fun, prefix};
use crate::Int;
use crate::std::stream::stream_cmds::ReadStreamCmd;
pub fn gen_stream_lib() -> Vec<GenMember> {
prefix("std", [comments(
["Read from and write to byte streams"],
prefix("stream", [
fun(true, "read_bin", async |hand: ForeignAtom, succ: Expr, fail: Expr| {
new_atom(ReadStreamCmd { hand, succ, fail, limit: ReadLimit::End })
}),
fun(true, "read_until", async |hand: ForeignAtom, delim: Int, succ: Expr, fail: Expr| {
let Ok(end) = delim.0.try_into() else {
return Err(mk_errv(
is("Byte out of range").await,
format!(
"{} doesn't fit into a byte and cannot be used as a delimiter for reading",
delim.0
),
[get_arg(1).pos().await],
));
};
Ok(new_atom(ReadStreamCmd { hand, succ, fail, limit: ReadLimit::Delimiter(end) }))
}),
fun(true, "read_bytes", async |hand: ForeignAtom, count: Int, succ: Expr, fail: Expr| {
Int(todo!())
}),
]),
)])
}

View File

@@ -7,17 +7,14 @@ use std::rc::Rc;
use futures::AsyncWrite;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::{Encode, Request};
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::format::{FmtCtx, FmtUnit};
use orchid_base::interner::{IStr, es, is};
use orchid_base::name::Sym;
use orchid_base::reqnot::{Receipt, ReqHandle, ReqHandleExt};
use orchid_base::sym;
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TAtom};
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
use orchid_extension::conv::TryFromExpr;
use orchid_base::{
FmtCtx, FmtUnit, IStr, OrcRes, Receipt, ReqHandle, ReqHandleExt, Sym, es, is, mk_errv, sym,
};
use orchid_extension::conv::{ToExpr, TryFromExpr};
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::sym_ref;
use orchid_extension::{
AtomMethod, Atomic, DeserializeCtx, MethodSetBuilder, OwnedAtom, OwnedVariant, Supports, TAtom,
};
use crate::std::protocol::types::{GetImpl, ProtocolMethod};
use crate::std::string::to_string::ToStringMethod;
@@ -36,7 +33,7 @@ pub struct StrAtom(Rc<String>);
impl Atomic for StrAtom {
type Variant = OwnedVariant;
type Data = ();
fn reg_reqs() -> MethodSetBuilder<Self> {
fn reg_methods() -> MethodSetBuilder<Self> {
MethodSetBuilder::new()
.handle::<StringGetValMethod>()
.handle::<ToStringMethod>()
@@ -92,11 +89,11 @@ impl Supports<ProtocolMethod> for StrAtom {
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::add) {
sym_ref(sym!(std::string::concat))
sym!(std::string::concat)
} else {
return hand.reply(req, &None).await;
};
hand.reply(req, &Some(val.create().await.serialize().await)).await
hand.reply(req, &Some(val.to_expr().await.serialize().await)).await
},
}
}
@@ -107,7 +104,7 @@ pub struct IntStrAtom(pub(crate) IStr);
impl Atomic for IntStrAtom {
type Variant = OwnedVariant;
type Data = orchid_api::TStr;
fn reg_reqs() -> MethodSetBuilder<Self> {
fn reg_methods() -> MethodSetBuilder<Self> {
MethodSetBuilder::new().handle::<ProtocolMethod>().handle::<ToStringMethod>()
}
}
@@ -154,11 +151,11 @@ impl Supports<ProtocolMethod> for IntStrAtom {
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::add) {
sym_ref(sym!(std::string::concat))
sym!(std::string::concat)
} else {
return hand.reply(req, &None).await;
};
hand.reply(req, &Some(val.create().await.serialize().await)).await
hand.reply(req, &Some(val.to_expr().await.serialize().await)).await
},
}
}
@@ -177,7 +174,7 @@ impl OrcString {
pub async fn get_string(&self) -> Rc<String> {
match &self.kind {
OrcStringKind::Int(tok) => es(**tok).await.rc(),
OrcStringKind::Val(atom) => atom.request(StringGetValMethod).await,
OrcStringKind::Val(atom) => atom.call(StringGetValMethod).await,
}
}
}

View File

@@ -1,11 +1,7 @@
use itertools::Itertools;
use orchid_base::error::{OrcErr, OrcErrv, OrcRes, mk_errv};
use orchid_base::interner::is;
use orchid_base::location::SrcRange;
use orchid_base::name::Sym;
use orchid_base::sym;
use orchid_base::tree::{Paren, wrap_tokv};
use orchid_extension::gen_expr::{new_atom, sym_ref};
use orchid_base::{OrcErr, OrcErrv, OrcRes, Paren, SrcRange, Sym, is, mk_errv, sym, wrap_tokv};
use orchid_extension::conv::ToExpr;
use orchid_extension::gen_expr::new_atom;
use orchid_extension::lexer::{LexContext, Lexer, err_not_applicable};
use orchid_extension::parser::p_tree2gen;
use orchid_extension::tree::{GenTok, GenTokTree, ref_tok, x_tok};
@@ -136,7 +132,7 @@ impl Lexer for StringLexer {
let (new_tail, tree) = lctx.recurse(rest).await?;
tail = new_tail;
// wrap the received token in a call to to_str
let to_str = sym_ref(sym!(std::string::to_str));
let to_str = sym!(std::string::to_str).to_gen().await;
let sr = tree.sr();
let inj_to_str_tok = GenTok::NewExpr(to_str).at(sr.map_range(|_| sr.start()..sr.start()));
let to_str_call = GenTok::S(Paren::Round, vec![inj_to_str_tok, p_tree2gen(tree)]).at(sr);

View File

@@ -1,15 +1,11 @@
use std::rc::Rc;
use orchid_base::error::mk_errv;
use orchid_base::format::fmt;
use orchid_base::interner::is;
use orchid_base::sym;
use orchid_extension::atom::ForeignAtom;
use orchid_extension::conv::ToExpr;
use orchid_base::{fmt, is, mk_errv, sym};
use orchid_extension::ForeignAtom;
use orchid_extension::coroutine_exec::exec;
use orchid_extension::expr::Expr;
use orchid_extension::func_atom::get_arg;
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
use orchid_extension::gen_expr::{call, new_atom};
use orchid_extension::tree::{GenMember, comments, fun, prefix};
use unicode_segmentation::UnicodeSegmentation;
@@ -154,13 +150,13 @@ pub fn gen_str_lib() -> Vec<GenMember> {
fun(true, "to_str", async |input: Expr| {
exec(async move |mut h| {
if let Ok(atom) = h.exec::<ForeignAtom>(input.clone()).await {
if let Some(str) = atom.request(ToStringMethod).await {
if let Some(str) = atom.call(ToStringMethod).await {
return new_atom(StrAtom::new(Rc::new(str)));
}
let proto_ref = sym_ref(sym!(std::string::to_string::__protocol_tag__));
let proto_ref = sym!(std::string::to_string::__protocol_tag__);
let proto = h.exec(proto_ref).await.expect("This protocol is defined in this system");
if let Ok(cb) = get_impl(atom.clone(), proto).await {
return call(cb.to_gen().await, [atom.to_gen().await]).to_gen().await;
return call(cb, atom).await;
}
}
return new_atom(StrAtom::new(Rc::new(fmt(&input).await)));

View File

@@ -1,6 +1,6 @@
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use orchid_extension::atom::AtomMethod;
use orchid_extension::AtomMethod;
/// Method version of std::string::to_string protocol for atoms
#[derive(Coding, Clone, Debug, Hierarchy)]

View File

@@ -0,0 +1,98 @@
use std::borrow::Cow;
use std::time::Instant;
use chrono::TimeDelta;
use never::Never;
use orchid_api::ExprTicket;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use orchid_base::{Numeric, OrcRes};
use orchid_extension::conv::{ToExpr, TryFromExpr};
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::{GExpr, call, new_atom};
use orchid_extension::system::sys_req;
use orchid_extension::tree::{GenMember, fun, prefix};
use orchid_extension::{Atomic, OwnedAtom, OwnedVariant, TAtom, ThinAtom, ThinVariant};
use ordered_float::NotNan;
use crate::std::std_system::StdReq;
use crate::{Float, Int, Num, StdSystem};
#[derive(Clone, Copy, Debug, Coding, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Hierarchy)]
#[extends(StdReq)]
pub struct CreateDT(pub OrcDT);
impl Request for CreateDT {
type Response = ExprTicket;
}
#[derive(Clone, Copy, Debug, Coding, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct OrcDT(pub TimeDelta);
impl Atomic for OrcDT {
type Variant = ThinVariant;
type Data = Self;
}
impl ThinAtom for OrcDT {}
impl ToExpr for OrcDT {
async fn to_gen(self) -> GExpr {
Expr::deserialize(sys_req::<StdSystem, _>(CreateDT(self)).await).await.to_gen().await
}
}
impl TryFromExpr for OrcDT {
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
Ok(TAtom::<OrcDT>::try_from_expr(expr).await?.value)
}
}
#[derive(Clone)]
pub struct InstantAtom(Instant);
impl Atomic for InstantAtom {
type Variant = OwnedVariant;
type Data = ();
}
impl OwnedAtom for InstantAtom {
type Refs = Never;
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
}
#[derive(Clone)]
struct Now(Expr);
impl Atomic for Now {
type Variant = OwnedVariant;
type Data = ();
}
impl OwnedAtom for Now {
type Refs = Never;
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
async fn command(self) -> OrcRes<Option<GExpr>> {
Ok(Some(call(self.0, new_atom(InstantAtom(Instant::now())))))
}
}
pub fn gen_time_lib() -> Vec<GenMember> {
prefix("std::time", [
fun(true, "weeks", async |amount: Int| new_atom(OrcDT(TimeDelta::weeks(amount.0)))),
fun(true, "num_weeks", async |amount: TAtom<OrcDT>| Int(amount.0.num_weeks())),
fun(true, "days", async |amount: Int| new_atom(OrcDT(TimeDelta::days(amount.0)))),
fun(true, "num_days", async |amount: TAtom<OrcDT>| Int(amount.0.num_days())),
fun(true, "hours", async |amount: Int| new_atom(OrcDT(TimeDelta::hours(amount.0)))),
fun(true, "num_hours", async |amount: TAtom<OrcDT>| Int(amount.0.num_hours())),
fun(true, "minutes", async |amount: Int| new_atom(OrcDT(TimeDelta::minutes(amount.0)))),
fun(true, "num_minutes", async |amount: TAtom<OrcDT>| Int(amount.0.num_minutes())),
fun(true, "secs", async |amount: Num| {
new_atom(OrcDT(match amount.0 {
Numeric::Int(i) => TimeDelta::seconds(i),
Numeric::Float(f) =>
TimeDelta::new(f.floor() as i64, (f.fract() * 1_000_000_000_f64).floor() as u32).unwrap(),
}))
}),
fun(true, "num_secs", async |amount: TAtom<OrcDT>| Int(amount.0.num_seconds())),
fun(true, "as_secs", async |amount: TAtom<OrcDT>| {
Float(NotNan::new(amount.0.as_seconds_f64()).unwrap())
}),
fun(true, "milis", async |amount: Int| new_atom(OrcDT(TimeDelta::milliseconds(amount.0)))),
fun(true, "num_millis", async |amount: TAtom<OrcDT>| Int(amount.0.num_milliseconds())),
fun(true, "nanos", async |amount: Int| new_atom(OrcDT(TimeDelta::nanoseconds(amount.0)))),
fun(true, "num_nanos", async |amount: TAtom<OrcDT>| Int(amount.0.num_nanoseconds().unwrap())),
fun(true, "now", async |cb: Expr| new_atom(Now(cb))),
])
}

View File

@@ -8,19 +8,15 @@ use futures::future::join_all;
use never::Never;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
use orchid_base::interner::is;
use orchid_base::name::Sym;
use orchid_base::reqnot::ReqHandleExt;
use orchid_base::sym;
use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports, TAtom};
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant, own};
use orchid_base::{FmtCtx, FmtUnit, Format, OrcRes, ReqHandleExt, Sym, Variants, is, mk_errv, sym};
use orchid_extension::conv::{ToExpr, TryFromExpr};
use orchid_extension::expr::{Expr, ExprHandle};
use orchid_extension::gen_expr::{GExpr, new_atom, sym_ref};
use orchid_extension::gen_expr::{GExpr, new_atom};
use orchid_extension::system::sys_req;
use orchid_extension::tree::{GenMember, cnst, fun, prefix};
use orchid_extension::{
Atomic, DeserializeCtx, MethodSetBuilder, OwnedAtom, OwnedVariant, Supports, TAtom,
};
use crate::std::protocol::types::{GetImpl, ProtocolMethod};
use crate::std::std_system::StdReq;
@@ -32,7 +28,7 @@ pub struct Tuple(pub(super) Rc<Vec<Expr>>);
impl Atomic for Tuple {
type Data = Vec<api::ExprTicket>;
type Variant = OwnedVariant;
fn reg_reqs() -> orchid_extension::atom::MethodSetBuilder<Self> {
fn reg_methods() -> orchid_extension::MethodSetBuilder<Self> {
MethodSetBuilder::new().handle::<ProtocolMethod>()
}
}
@@ -48,29 +44,29 @@ impl OwnedAtom for Tuple {
async fn deserialize(_: impl DeserializeCtx, refs: Self::Refs) -> Self { Self(Rc::new(refs)) }
async fn print_atom<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
Variants::default()
.sequence(self.0.len(), "t[", ", ", "]", Some(true))
.sequence(self.0.len(), "t[\n", ",\n", "\n]", Some(true))
.sequence(self.0.len(), "t[", ", ", "]", true)
.sequence(self.0.len(), "t[\n", ",\n", "\n]", true)
.units_own(join_all(self.0.iter().map(|x| x.print(c))).await)
}
}
impl Supports<ProtocolMethod> for Tuple {
async fn handle<'a>(
&self,
hand: Box<dyn orchid_base::reqnot::ReqHandle<'a> + '_>,
hand: Box<dyn orchid_base::ReqHandle<'a> + '_>,
req: ProtocolMethod,
) -> std::io::Result<orchid_base::reqnot::Receipt<'a>> {
) -> std::io::Result<orchid_base::Receipt<'a>> {
match req {
ProtocolMethod::GetTagId(req) => hand.reply(&req, &sym!(std::tuple).to_api()).await,
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::get) {
sym_ref(sym!(std::tuple::get))
sym!(std::tuple::get)
} else if name == sym!(std::ops::set) {
sym_ref(sym!(std::tuple::set))
sym!(std::tuple::set)
} else {
return hand.reply(req, &None).await;
};
hand.reply(req, &Some(val.create().await.serialize().await)).await
hand.reply(req, &Some(val.to_expr().await.serialize().await)).await
},
}
}
@@ -118,7 +114,7 @@ pub fn gen_tuple_lib() -> Vec<GenMember> {
}),
fun(true, "get", async |tup: TAtom<Tuple>, idx: TAtom<Int>| {
if let Ok(idx) = usize::try_from(idx.0)
&& let Some(val) = own(&tup).await.0.get(idx)
&& let Some(val) = tup.own().await.0.get(idx)
{
return Ok(val.clone());
}
@@ -130,7 +126,7 @@ pub fn gen_tuple_lib() -> Vec<GenMember> {
}),
fun(true, "set", async |tup: TAtom<Tuple>, idx: TAtom<Int>, val: Expr| {
if let Ok(idx) = usize::try_from(idx.0) {
let mut new_vec = own(&tup).await.0.to_vec();
let mut new_vec = tup.own().await.0.to_vec();
if let Some(slot) = new_vec.get_mut(idx) {
*slot = val;
return Ok(new_atom(Tuple(Rc::new(new_vec))));
@@ -147,7 +143,7 @@ pub fn gen_tuple_lib() -> Vec<GenMember> {
}),
fun(true, "cat", async |left: TAtom<Tuple>, right: TAtom<Tuple>| {
new_atom(Tuple(Rc::new(
own(&left).await.0.iter().chain(own(&right).await.0.iter()).cloned().collect(),
left.own().await.0.iter().chain(right.own().await.0.iter()).cloned().collect(),
)))
}),
])
@@ -174,8 +170,7 @@ pub struct Tpl<T>(pub T);
mod tpl_impls {
use itertools::Itertools;
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::interner::is;
use orchid_base::{OrcRes, is, mk_errv};
use orchid_extension::conv::{ToExpr, TryFromExpr};
use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::GExpr;