This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -948,6 +948,7 @@ dependencies = [
|
||||
"orchid-api",
|
||||
"orchid-api-traits",
|
||||
"orchid-base",
|
||||
"orchid-extension",
|
||||
"ordered-float",
|
||||
"pastey",
|
||||
"substack",
|
||||
@@ -981,6 +982,7 @@ dependencies = [
|
||||
"substack",
|
||||
"test_executors",
|
||||
"tokio",
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1708,6 +1710,12 @@ version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
let user = r[ "foo" 1, "bar" t[3, 4] ]
|
||||
let main = user.bar.1
|
||||
let _main = user.bar.1
|
||||
|
||||
let main = "foo" + string::slice "hello" 1 3 + "bar"
|
||||
|
||||
@@ -9,9 +9,9 @@ use orchid_base::interner::is;
|
||||
use orchid_base::location::Pos;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::atom::{AtomicFeatures, ForeignAtom, TAtom, ToAtom};
|
||||
use crate::atom::{AtomicFeatures, ForeignAtom, TAtom};
|
||||
use crate::expr::{Expr, ExprKind};
|
||||
use crate::gen_expr::{GExpr, atom, bot};
|
||||
use crate::gen_expr::{GExpr, bot};
|
||||
|
||||
pub trait TryFromExpr: Sized {
|
||||
fn try_from_expr(expr: Expr) -> impl Future<Output = OrcRes<Self>>;
|
||||
@@ -111,10 +111,6 @@ impl<T: ToExpr> ToExpr for OrcRes<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ToAtom> ToExpr for A {
|
||||
async fn to_gen(self) -> GExpr { atom(self) }
|
||||
}
|
||||
|
||||
impl ToExpr for Never {
|
||||
async fn to_gen(self) -> GExpr { match self {} }
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::atom::Atomic;
|
||||
use crate::atom_owned::{OwnedAtom, OwnedVariant};
|
||||
use crate::conv::{ToExpr, TryFromExpr};
|
||||
use crate::expr::Expr;
|
||||
use crate::gen_expr::{GExpr, arg, call, lambda, seq};
|
||||
use crate::gen_expr::{GExpr, arg, call, lambda, new_atom, seq};
|
||||
|
||||
enum Command {
|
||||
Execute(GExpr, Sender<Expr>),
|
||||
@@ -34,11 +34,11 @@ impl BuilderCoroutine {
|
||||
None => panic!("Before the stream ends, we should have gotten a Halt"),
|
||||
Some(Command::Halt(expr)) => expr,
|
||||
Some(Command::Execute(expr, reply)) => call(
|
||||
lambda(0, [seq([arg(0)], call(Replier { reply, builder: self }.to_gen().await, [arg(0)]))]),
|
||||
lambda(0, [seq([arg(0)], call(new_atom(Replier { reply, builder: self }), [arg(0)]))]),
|
||||
[expr],
|
||||
),
|
||||
Some(Command::Register(expr, reply)) =>
|
||||
call(Replier { reply, builder: self }.to_gen().await, [expr]),
|
||||
call(new_atom(Replier { reply, builder: self }), [expr]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +261,8 @@ impl ExtensionBuilder {
|
||||
let text = es(text).await;
|
||||
let src = Sym::from_api(src).await;
|
||||
let expr_store = BorrowedExprStore::new();
|
||||
let trigger_char = text.chars().nth(pos as usize).unwrap();
|
||||
let tail = &text[pos as usize..];
|
||||
let trigger_char = tail.chars().next().unwrap();
|
||||
let ekey_na = ekey_not_applicable().await;
|
||||
let ekey_cascade = ekey_cascade().await;
|
||||
let lexers = cted().inst().dyn_lexers();
|
||||
@@ -269,7 +270,7 @@ impl ExtensionBuilder {
|
||||
lexers.iter().filter(|l| char_filter_match(l.char_filter(), trigger_char))
|
||||
{
|
||||
let ctx = LexContext::new(&expr_store, &text, id, pos, src.clone());
|
||||
match try_with_reporter(lx.lex(&text[pos as usize..], &ctx)).await {
|
||||
match try_with_reporter(lx.lex(tail, &ctx)).await {
|
||||
Err(e) if e.any(|e| *e == ekey_na) => continue,
|
||||
Err(e) => {
|
||||
let eopt = e.keep_only(|e| *e != ekey_cascade).map(|e| Err(e.to_api()));
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::future::{LocalBoxFuture, join_all};
|
||||
use futures::{AsyncWrite, FutureExt};
|
||||
use itertools::Itertools;
|
||||
use never::Never;
|
||||
@@ -14,6 +14,7 @@ use orchid_api_traits::Encode;
|
||||
use orchid_base::clone;
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::format::{FmtCtx, FmtUnit};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::name::Sym;
|
||||
use task_local::task_local;
|
||||
use trait_set::trait_set;
|
||||
@@ -24,7 +25,7 @@ use crate::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||
use crate::conv::ToExpr;
|
||||
use crate::coroutine_exec::{ExecHandle, exec};
|
||||
use crate::expr::Expr;
|
||||
use crate::gen_expr::GExpr;
|
||||
use crate::gen_expr::{GExpr, new_atom};
|
||||
use crate::system::sys_id;
|
||||
|
||||
trait_set! {
|
||||
@@ -44,6 +45,16 @@ pub fn get_arg(idx: usize) -> Expr {
|
||||
.expect("get_arg called outside ExprFunc")
|
||||
}
|
||||
|
||||
pub fn get_argc() -> usize {
|
||||
ARGV.try_with(|argv| argv.len()).expect("get_arg called outside ExprFunc")
|
||||
}
|
||||
|
||||
pub async fn get_arg_posv(idxes: impl IntoIterator<Item = usize>) -> impl Iterator<Item = Pos> {
|
||||
let args = (ARGV.try_with(|argv| idxes.into_iter().map(|i| &argv[i]).cloned().collect_vec()))
|
||||
.expect("get_arg_posv called outside ExprFunc");
|
||||
join_all(args.iter().map(|expr| expr.pos())).await.into_iter()
|
||||
}
|
||||
|
||||
pub trait ExprFunc<I, O>: Clone + 'static {
|
||||
fn argtyps() -> &'static [TypeId];
|
||||
fn apply<'a>(&self, hand: ExecHandle<'a>, v: Vec<Expr>) -> impl Future<Output = OrcRes<GExpr>>;
|
||||
@@ -123,7 +134,7 @@ impl OwnedAtom for Fun {
|
||||
if new_args.len() == self.record.argtyps.len() {
|
||||
(self.record.fun)(new_args).await.to_gen().await
|
||||
} else {
|
||||
Self { args: new_args, record: self.record.clone(), path: self.path.clone() }.to_gen().await
|
||||
new_atom(Self { args: new_args, record: self.record.clone(), path: self.path.clone() })
|
||||
}
|
||||
}
|
||||
async fn call(self, arg: Expr) -> GExpr { self.call_ref(arg).await }
|
||||
@@ -169,7 +180,7 @@ impl OwnedAtom for Lambda {
|
||||
if new_args.len() == self.record.argtyps.len() {
|
||||
(self.record.fun)(new_args).await.to_gen().await
|
||||
} else {
|
||||
Self { args: new_args, record: self.record.clone() }.to_gen().await
|
||||
new_atom(Self { args: new_args, record: self.record.clone() })
|
||||
}
|
||||
}
|
||||
async fn call(self, arg: Expr) -> GExpr { self.call_ref(arg).await }
|
||||
@@ -181,7 +192,7 @@ mod expr_func_derives {
|
||||
|
||||
use orchid_base::error::OrcRes;
|
||||
|
||||
use super::ExprFunc;
|
||||
use super::{ARGV, ExprFunc};
|
||||
use crate::conv::{ToExpr, TryFromExpr};
|
||||
use crate::func_atom::{ExecHandle, Expr};
|
||||
use crate::gen_expr::GExpr;
|
||||
@@ -200,8 +211,9 @@ mod expr_func_derives {
|
||||
}
|
||||
async fn apply<'a>(&self, _: ExecHandle<'a>, v: Vec<Expr>) -> OrcRes<GExpr> {
|
||||
assert_eq!(v.len(), Self::argtyps().len(), "Arity mismatch");
|
||||
let argv = v.clone();
|
||||
let [$([< $t:lower >],)*] = v.try_into().unwrap_or_else(|_| panic!("Checked above"));
|
||||
Ok(self($($t::try_from_expr([< $t:lower >]).await?,)*).await.to_gen().await)
|
||||
Ok(ARGV.scope(argv, self($($t::try_from_expr([< $t:lower >]).await?,)*)).await.to_gen().await)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,8 @@ impl Format for GExprKind {
|
||||
fn inherit(kind: GExprKind) -> GExpr { GExpr { pos: Pos::Inherit, kind } }
|
||||
|
||||
pub fn sym_ref(path: Sym) -> GExpr { inherit(GExprKind::Const(path)) }
|
||||
pub fn atom<A: ToAtom>(atom: A) -> GExpr { inherit(GExprKind::NewAtom(atom.to_atom_factory())) }
|
||||
/// Creates an expression from a new atom that we own.
|
||||
pub fn new_atom<A: ToAtom>(atom: A) -> GExpr { inherit(GExprKind::NewAtom(atom.to_atom_factory())) }
|
||||
|
||||
pub fn seq(deps: impl IntoIterator<Item = GExpr>, val: GExpr) -> GExpr {
|
||||
fn recur(mut ops: impl Iterator<Item = GExpr>) -> Option<GExpr> {
|
||||
|
||||
@@ -155,7 +155,10 @@ where A: AtomicFeatures {
|
||||
Ok(TAtom { value: *value, untyped: foreign })
|
||||
}
|
||||
|
||||
pub async fn dep_req<Sys: SystemCard, Req: Request + Into<Sys::Req>>(req: Req) -> Req::Response {
|
||||
/// Make a global request to a system that supports this request type. The
|
||||
/// target system must either be the system in which this function is called, or
|
||||
/// one of its direct dependencies.
|
||||
pub async fn sys_req<Sys: SystemCard, Req: Request + Into<Sys::Req>>(req: Req) -> Req::Response {
|
||||
let mut msg = Vec::new();
|
||||
req.into().encode_vec(&mut msg);
|
||||
let cted = cted();
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::api;
|
||||
use crate::conv::ToExpr;
|
||||
use crate::expr::{BorrowedExprStore, Expr, ExprHandle};
|
||||
use crate::func_atom::{ExprFunc, Fun};
|
||||
use crate::gen_expr::{GExpr, sym_ref};
|
||||
use crate::gen_expr::{GExpr, new_atom, sym_ref};
|
||||
|
||||
pub type GenTokTree = TokTree<Expr, GExpr>;
|
||||
pub type GenTok = Token<Expr, GExpr>;
|
||||
@@ -75,7 +75,7 @@ pub fn root_mod(name: &str, mems: impl IntoIterator<Item = Vec<GenMember>>) -> (
|
||||
}
|
||||
pub fn fun<I, O>(public: bool, name: &str, xf: impl ExprFunc<I, O>) -> Vec<GenMember> {
|
||||
let fac =
|
||||
LazyMemberFactory::new(async move |sym| MemKind::Const(Fun::new(sym, xf).await.to_gen().await));
|
||||
LazyMemberFactory::new(async move |sym| MemKind::Const(new_atom(Fun::new(sym, xf).await)));
|
||||
vec![GenMember { name: name.to_string(), kind: MemKind::Lazy(fac), public, comments: vec![] }]
|
||||
}
|
||||
pub fn prefix(path: &str, items: impl IntoIterator<Item = Vec<GenMember>>) -> Vec<GenMember> {
|
||||
|
||||
@@ -22,6 +22,7 @@ num-traits = "0.2.19"
|
||||
orchid-api = { version = "0.1.0", path = "../orchid-api" }
|
||||
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
|
||||
orchid-base = { version = "0.1.0", path = "../orchid-base" }
|
||||
orchid-extension = { version = "0.1.0", path = "../orchid-extension", optional = true }
|
||||
ordered-float = "5.1.0"
|
||||
pastey = "0.2.1"
|
||||
substack = "1.1.1"
|
||||
@@ -33,3 +34,4 @@ unsync-pipe = { version = "0.2.0", path = "../unsync-pipe" }
|
||||
|
||||
[features]
|
||||
tokio = ["dep:tokio", "dep:tokio-util", "dep:libloading"]
|
||||
orchid-extension = ["dep:orchid-extension"]
|
||||
|
||||
@@ -33,6 +33,7 @@ rust_decimal = "1.39.0"
|
||||
subslice-offset = "0.1.1"
|
||||
substack = "1.1.1"
|
||||
tokio = { version = "1.49.0", features = ["full"] }
|
||||
unicode-segmentation = "1.12.0"
|
||||
|
||||
[dev-dependencies]
|
||||
test_executors = "0.4.1"
|
||||
|
||||
@@ -7,7 +7,7 @@ use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::coroutine_exec::exec;
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::gen_expr::GExpr;
|
||||
use orchid_extension::gen_expr::{GExpr, new_atom};
|
||||
|
||||
use crate::macros::mactree::{MacTok, MacTree};
|
||||
|
||||
@@ -41,7 +41,7 @@ impl OwnedAtom for InstantiateTplCall {
|
||||
Ok(t) => self.argv.push(own(&t).await),
|
||||
};
|
||||
if self.argv.len() < self.argc {
|
||||
return self.to_gen().await;
|
||||
return new_atom(self);
|
||||
}
|
||||
let mut args = self.argv.into_iter();
|
||||
let ret = self.tpl.map(&mut false, &mut |mt| match mt.tok() {
|
||||
@@ -49,7 +49,7 @@ impl OwnedAtom for InstantiateTplCall {
|
||||
_ => None,
|
||||
});
|
||||
assert!(args.next().is_none(), "Too many arguments for all slots");
|
||||
ret.to_gen().await
|
||||
new_atom(ret)
|
||||
})
|
||||
.await
|
||||
.to_gen()
|
||||
|
||||
@@ -11,7 +11,7 @@ use orchid_base::sym;
|
||||
use orchid_base::tree::Paren;
|
||||
use orchid_extension::atom::TAtom;
|
||||
use orchid_extension::conv::TryFromExpr;
|
||||
use orchid_extension::gen_expr::{atom, call, sym_ref};
|
||||
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
|
||||
use orchid_extension::parser::{ConstCtx, PSnippet, PTok, PTokTree, ParsCtx, ParsedLine, Parser};
|
||||
|
||||
use crate::macros::mactree::{MacTok, MacTree, MacTreeSeq};
|
||||
@@ -40,7 +40,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)), [atom(macro_input)]))
|
||||
Ok(call(sym_ref(sym!(macros::resolve)), [new_atom(macro_input)]))
|
||||
})])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use orchid_base::sym;
|
||||
use orchid_extension::atom::TAtom;
|
||||
use orchid_extension::atom_owned::own;
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::coroutine_exec::exec;
|
||||
use orchid_extension::gen_expr::{call, sym_ref};
|
||||
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
|
||||
use orchid_extension::tree::{GenMember, fun, prefix};
|
||||
|
||||
use crate::macros::mactree::MacTree;
|
||||
@@ -53,14 +52,14 @@ pub async fn gen_macro_lib() -> Vec<GenMember> {
|
||||
exec(async |mut h| {
|
||||
let recur = resolve(mactree!(macros::common::comma_list "push" tail ;)).await;
|
||||
let mut tail = h.exec::<HomoTpl<TAtom<MacTree>>>(recur).await?;
|
||||
tail.0.insert(0, h.exec(head).await?);
|
||||
tail.0.insert(0, h.exec(new_atom(head)).await?);
|
||||
Ok(tail)
|
||||
})
|
||||
.await
|
||||
}],
|
||||
)
|
||||
.rule(mactreev!(macros::common::comma_list ( "...$" final_tail 0 )), [async |[tail]| {
|
||||
HomoTpl(vec![tail.to_gen().await])
|
||||
HomoTpl(vec![new_atom(tail)])
|
||||
}])
|
||||
.rule(mactreev!(macros::common::comma_list()), [async |[]| UntypedTuple(Vec::new())])
|
||||
.finish(),
|
||||
@@ -71,14 +70,14 @@ pub async fn gen_macro_lib() -> Vec<GenMember> {
|
||||
exec(async |mut h| {
|
||||
let recur = resolve(mactree!(macros::common::semi_list "push" tail ;)).await;
|
||||
let mut tail = h.exec::<HomoTpl<TAtom<MacTree>>>(recur).await?;
|
||||
tail.0.insert(0, h.exec(head).await?);
|
||||
tail.0.insert(0, h.exec(new_atom(head)).await?);
|
||||
Ok(tail)
|
||||
})
|
||||
.await
|
||||
}],
|
||||
)
|
||||
.rule(mactreev!(macros::common::semi_list ( "...$" final_tail 0 )), [async |[tail]| {
|
||||
HomoTpl(vec![tail.to_gen().await])
|
||||
HomoTpl(vec![new_atom(tail)])
|
||||
}])
|
||||
.rule(mactreev!(macros::common::semi_list()), [async |[]| UntypedTuple(Vec::new())])
|
||||
.finish(),
|
||||
|
||||
@@ -13,7 +13,7 @@ use orchid_base::tree::{Paren, Token};
|
||||
use orchid_base::{clone, sym};
|
||||
use orchid_extension::atom::TAtom;
|
||||
use orchid_extension::conv::{ToExpr, TryFromExpr};
|
||||
use orchid_extension::gen_expr::{call, sym_ref};
|
||||
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
|
||||
use orchid_extension::parser::{PSnippet, ParsCtx, ParsedLine, Parser};
|
||||
|
||||
use crate::macros::let_line::{dealias_mac_v, parse_tokv};
|
||||
@@ -133,7 +133,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)), [macro_input.to_gen().await]))
|
||||
Ok(call(sym_ref(sym!(macros::resolve)), [new_atom(macro_input)]))
|
||||
}))
|
||||
}
|
||||
let mac_cell = Rc::new(OnceCell::new());
|
||||
@@ -165,7 +165,7 @@ impl Parser for MacroLine {
|
||||
rules,
|
||||
})))
|
||||
};
|
||||
mac_cell.get_or_init(mac_future).await.clone().to_gen().await
|
||||
mac_cell.get_or_init(mac_future).await.clone().map(new_atom).to_gen().await
|
||||
}))
|
||||
}
|
||||
Ok(lines)
|
||||
|
||||
@@ -6,6 +6,7 @@ use orchid_base::error::{OrcRes, mk_errv};
|
||||
use orchid_base::interner::is;
|
||||
use orchid_base::tokens::PARENS;
|
||||
use orchid_base::tree::Paren;
|
||||
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, x_tok};
|
||||
@@ -28,11 +29,12 @@ impl Lexer for MacTreeLexer {
|
||||
Ok((tail4, mactree)) => {
|
||||
let range = lctx.pos_tt(tail, tail4);
|
||||
let tok = match &args[..] {
|
||||
[] => x_tok(mactree).await,
|
||||
[] => x_tok(new_atom(mactree)).await,
|
||||
_ => {
|
||||
let instantiate_tpl_call =
|
||||
InstantiateTplCall { argc: args.len(), argv: vec![], tpl: mactree };
|
||||
let call = chain!([x_tok(instantiate_tpl_call).await.at(range.clone())], args);
|
||||
let call =
|
||||
chain!([x_tok(new_atom(instantiate_tpl_call)).await.at(range.clone())], args);
|
||||
GenTok::S(Paren::Round, call.collect())
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
|
||||
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, sym_ref};
|
||||
use orchid_extension::gen_expr::{GExpr, arg, bot, call, lambda, new_atom, sym_ref};
|
||||
use orchid_extension::tree::{GenMember, fun, prefix};
|
||||
|
||||
use crate::macros::resolve::resolve;
|
||||
@@ -82,25 +82,27 @@ pub async fn gen_match_macro_lib() -> Vec<GenMember> {
|
||||
.await
|
||||
},
|
||||
),
|
||||
fun(true, "matcher", async |names: HomoTpl<TAtom<SymAtom>>, matcher: Expr| MatcherAtom {
|
||||
keys: join_all(names.0.iter().map(async |atm| Sym::from_api(atm.0).await)).await,
|
||||
matcher,
|
||||
fun(true, "matcher", async |names: HomoTpl<TAtom<SymAtom>>, matcher: Expr| {
|
||||
new_atom(MatcherAtom {
|
||||
keys: join_all(names.0.iter().map(async |atm| Sym::from_api(atm.0).await)).await,
|
||||
matcher,
|
||||
})
|
||||
}),
|
||||
build_macro(None, ["match", "match_rule", "_row", "=>"])
|
||||
.rule(mactreev!("pattern::match" "...$" value 0 { "..$" rules 0 }), [
|
||||
async |[value, rules]| {
|
||||
exec(async move |mut h| {
|
||||
let rule_lines = h
|
||||
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(sym!(macros::resolve)), [
|
||||
mactree!(macros::common::semi_list "push" rules.clone();).to_gen().await,
|
||||
]))
|
||||
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(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)), [
|
||||
mactree!(pattern::_row "push" own(line_mac).await ;).to_gen().await,
|
||||
]))
|
||||
.exec(call(sym_ref(sym!(macros::resolve)), [new_atom(
|
||||
mactree!(pattern::_row "push" own(line_mac).await ;),
|
||||
)]))
|
||||
.await?;
|
||||
rule_atoms.push((matcher, body));
|
||||
}
|
||||
@@ -128,18 +130,18 @@ pub async fn gen_match_macro_lib() -> Vec<GenMember> {
|
||||
resolve(mactree!(pattern::match_rule "push" pattern; )).await
|
||||
}])
|
||||
.rule(mactreev!(pattern::match_rule ( macros::common::_ )), [async |[]| {
|
||||
Ok(MatcherAtom {
|
||||
Ok(new_atom(MatcherAtom {
|
||||
keys: Vec::new(),
|
||||
matcher: lambda(0, [OrcOpt(Some(Tpl(()))).to_gen().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)), [
|
||||
mactree!(pattern::match_rule "push" pattern.clone();).to_gen().await,
|
||||
]))
|
||||
.exec::<TAtom<MatcherAtom>>(call(sym_ref(sym!(macros::resolve)), [new_atom(
|
||||
mactree!(pattern::match_rule "push" pattern.clone();),
|
||||
)]))
|
||||
.await
|
||||
else {
|
||||
return Err(mk_errv(
|
||||
@@ -171,10 +173,10 @@ pub async fn gen_match_macro_lib() -> Vec<GenMember> {
|
||||
[name.pos()],
|
||||
));
|
||||
};
|
||||
Ok(MatcherAtom {
|
||||
Ok(new_atom(MatcherAtom {
|
||||
keys: vec![name.clone()],
|
||||
matcher: sym_ref(sym!(pattern::ref_body)).to_expr().await,
|
||||
})
|
||||
}))
|
||||
}])
|
||||
.finish(),
|
||||
])
|
||||
|
||||
@@ -5,6 +5,7 @@ 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_extension::gen_expr::new_atom;
|
||||
use orchid_extension::lexer::{LexContext, Lexer, err_not_applicable};
|
||||
use orchid_extension::tree::{GenTokTree, x_tok};
|
||||
|
||||
@@ -72,6 +73,6 @@ impl Lexer for PhLexer {
|
||||
}
|
||||
};
|
||||
let ph_atom = PhAtom(is(name).await.to_api(), phkind);
|
||||
Ok((tail, x_tok(ph_atom).await.at(ctx.pos_tt(line, tail))))
|
||||
Ok((tail, x_tok(new_atom(ph_atom)).await.at(ctx.pos_tt(line, tail))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use orchid_extension::atom::TAtom;
|
||||
use orchid_extension::atom_owned::own;
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::coroutine_exec::{ExecHandle, exec};
|
||||
use orchid_extension::gen_expr::{GExpr, arg, bot, call, lambda, sym_ref};
|
||||
use orchid_extension::gen_expr::{GExpr, arg, bot, call, lambda, new_atom, sym_ref};
|
||||
use orchid_extension::reflection::{ReflMemKind, refl};
|
||||
use subslice_offset::SubsliceOffset;
|
||||
use substack::Substack;
|
||||
@@ -283,9 +283,9 @@ async fn mk_body_call(mac: &Macro, rule: &Rule, state: &MatchState<'_>, pos: Pos
|
||||
let mut call_args = vec![];
|
||||
for name in rule.ph_names.iter() {
|
||||
call_args.push(match state.get(name).expect("Missing state entry for placeholder") {
|
||||
StateEntry::Scalar(scal) => (**scal).clone().to_gen().await,
|
||||
StateEntry::Scalar(scal) => new_atom((**scal).clone()),
|
||||
StateEntry::Vec(vec) =>
|
||||
MacTok::S(Paren::Round, MacTreeSeq::new(vec.iter().cloned())).at(Pos::None).to_gen().await,
|
||||
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())
|
||||
|
||||
@@ -4,7 +4,7 @@ use orchid_extension::atom::TAtom;
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::coroutine_exec::exec;
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::gen_expr::{call, sym_ref};
|
||||
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
|
||||
use orchid_extension::tree::{GenMember, fun, prefix};
|
||||
|
||||
use crate::macros::match_macros::MatcherAtom;
|
||||
@@ -34,21 +34,21 @@ pub async fn gen_option_macro_lib() -> Vec<GenMember> {
|
||||
let sub = h
|
||||
.exec::<TAtom<MatcherAtom>>(resolve(mactree!(pattern::match_rule "push" sub;)).await)
|
||||
.await?;
|
||||
Ok(MatcherAtom {
|
||||
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,
|
||||
})
|
||||
}))
|
||||
})
|
||||
},
|
||||
])
|
||||
.rule(mactreev!(pattern::match_rule(std::option::none)), [|[]: [_; _]| {
|
||||
exec(async |mut h| {
|
||||
Ok(MatcherAtom {
|
||||
Ok(new_atom(MatcherAtom {
|
||||
keys: vec![],
|
||||
matcher: h.register(sym_ref(sym!(std::option::is_none_body))).await,
|
||||
})
|
||||
}))
|
||||
})
|
||||
}])
|
||||
.finish(),
|
||||
|
||||
@@ -4,7 +4,7 @@ use orchid_extension::atom_owned::own;
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::coroutine_exec::exec;
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::gen_expr::{call, sym_ref};
|
||||
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
|
||||
use orchid_extension::tree::{GenMember, prefix};
|
||||
|
||||
use crate::macros::resolve::resolve;
|
||||
@@ -17,9 +17,9 @@ 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)), [
|
||||
mactree!((macros::common::comma_list "push" elements ;)).to_gen().await,
|
||||
]))
|
||||
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(sym!(macros::resolve)), [new_atom(
|
||||
mactree!((macros::common::comma_list "push" elements ;)),
|
||||
)]))
|
||||
.await?;
|
||||
let mut record = sym_ref(sym!(std::record::empty));
|
||||
for item_exprh in tup.0 {
|
||||
|
||||
@@ -6,7 +6,7 @@ use orchid_extension::atom_owned::own;
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::coroutine_exec::exec;
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::gen_expr::{GExpr, call, sym_ref};
|
||||
use orchid_extension::gen_expr::{GExpr, call, new_atom, sym_ref};
|
||||
use orchid_extension::tree::{GenMember, fun, prefix};
|
||||
|
||||
use crate::macros::match_macros::MatcherAtom;
|
||||
@@ -20,7 +20,7 @@ pub async fn gen_tuple_macro_lib() -> Vec<GenMember> {
|
||||
exec(async move |mut h| {
|
||||
let tup = h
|
||||
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(sym!(macros::resolve)), [
|
||||
mactree!((macros::common::comma_list "push" elements ;)).to_gen().await,
|
||||
new_atom(mactree!((macros::common::comma_list "push" elements ;))),
|
||||
]))
|
||||
.await?;
|
||||
let val = stream::iter(&tup.0[..])
|
||||
@@ -56,32 +56,32 @@ 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<MatcherAtom> {
|
||||
exec(async move |mut h| -> OrcRes<GExpr> {
|
||||
let tup = h
|
||||
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(sym!(macros::resolve)), [
|
||||
mactree!((macros::common::comma_list "push" elements ;)).to_gen().await,
|
||||
]))
|
||||
.exec::<HomoTpl<TAtom<MacTree>>>(call(sym_ref(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)), [
|
||||
mactree!(pattern::match_rule ("push" mac ;)).to_gen().await,
|
||||
]))
|
||||
.exec::<TAtom<MatcherAtom>>(call(sym_ref(sym!(macros::resolve)), [new_atom(
|
||||
mactree!(pattern::match_rule ("push" mac ;)),
|
||||
)]))
|
||||
.await?;
|
||||
subs.push(sub);
|
||||
}
|
||||
let tail_matcher = match tail_matcher {
|
||||
Some(mac) => Some(
|
||||
h.exec::<TAtom<MatcherAtom>>(call(sym_ref(sym!(macros::resolve)), [
|
||||
mactree!(pattern::match_rule "push" mac ;).to_gen().await,
|
||||
]))
|
||||
h.exec::<TAtom<MatcherAtom>>(call(sym_ref(sym!(macros::resolve)), [new_atom(
|
||||
mactree!(pattern::match_rule "push" mac ;),
|
||||
)]))
|
||||
.await?,
|
||||
),
|
||||
None => None,
|
||||
};
|
||||
Ok(MatcherAtom {
|
||||
Ok(new_atom(MatcherAtom {
|
||||
keys: stream::iter(&subs[..])
|
||||
.flat_map(|t| t.keys())
|
||||
.chain(stream::iter(&tail_matcher).flat_map(|mat| mat.keys()))
|
||||
@@ -93,7 +93,7 @@ fn parse_tpl(elements: MacTree, tail_matcher: Option<MacTree>) -> impl Future<Ou
|
||||
])
|
||||
.to_expr()
|
||||
.await,
|
||||
})
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ use orchid_base::name::{NameLike, Sym, VPath};
|
||||
use orchid_extension::atom::{Atomic, TAtom};
|
||||
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::gen_expr::{GExpr, sym_ref};
|
||||
use orchid_extension::gen_expr::{GExpr, new_atom, sym_ref};
|
||||
use orchid_extension::tree::{GenMember, MemKind, cnst, lazy};
|
||||
|
||||
use crate::macros::macro_value::{Macro, MacroData, Rule};
|
||||
@@ -48,7 +48,7 @@ impl OwnedAtom for MacroBodyArgCollector {
|
||||
if self.argc == self.args.len() {
|
||||
(self.cb)(self.args).await.to_gen().await
|
||||
} else {
|
||||
self.to_gen().await
|
||||
new_atom(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,15 +86,20 @@ impl MacroBuilder {
|
||||
let argv = [].into_iter().collect_array().expect("N is 0");
|
||||
MemKind::Const(body(argv).await.to_gen().await)
|
||||
}),
|
||||
1.. => cnst(true, name, MacroBodyArgCollector {
|
||||
argc: N,
|
||||
args: Vec::new(),
|
||||
cb: Rc::new(move |argv| {
|
||||
let arr = argv.into_iter().collect_array::<N>().expect("argc should enforce the length");
|
||||
let body = body.clone();
|
||||
Box::pin(async move { body(arr).await.to_gen().await })
|
||||
1.. => cnst(
|
||||
true,
|
||||
name,
|
||||
new_atom(MacroBodyArgCollector {
|
||||
argc: N,
|
||||
args: Vec::new(),
|
||||
cb: Rc::new(move |argv| {
|
||||
let arr =
|
||||
argv.into_iter().collect_array::<N>().expect("argc should enforce the length");
|
||||
let body = body.clone();
|
||||
Box::pin(async move { body(arr).await.to_gen().await })
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
),
|
||||
});
|
||||
self.patterns.push(pat);
|
||||
self
|
||||
@@ -105,35 +110,31 @@ impl MacroBuilder {
|
||||
let main_const = lazy(true, &format!("__macro__{name}"), async move |path| {
|
||||
let module = (Sym::new(path.split_last_seg().1.iter().cloned()).await)
|
||||
.expect("Default macro in global root");
|
||||
MemKind::Const(
|
||||
Macro(Rc::new(MacroData {
|
||||
canonical_name: module.suffix([is(name).await]).await,
|
||||
module,
|
||||
prio,
|
||||
rules: stream(async |mut h| {
|
||||
for (counter, pattern) in patterns.into_iter().enumerate() {
|
||||
let mut placeholders = Vec::new();
|
||||
pattern.map(&mut false, &mut |tt| {
|
||||
if let MacTok::Ph(ph) = &*tt.tok {
|
||||
placeholders.push(ph.name.clone())
|
||||
}
|
||||
None
|
||||
});
|
||||
h.emit(Rule {
|
||||
matcher: Matcher::new(pattern.clone()).await.unwrap(),
|
||||
pattern,
|
||||
ph_names: placeholders,
|
||||
body: is(&format!("({name})::{counter}")).await,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
.await,
|
||||
}))
|
||||
.to_gen()
|
||||
MemKind::Const(new_atom(Macro(Rc::new(MacroData {
|
||||
canonical_name: module.suffix([is(name).await]).await,
|
||||
module,
|
||||
prio,
|
||||
rules: stream(async |mut h| {
|
||||
for (counter, pattern) in patterns.into_iter().enumerate() {
|
||||
let mut placeholders = Vec::new();
|
||||
pattern.map(&mut false, &mut |tt| {
|
||||
if let MacTok::Ph(ph) = &*tt.tok {
|
||||
placeholders.push(ph.name.clone())
|
||||
}
|
||||
None
|
||||
});
|
||||
h.emit(Rule {
|
||||
matcher: Matcher::new(pattern.clone()).await.unwrap(),
|
||||
pattern,
|
||||
ph_names: placeholders,
|
||||
body: is(&format!("({name})::{counter}")).await,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
.await,
|
||||
)
|
||||
}))))
|
||||
});
|
||||
let kw_consts = own_kws[1..].iter().flat_map(|kw| {
|
||||
lazy(true, &format!("__macro__{kw}"), async move |path| {
|
||||
|
||||
25
orchid-std/src/std/binary/binary_atom.rs
Normal file
25
orchid-std/src/std/binary/binary_atom.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use std::borrow::Cow;
|
||||
use std::pin::Pin;
|
||||
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};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BlobAtom(pub(crate) Rc<Vec<u8>>);
|
||||
impl Atomic for BlobAtom {
|
||||
type Variant = OwnedVariant;
|
||||
type Data = ();
|
||||
}
|
||||
impl OwnedAtom for BlobAtom {
|
||||
type Refs = ();
|
||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||
async fn serialize(&self, write: Pin<&mut (impl AsyncWrite + ?Sized)>) -> Self::Refs {
|
||||
self.0.encode(write).await.unwrap()
|
||||
}
|
||||
async fn deserialize(mut dctx: impl DeserializeCtx, _: Self::Refs) -> Self {
|
||||
Self(dctx.read::<Rc<Vec<u8>>>().await)
|
||||
}
|
||||
}
|
||||
146
orchid-std/src/std/binary/binary_lib.rs
Normal file
146
orchid-std/src/std/binary/binary_lib.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
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_extension::func_atom::get_arg_posv;
|
||||
use orchid_extension::gen_expr::new_atom;
|
||||
use orchid_extension::tree::{GenMember, comments, fun, prefix};
|
||||
|
||||
use crate::std::binary::binary_atom::BlobAtom;
|
||||
use crate::std::boolean::Bool;
|
||||
use crate::{Int, OrcOpt, Tpl};
|
||||
|
||||
async fn bounds_error(
|
||||
expected: String,
|
||||
blob: &BlobAtom,
|
||||
args: impl IntoIterator<Item = usize>,
|
||||
) -> OrcErrv {
|
||||
mk_errv(
|
||||
is("Index out of bounds").await,
|
||||
format!("Selected {expected} from blob of len {}", blob.0.len()),
|
||||
get_arg_posv(args).await,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn gen_binary_lib() -> Vec<GenMember> {
|
||||
prefix("std", [comments(
|
||||
["A Blob is a sequence of bytes stored and processed efficiently."],
|
||||
prefix("binary", [
|
||||
comments(
|
||||
["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(),
|
||||
)))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Copies out a subsection of the binary into a new blob \
|
||||
specified by starting point and length",
|
||||
"|type: Blob -> Int -> Int -> Blob|",
|
||||
],
|
||||
fun(true, "slice", async |a: TAtom<BlobAtom>, Int(start): Int, Int(len): Int| {
|
||||
let blob = own(&a).await;
|
||||
if start + len > blob.0.len() as i64 {
|
||||
return Err(bounds_error(format!("{start}+{len}"), &blob, 0..3).await);
|
||||
}
|
||||
let sub = blob.0[start as usize..(start + len) as usize].to_vec();
|
||||
Ok(new_atom(BlobAtom(Rc::new(sub))))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Return the index where the second binary appears as a subsection of the first",
|
||||
"|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;
|
||||
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)));
|
||||
}
|
||||
}
|
||||
OrcOpt(None)
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Splits the binary into two halves at the given byte index",
|
||||
"|type: Blob -> Int -> std::tuple Blob Blob|",
|
||||
],
|
||||
fun(true, "split", async |a: TAtom<BlobAtom>, i: Int| {
|
||||
let v = own(&a).await;
|
||||
if v.0.len() < i.0 as usize {
|
||||
return Err(bounds_error(i.0.to_string(), &v, 1..2).await);
|
||||
}
|
||||
let (l, r) = v.0.split_at(i.0 as usize);
|
||||
Ok(Tpl((
|
||||
new_atom(BlobAtom(Rc::new(l.to_vec()))),
|
||||
new_atom(BlobAtom(Rc::new(r.to_vec()))),
|
||||
)))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Takes a binary, a starting point, a length no greater than 8, and a boolean flag \
|
||||
which is true if the number is little endian. Reads a usize from \
|
||||
the specified location in the binary.",
|
||||
"|type: Blob -> Int -> Int -> Bool -> Int|",
|
||||
],
|
||||
fun(
|
||||
true,
|
||||
"get_int",
|
||||
async |bin: TAtom<BlobAtom>, Int(start): Int, Int(len): Int, Bool(le): Bool| {
|
||||
let vec = own(&bin).await;
|
||||
if start + len > vec.0.len() as i64 {
|
||||
return Err(bounds_error(format!("{start}+{len}"), &vec, 1..3).await);
|
||||
}
|
||||
if 8 < len {
|
||||
return Err(mk_errv(
|
||||
is("Too many bytes for int conversion").await,
|
||||
format!("At most 8 bytes fit into an Int, requested {len}"),
|
||||
get_arg_posv(3..4).await,
|
||||
));
|
||||
}
|
||||
let slice = &vec.0[start as usize..(start + len) as usize];
|
||||
let mut data = [0u8; 8];
|
||||
Ok(Int(if le {
|
||||
data[..len as usize].copy_from_slice(slice);
|
||||
i64::from_le_bytes(data)
|
||||
} else {
|
||||
data[(8 - len as usize)..].copy_from_slice(slice);
|
||||
i64::from_be_bytes(data)
|
||||
}))
|
||||
},
|
||||
),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Takes a length no greater than int_bytes, a little endian flag and a number to encode. \
|
||||
Turns the least significant bytes of the given int into a binary.",
|
||||
"|type: Int -> Bool -> Int -> Blob|",
|
||||
],
|
||||
fun(true, "from_num", async |len: Int, le: Bool, val: Int| {
|
||||
if 8 < len.0 {
|
||||
return Err(mk_errv(
|
||||
is("Too many bytes for int conversion").await,
|
||||
format!("Ints are 8 bytes, attempted to write {} byte buffer", len.0),
|
||||
get_arg_posv(0..1).await,
|
||||
));
|
||||
}
|
||||
let data = if le.0 { val.0.to_le_bytes() } else { val.0.to_be_bytes() };
|
||||
let data = if le.0 { &data[..len.0 as usize] } else { &data[(8 - len.0 as usize)..] };
|
||||
Ok(new_atom(BlobAtom(Rc::new(data.to_vec()))))
|
||||
}),
|
||||
),
|
||||
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)),
|
||||
),
|
||||
]),
|
||||
)])
|
||||
}
|
||||
2
orchid-std/src/std/binary/mod.rs
Normal file
2
orchid-std/src/std/binary/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod binary_atom;
|
||||
pub mod binary_lib;
|
||||
47
orchid-std/src/std/boolean.rs
Normal file
47
orchid-std/src/std/boolean.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
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_extension::conv::{ToExpr, TryFromExpr};
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::gen_expr::{GExpr, sym_ref};
|
||||
use orchid_extension::tree::{GenMember, cnst, comments, fun, prefix};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Coding)]
|
||||
pub struct Bool(pub bool);
|
||||
impl Atomic for Bool {
|
||||
type Variant = ThinVariant;
|
||||
type Data = Self;
|
||||
}
|
||||
impl ThinAtom for Bool {
|
||||
async fn print(&self) -> FmtUnit { self.0.to_string().into() }
|
||||
}
|
||||
impl TryFromExpr for Bool {
|
||||
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
||||
match TAtom::<Bool>::downcast(expr.handle()).await {
|
||||
Err(e) => Err(e.mk_err().await),
|
||||
Ok(atom) => Ok(atom.value),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ToExpr for Bool {
|
||||
async fn to_gen(self) -> GExpr {
|
||||
sym_ref(if self.0 { sym!(std::true) } else { sym!(std::false) })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_bool_lib() -> Vec<GenMember> {
|
||||
prefix("std", [
|
||||
comments(
|
||||
[
|
||||
"Returns the second argument if the bool is true, the third argument otherwise",
|
||||
"|type: Bool -> T -> T -> T|",
|
||||
],
|
||||
fun(true, "ifthenelse", async |Bool(b): Bool, t: Expr, f: Expr| if b { t } else { f }),
|
||||
),
|
||||
cnst(true, "true", Bool(true)),
|
||||
cnst(true, "false", Bool(false)),
|
||||
])
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
pub mod binary;
|
||||
pub mod boolean;
|
||||
pub mod number;
|
||||
pub mod ops;
|
||||
pub mod option;
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
use orchid_api_derive::Coding;
|
||||
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::sym;
|
||||
use orchid_extension::atom::{
|
||||
AtomFactory, Atomic, AtomicFeatures, MethodSetBuilder, Supports, TAtom, ToAtom,
|
||||
};
|
||||
use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports, TAtom};
|
||||
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
|
||||
use orchid_extension::conv::TryFromExpr;
|
||||
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 ordered_float::NotNan;
|
||||
use rust_decimal::prelude::Zero;
|
||||
|
||||
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod};
|
||||
use crate::std::std_system::StdReq;
|
||||
use crate::std::string::to_string::ToStringMethod;
|
||||
use crate::{StdSystem, api};
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
#[derive(Debug, Clone, Copy, Coding, Hash, PartialEq, Eq, Hierarchy)]
|
||||
#[extends(StdReq)]
|
||||
pub struct CreateInt(pub Int);
|
||||
impl Request for CreateInt {
|
||||
type Response = api::ExprTicket;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Coding, Hash, PartialEq, Eq)]
|
||||
pub struct Int(pub i64);
|
||||
impl Atomic for Int {
|
||||
type Variant = ThinVariant;
|
||||
@@ -38,6 +46,11 @@ impl TryFromExpr for Int {
|
||||
TAtom::<Int>::try_from_expr(expr).await.map(|t| t.value)
|
||||
}
|
||||
}
|
||||
impl ToExpr for Int {
|
||||
async fn to_gen(self) -> orchid_extension::gen_expr::GExpr {
|
||||
Expr::deserialize(sys_req::<StdSystem, _>(CreateInt(self)).await).await.to_gen().await
|
||||
}
|
||||
}
|
||||
impl Supports<GetTagIdMethod> for Int {
|
||||
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response {
|
||||
sym!(std::number::Int).to_api()
|
||||
@@ -68,7 +81,14 @@ impl Supports<ToStringMethod> for Int {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
#[derive(Clone, Copy, Debug, Coding, Hash, PartialEq, Eq, Hierarchy)]
|
||||
#[extends(StdReq)]
|
||||
pub struct CreateFloat(pub Float);
|
||||
impl Request for CreateFloat {
|
||||
type Response = api::ExprTicket;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Coding, Hash, PartialEq, Eq)]
|
||||
pub struct Float(pub NotNan<f64>);
|
||||
impl Atomic for Float {
|
||||
type Variant = ThinVariant;
|
||||
@@ -88,6 +108,11 @@ impl TryFromExpr for Float {
|
||||
Ok(Self(Num::try_from_expr(expr).await?.0.to_f64()))
|
||||
}
|
||||
}
|
||||
impl ToExpr for Float {
|
||||
async fn to_gen(self) -> orchid_extension::gen_expr::GExpr {
|
||||
Expr::deserialize(sys_req::<StdSystem, _>(CreateFloat(self)).await).await.to_gen().await
|
||||
}
|
||||
}
|
||||
impl Supports<GetTagIdMethod> for Float {
|
||||
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response {
|
||||
sym!(std::number::Float).to_api()
|
||||
@@ -131,12 +156,14 @@ impl TryFromExpr for Num {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ToAtom for Num {
|
||||
fn to_atom_factory(self) -> AtomFactory {
|
||||
impl ToExpr for Num {
|
||||
async fn to_gen(self) -> orchid_extension::gen_expr::GExpr {
|
||||
match self.0 {
|
||||
Numeric::Float(f) => Float(f).factory(),
|
||||
Numeric::Int(i) => Int(i).factory(),
|
||||
Numeric::Float(f) => Float(f).to_expr().await,
|
||||
Numeric::Int(i) => Int(i).to_expr().await,
|
||||
}
|
||||
.to_gen()
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::ops::RangeInclusive;
|
||||
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::number::{num_to_errv, parse_num};
|
||||
use orchid_extension::atom::ToAtom;
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::lexer::{LexContext, Lexer};
|
||||
use orchid_extension::tree::{GenTokTree, x_tok};
|
||||
|
||||
@@ -15,10 +15,10 @@ impl Lexer for NumLexer {
|
||||
async fn lex<'a>(all: &'a str, lxcx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree)> {
|
||||
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()));
|
||||
let fac = match parse_num(chars) {
|
||||
Ok(numeric) => Num(numeric).to_atom_factory(),
|
||||
Err(e) => return Err(num_to_errv(e, lxcx.pos(all), lxcx.src()).await),
|
||||
};
|
||||
Ok((tail, x_tok(fac).await.at(lxcx.pos_lt(chars.len(), tail))))
|
||||
match parse_num(chars) {
|
||||
Ok(numeric) =>
|
||||
Ok((tail, x_tok(Num(numeric).to_gen().await).await.at(lxcx.pos_lt(chars.len(), tail)))),
|
||||
Err(e) => Err(num_to_errv(e, lxcx.pos(all), lxcx.src()).await),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::interner::is;
|
||||
use orchid_base::parse::{name_char, name_start};
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::gen_expr::new_atom;
|
||||
use orchid_extension::lexer::{LexContext, LexedData, Lexer, err_not_applicable};
|
||||
use orchid_extension::tree::GenTok;
|
||||
|
||||
@@ -22,7 +22,7 @@ impl Lexer for SubscriptLexer {
|
||||
let new_tail = &tail[name_len + 1..];
|
||||
Ok((new_tail, [
|
||||
GenTok::Name(is(".").await).at(lctx.pos_lt(1, &tail[1..])),
|
||||
GenTok::NewExpr(IntStrAtom(is(&tail[1..name_len + 1]).await).to_gen().await)
|
||||
GenTok::NewExpr(new_atom(IntStrAtom(is(&tail[1..name_len + 1]).await)))
|
||||
.at(lctx.pos_tt(&tail[1..], new_tail)),
|
||||
]))
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use orchid_extension::atom::{Atomic, ForeignAtom, TAtom};
|
||||
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||
use orchid_extension::conv::{ToExpr, TryFromExpr};
|
||||
use orchid_extension::expr::{Expr, ExprHandle};
|
||||
use orchid_extension::gen_expr::{call, sym_ref};
|
||||
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
|
||||
use orchid_extension::tree::{GenMember, cnst, fun, prefix};
|
||||
|
||||
use crate::{OrcString, api};
|
||||
@@ -59,8 +59,8 @@ impl<T: ToExpr + 'static> ToExpr for OrcOpt<T> {
|
||||
|
||||
pub fn gen_option_lib() -> Vec<GenMember> {
|
||||
prefix("std::option", [
|
||||
cnst(true, "none", OptAtom(None)),
|
||||
fun(true, "some", async |ex: Expr| OptAtom(Some(ex))),
|
||||
cnst(true, "none", new_atom(OptAtom(None))),
|
||||
fun(true, "some", async |ex: Expr| new_atom(OptAtom(Some(ex)))),
|
||||
fun(true, "expect", async |opt: ForeignAtom, msg: OrcString| {
|
||||
match OrcOpt::try_from_expr(opt.clone().ex()).await? {
|
||||
OrcOpt(Some(ex)) => Ok::<Expr, _>(ex),
|
||||
|
||||
@@ -7,7 +7,7 @@ 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, sym_ref};
|
||||
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
|
||||
use orchid_extension::parser::{PSnippet, ParsCtx, ParsedLine, Parser};
|
||||
|
||||
use crate::std::protocol::parse_impls::parse_impls;
|
||||
@@ -44,7 +44,7 @@ impl Parser for AsProtoParser {
|
||||
for (k, v) in impls {
|
||||
new_impls.insert(k.clone(), h.register(sym_ref(id.suffix([v]).await)).await);
|
||||
}
|
||||
Tag { id, impls: Rc::new(new_impls) }
|
||||
new_atom(Tag { id, impls: Rc::new(new_impls) })
|
||||
})
|
||||
.await
|
||||
}));
|
||||
|
||||
@@ -7,7 +7,7 @@ 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, sym_ref};
|
||||
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
|
||||
use orchid_extension::parser::{PSnippet, ParsCtx, ParsedLine, Parser};
|
||||
|
||||
use crate::std::protocol::parse_impls::parse_impls;
|
||||
@@ -44,7 +44,7 @@ impl Parser for AsTypeParser {
|
||||
for (k, v) in impls {
|
||||
new_impls.insert(k.clone(), h.register(sym_ref(id.suffix([v]).await)).await);
|
||||
}
|
||||
Tag { id, impls: Rc::new(new_impls) }
|
||||
new_atom(Tag { id, impls: Rc::new(new_impls) })
|
||||
})
|
||||
.await
|
||||
}));
|
||||
|
||||
@@ -18,8 +18,8 @@ use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
|
||||
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, sym_ref};
|
||||
use orchid_extension::system::dep_req;
|
||||
use orchid_extension::gen_expr::{GExpr, call, new_atom, sym_ref};
|
||||
use orchid_extension::system::sys_req;
|
||||
use orchid_extension::tree::{GenMember, MemKind, cnst, fun, lazy, prefix};
|
||||
|
||||
use crate::std::std_system::StdReq;
|
||||
@@ -135,7 +135,9 @@ pub fn gen_protocol_lib() -> Vec<GenMember> {
|
||||
fun(false, "resolve", async |tag: ForeignAtom, value: ForeignAtom| {
|
||||
Ok(call(get_impl(value.clone(), tag).await?.to_gen().await, [value.to_gen().await]))
|
||||
}),
|
||||
fun(false, "wrap", async |tag: TAtom<Tag>, value: Expr| Tagged { tag: own(&tag).await, value }),
|
||||
fun(false, "wrap", async |tag: TAtom<Tag>, value: Expr| {
|
||||
new_atom(Tagged { tag: own(&tag).await, value })
|
||||
}),
|
||||
fun(false, "unwrap", async |tag: TAtom<Tag>, value: TAtom<Tagged>| {
|
||||
let own_tag = own(&tag).await;
|
||||
let own_val = own(&value).await;
|
||||
@@ -178,7 +180,7 @@ impl<'a> TagBuilder<'a> {
|
||||
self
|
||||
}
|
||||
pub async fn finish(self) -> TAtom<Tag> {
|
||||
let tk = dep_req::<StdSystem, _>(CreateTag {
|
||||
let tk = sys_req::<StdSystem, _>(CreateTag {
|
||||
name: Sym::parse(&self.name).await.unwrap().to_api(),
|
||||
impls: join_all(self.impls.into_iter().map(|(s, fut)| async move {
|
||||
(
|
||||
|
||||
@@ -7,7 +7,7 @@ use orchid_base::interner::is;
|
||||
use orchid_extension::atom::TAtom;
|
||||
use orchid_extension::atom_owned::own;
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::gen_expr::arg;
|
||||
use orchid_extension::gen_expr::{arg, new_atom};
|
||||
use orchid_extension::tree::{GenMember, cnst, fun, prefix};
|
||||
|
||||
use crate::std::record::record_atom::RecordAtom;
|
||||
@@ -15,11 +15,11 @@ use crate::std::string::str_atom::IntStrAtom;
|
||||
|
||||
pub fn gen_record_lib() -> Vec<GenMember> {
|
||||
prefix("std::record", [
|
||||
cnst(true, "empty", RecordAtom(Rc::new(HashMap::new()))),
|
||||
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();
|
||||
map.insert(key.0.clone(), val);
|
||||
RecordAtom(Rc::new(map))
|
||||
new_atom(RecordAtom(Rc::new(map)))
|
||||
}),
|
||||
fun(true, "get", async |map: TAtom<RecordAtom>, key: IntStrAtom| {
|
||||
let record = own(&map).await;
|
||||
@@ -35,7 +35,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();
|
||||
map.remove(&key.0);
|
||||
RecordAtom(Rc::new(map))
|
||||
new_atom(RecordAtom(Rc::new(map)))
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ use orchid_base::name::{NameLike, Sym};
|
||||
use orchid_extension::atom::{Atomic, Supports, TAtom};
|
||||
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
|
||||
use orchid_extension::expr::{Expr, ExprHandle};
|
||||
use orchid_extension::system::dep_req;
|
||||
use orchid_extension::gen_expr::new_atom;
|
||||
use orchid_extension::system::sys_req;
|
||||
use orchid_extension::tree::{GenMember, fun, prefix};
|
||||
|
||||
use crate::std::std_system::StdReq;
|
||||
@@ -43,7 +44,7 @@ impl Request for CreateSymAtom {
|
||||
|
||||
pub async fn sym_expr(sym: Sym) -> Expr {
|
||||
Expr::from_handle(ExprHandle::deserialize(
|
||||
dep_req::<StdSystem, _>(CreateSymAtom(sym.to_api())).await,
|
||||
sys_req::<StdSystem, _>(CreateSymAtom(sym.to_api())).await,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -51,7 +52,7 @@ pub async fn gen_sym_lib() -> Vec<GenMember> {
|
||||
prefix("std::refl::sym", [
|
||||
fun(true, "from_str", async move |str: TAtom<IntStrAtom>| {
|
||||
match Sym::parse(&es(*str).await).await {
|
||||
Ok(sym) => Ok(SymAtom(sym)),
|
||||
Ok(sym) => Ok(new_atom(SymAtom(sym))),
|
||||
Err(_) => Err(mk_errv(
|
||||
is("Cannot parse sym from empty string").await,
|
||||
"Empty string passed to std::refl::sym::from_str",
|
||||
@@ -60,7 +61,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(IntStrAtom).collect())
|
||||
HomoTpl(own(&sym).await.0.segs().map(|seg| new_atom(IntStrAtom(seg))).collect())
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use orchid_base::sym;
|
||||
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
|
||||
use orchid_extension::conv::ToExpr;
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::gen_expr::new_atom;
|
||||
use orchid_extension::lexer::LexerObj;
|
||||
use orchid_extension::parser::ParserObj;
|
||||
use orchid_extension::system::{System, SystemCard};
|
||||
@@ -18,6 +19,10 @@ use orchid_extension::tree::{GenMember, merge_trivial};
|
||||
use super::number::num_lib::gen_num_lib;
|
||||
use super::string::str_atom::{IntStrAtom, StrAtom};
|
||||
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::number::num_atom::{CreateFloat, CreateInt};
|
||||
use crate::std::number::num_lexer::NumLexer;
|
||||
use crate::std::ops::gen_ops_lib;
|
||||
use crate::std::ops::subscript_lexer::SubscriptLexer;
|
||||
@@ -36,6 +41,8 @@ use crate::{Float, Int};
|
||||
#[extendable]
|
||||
#[allow(clippy::enum_variant_names, reason = "For the time being there are only ctor calls")]
|
||||
pub enum StdReq {
|
||||
CreateInt(CreateInt),
|
||||
CreateFloat(CreateFloat),
|
||||
CreateTag(CreateTag),
|
||||
CreateTuple(CreateTuple),
|
||||
CreateRecord(CreateRecord),
|
||||
@@ -56,6 +63,7 @@ impl SystemCard for StdSystem {
|
||||
type Req = StdReq;
|
||||
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomDynfo>>> {
|
||||
[
|
||||
Some(BlobAtom::dynfo()),
|
||||
Some(Int::dynfo()),
|
||||
Some(Float::dynfo()),
|
||||
Some(StrAtom::dynfo()),
|
||||
@@ -72,9 +80,13 @@ impl SystemCard for StdSystem {
|
||||
impl System for StdSystem {
|
||||
async fn request<'a>(xreq: Box<dyn ReqHandle<'a> + 'a>, req: Self::Req) -> Receipt<'a> {
|
||||
match req {
|
||||
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::CreateTuple(ref req @ CreateTuple(ref items)) => {
|
||||
let tpl = Tuple(Rc::new(join_all(items.iter().copied().map(Expr::deserialize)).await));
|
||||
let tk = tpl.to_expr().await.serialize().await;
|
||||
let tk = new_atom(tpl).to_expr().await.serialize().await;
|
||||
xreq.reply(req, &tk).await.unwrap()
|
||||
},
|
||||
StdReq::CreateRecord(ref req @ CreateRecord(ref items)) => {
|
||||
@@ -82,12 +94,12 @@ impl System for StdSystem {
|
||||
join_all(items.iter().map(async |(k, v)| (es(*k).await, Expr::deserialize(*v).await)))
|
||||
.await;
|
||||
let rec = RecordAtom(Rc::new(values.into_iter().collect()));
|
||||
let tk = rec.to_expr().await.serialize().await;
|
||||
let tk = new_atom(rec).to_expr().await.serialize().await;
|
||||
xreq.reply(req, &tk).await.unwrap()
|
||||
},
|
||||
StdReq::CreateSymAtom(ref req @ CreateSymAtom(sym_tok)) => {
|
||||
let sym_atom = SymAtom(Sym::from_api(sym_tok).await);
|
||||
xreq.reply(req, &sym_atom.to_expr().await.serialize().await).await.unwrap()
|
||||
xreq.reply(req, &new_atom(sym_atom).to_expr().await.serialize().await).await.unwrap()
|
||||
},
|
||||
StdReq::CreateTag(ref req @ CreateTag { name, ref impls }) => {
|
||||
let tag_atom = Tag {
|
||||
@@ -102,7 +114,7 @@ impl System for StdSystem {
|
||||
.collect(),
|
||||
),
|
||||
};
|
||||
xreq.reply(req, &tag_atom.to_expr().await.serialize().await).await.unwrap()
|
||||
xreq.reply(req, &new_atom(tag_atom).to_expr().await.serialize().await).await.unwrap()
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -110,6 +122,7 @@ impl System for StdSystem {
|
||||
fn parsers() -> Vec<ParserObj> { vec![&AsTypeParser, &TypeParser, &AsProtoParser, &ProtoParser] }
|
||||
async fn env() -> Vec<GenMember> {
|
||||
merge_trivial([
|
||||
gen_bool_lib(),
|
||||
gen_num_lib(),
|
||||
gen_str_lib(),
|
||||
gen_option_lib(),
|
||||
@@ -118,9 +131,10 @@ impl System for StdSystem {
|
||||
gen_protocol_lib(),
|
||||
gen_sym_lib().await,
|
||||
gen_ops_lib(),
|
||||
gen_binary_lib(),
|
||||
])
|
||||
}
|
||||
async fn prelude() -> Vec<Sym> {
|
||||
vec![sym!(std), sym!(std::tuple), sym!(std::option), sym!(std::record)]
|
||||
vec![sym!(std), sym!(std::tuple), sym!(std::option), sym!(std::record), sym!(std::string)]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ 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::sym_ref;
|
||||
use orchid_extension::gen_expr::{new_atom, sym_ref};
|
||||
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};
|
||||
@@ -99,6 +99,7 @@ impl Lexer for StringLexer {
|
||||
const CHAR_FILTER: &'static [std::ops::RangeInclusive<char>] = &['"'..='"', '`'..='`'];
|
||||
async fn lex<'a>(all: &'a str, lctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree)> {
|
||||
let Some(mut tail) = all.strip_prefix('"') else {
|
||||
eprintln!("Unrecognized start char {:?}", all.chars().next().unwrap());
|
||||
return Err(err_not_applicable().await);
|
||||
};
|
||||
let mut ret = None;
|
||||
@@ -115,8 +116,8 @@ impl Lexer for StringLexer {
|
||||
err.extend(e.clone().into_proj(ctx.src(), ctx.pos(tail) - str.len() as u32).await);
|
||||
}
|
||||
let str_val = str_val_res.unwrap_or_default();
|
||||
x_tok(IntStrAtom::from(is(&str_val).await)).await.at(ctx.pos_lt(str.len() as u32, tail))
|
||||
as GenTokTree
|
||||
let atom = new_atom(IntStrAtom::from(is(&str_val).await));
|
||||
x_tok(atom).await.at(ctx.pos_lt(str.len() as u32, tail)) as GenTokTree
|
||||
}
|
||||
let add_frag = |prev: Option<GenTokTree>, new: GenTokTree| async {
|
||||
let Some(prev) = prev else { return new };
|
||||
|
||||
@@ -1,50 +1,174 @@
|
||||
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_extension::coroutine_exec::exec;
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::gen_expr::{call, sym_ref};
|
||||
use orchid_extension::func_atom::get_arg;
|
||||
use orchid_extension::gen_expr::{call, new_atom, sym_ref};
|
||||
use orchid_extension::tree::{GenMember, comments, fun, prefix};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
use super::str_atom::StrAtom;
|
||||
use crate::OrcString;
|
||||
use crate::std::protocol::types::{get_impl, proto};
|
||||
use crate::std::string::to_string::ToStringMethod;
|
||||
use crate::{Int, OrcOpt, OrcString, Tpl};
|
||||
|
||||
pub fn gen_str_lib() -> Vec<GenMember> {
|
||||
prefix("std::string", [
|
||||
comments(
|
||||
["Concatenate two strings"],
|
||||
fun(true, "concat", async |left: OrcString, right: OrcString| {
|
||||
StrAtom::new(Rc::new(left.get_string().await.to_string() + &right.get_string().await))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
["Converts a value to string. This function is used in interpolation. \
|
||||
It supports the std::string::to_string protocol in Orchid, \
|
||||
the std::string::to_string request in Rust, \
|
||||
and expression debug printing as a fallback (print_atom for Atomic implementors in Rust).\n\n\
|
||||
This function is infallible."],
|
||||
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 {
|
||||
return StrAtom::new(Rc::new(str)).to_gen().await;
|
||||
}
|
||||
let proto_ref = sym_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;
|
||||
}
|
||||
prefix("std", [comments(
|
||||
["There are two string types, IntStr and Str. Literals are always IntStr, which are quick to \
|
||||
equality-compare but may leak, so you can't generally create them at runtime.\n\n\
|
||||
All functions here operate on Unicode graphemes. This essentially means that letters with \
|
||||
added diacritics and Mandarin multi-codepoint characters are treated as a single character."],
|
||||
prefix("string", [
|
||||
comments(
|
||||
["Concatenate two strings", "|type: Str -> Str -> Str|"],
|
||||
fun(true, "concat", async |left: OrcString, right: OrcString| {
|
||||
new_atom(StrAtom::new(Rc::new(
|
||||
left.get_string().await.to_string() + &right.get_string().await,
|
||||
)))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Find the size of a string in bytes. Strings are stored in UTF-8. \
|
||||
This should be used to determine the computational resource utilization of strings. \
|
||||
It should not be used to determine whether to truncate text.",
|
||||
"|type: Str -> Int|",
|
||||
],
|
||||
fun(true, "size", async |s: OrcString| Int(s.get_string().await.len().try_into().unwrap())),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Find the number of characters in a string. This can be used for example to \
|
||||
truncate text. It should not be used to limit the size of messages for security purposes.",
|
||||
"|type: Str -> Int|",
|
||||
],
|
||||
fun(true, "len", async |s: OrcString| {
|
||||
Int(s.get_string().await.graphemes(true).count().try_into().unwrap())
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Takes a string, a start and a length in graphemes. \
|
||||
Slices out the specified subsection of the string.",
|
||||
"|type: Str -> Int -> Int -> Str|",
|
||||
],
|
||||
fun(true, "slice", async |s: OrcString, Int(start): Int, Int(len): Int| {
|
||||
let str = s.get_string().await;
|
||||
if len <= 0 {
|
||||
return Ok(new_atom(StrAtom::new(Rc::default())));
|
||||
}
|
||||
return StrAtom::new(Rc::new(fmt(&input).await)).to_gen().await;
|
||||
})
|
||||
.await
|
||||
}),
|
||||
),
|
||||
proto(true, "to_string").finish(),
|
||||
])
|
||||
let mut substr_iter = str.graphemes(true).skip(start.try_into().unwrap());
|
||||
let new_str: String =
|
||||
substr_iter.by_ref().take(usize::try_from(len).unwrap() - 1).collect();
|
||||
let Some(s) = substr_iter.next() else {
|
||||
let str_len = str.graphemes(true).count();
|
||||
return Err(mk_errv(
|
||||
is("Index out of bounds").await,
|
||||
format!("Tried to select grapheme {start}+{len} from string that only has {str_len}"),
|
||||
[get_arg(0).pos().await, get_arg(1).pos().await, get_arg(2).pos().await],
|
||||
));
|
||||
};
|
||||
Ok(new_atom(StrAtom::new(Rc::new(new_str + s))))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"If the first string contains the second then returns the index.",
|
||||
"|type: Str -> Str -> std::option Int|",
|
||||
],
|
||||
fun(true, "find", async |haystack: OrcString, needle: OrcString| {
|
||||
let haystack_str = haystack.get_string().await;
|
||||
let needle_str = needle.get_string().await;
|
||||
let mut haystack_graphs = haystack_str.graphemes(true);
|
||||
let mut index = 0;
|
||||
loop {
|
||||
let mut needle_graphs = needle_str.graphemes(true);
|
||||
// check that all chars are equal
|
||||
if haystack_graphs.clone().zip(needle_graphs.by_ref()).all(|(l, r)| l == r) {
|
||||
// if we exhausted the haystack but not the needle, we can't succeed
|
||||
if needle_graphs.next().is_some() {
|
||||
break;
|
||||
}
|
||||
return OrcOpt(Some(Int(index)));
|
||||
}
|
||||
if haystack_graphs.next().is_none() {
|
||||
break;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
OrcOpt(None)
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Splits the string into two substrings at the nth grapheme.",
|
||||
"|type: Str -> Int -> std::tuple Str Str|",
|
||||
],
|
||||
fun(true, "split", async |s: OrcString, i: Int| {
|
||||
let str = s.get_string().await;
|
||||
let Some((i, _)) = str.grapheme_indices(true).nth(i.0.try_into().unwrap()) else {
|
||||
let len = str.graphemes(true).count();
|
||||
return Err(mk_errv(
|
||||
is("Index out of bounds").await,
|
||||
format!("Tried to split string at {}, it only has {} graphemes", i.0, len),
|
||||
[get_arg(0).pos().await, get_arg(1).pos().await],
|
||||
));
|
||||
};
|
||||
let (left, right) = str.split_at(i);
|
||||
Ok(Tpl((
|
||||
new_atom(StrAtom::new(Rc::new(left.to_string()))),
|
||||
new_atom(StrAtom::new(Rc::new(right.to_string()))),
|
||||
)))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
["Returns the nth grapheme.", "|type: Str -> Int -> Str|"],
|
||||
fun(true, "char_at", async |s: OrcString, i: Int| {
|
||||
let str = s.get_string().await;
|
||||
let Some(s) = str.graphemes(true).nth(i.0.try_into().unwrap()) else {
|
||||
let len = str.graphemes(true).count();
|
||||
return Err(mk_errv(
|
||||
is("Index out of bounds").await,
|
||||
format!("Tried to read grapheme {} from string, it only has {}", i.0, len),
|
||||
[get_arg(0).pos().await, get_arg(1).pos().await],
|
||||
));
|
||||
};
|
||||
Ok(new_atom(StrAtom::new(Rc::new(s.to_string()))))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Converts a value to string. This function is used in interpolation. \
|
||||
It supports the std::string::to_string protocol in Orchid, \
|
||||
the std::string::to_string request in Rust, \
|
||||
and expression debug printing as a fallback (print_atom for Atomic implementors in Rust).\n\n\
|
||||
This function is infallible.",
|
||||
"|type: any -> Str|",
|
||||
],
|
||||
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 {
|
||||
return new_atom(StrAtom::new(Rc::new(str)));
|
||||
}
|
||||
let proto_ref = sym_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 new_atom(StrAtom::new(Rc::new(fmt(&input).await)));
|
||||
})
|
||||
.await
|
||||
}),
|
||||
),
|
||||
proto(true, "to_string").finish(),
|
||||
]),
|
||||
)])
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports, TAtom};
|
||||
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant, own};
|
||||
use orchid_extension::conv::{ToExpr, TryFromExpr};
|
||||
use orchid_extension::expr::{Expr, ExprHandle};
|
||||
use orchid_extension::gen_expr::{GExpr, sym_ref};
|
||||
use orchid_extension::system::dep_req;
|
||||
use orchid_extension::gen_expr::{GExpr, new_atom, sym_ref};
|
||||
use orchid_extension::system::sys_req;
|
||||
use orchid_extension::tree::{GenMember, cnst, fun, prefix};
|
||||
|
||||
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod};
|
||||
@@ -93,22 +93,22 @@ impl OwnedAtom for TupleBuilder {
|
||||
async fn call(mut self, arg: Expr) -> GExpr {
|
||||
self.items.push(arg);
|
||||
if self.arity.get() == self.items.len().try_into().expect("counting up from 0") {
|
||||
Tuple(Rc::new(self.items)).to_gen().await
|
||||
new_atom(Tuple(Rc::new(self.items)))
|
||||
} else {
|
||||
self.to_gen().await
|
||||
new_atom(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_tuple_lib() -> Vec<GenMember> {
|
||||
prefix("std::tuple", [
|
||||
cnst(true, "empty", Tuple(Rc::new(Vec::new()))),
|
||||
fun(true, "one", async |item: Expr| Tuple(Rc::new(vec![item]))),
|
||||
cnst(true, "empty", new_atom(Tuple(Rc::new(Vec::new())))),
|
||||
fun(true, "one", async |item: Expr| new_atom(Tuple(Rc::new(vec![item])))),
|
||||
fun(true, "new", async |arity: TAtom<Int>| {
|
||||
if let Ok(arity) = u32::try_from(arity.value.0).and_then(|v| v.try_into()) {
|
||||
TupleBuilder { arity, items: Vec::new() }.to_gen().await
|
||||
new_atom(TupleBuilder { arity, items: Vec::new() })
|
||||
} else {
|
||||
Tuple(Rc::new(Vec::new())).to_gen().await
|
||||
new_atom(Tuple(Rc::new(Vec::new())))
|
||||
}
|
||||
}),
|
||||
fun(true, "get", async |tup: TAtom<Tuple>, idx: TAtom<Int>| {
|
||||
@@ -128,7 +128,7 @@ pub fn gen_tuple_lib() -> Vec<GenMember> {
|
||||
let mut new_vec = own(&tup).await.0.to_vec();
|
||||
if let Some(slot) = new_vec.get_mut(idx) {
|
||||
*slot = val;
|
||||
return Ok(Tuple(Rc::new(new_vec)));
|
||||
return Ok(new_atom(Tuple(Rc::new(new_vec))));
|
||||
}
|
||||
}
|
||||
return Err(mk_errv(
|
||||
@@ -141,7 +141,9 @@ pub fn gen_tuple_lib() -> Vec<GenMember> {
|
||||
Int(tup.len().try_into().expect("Tuple was created with an Int length"))
|
||||
}),
|
||||
fun(true, "cat", async |left: TAtom<Tuple>, right: TAtom<Tuple>| {
|
||||
Tuple(Rc::new(own(&left).await.0.iter().chain(own(&right).await.0.iter()).cloned().collect()))
|
||||
new_atom(Tuple(Rc::new(
|
||||
own(&left).await.0.iter().chain(own(&right).await.0.iter()).cloned().collect(),
|
||||
)))
|
||||
}),
|
||||
])
|
||||
}
|
||||
@@ -159,7 +161,7 @@ impl TryFromExpr for UntypedTuple {
|
||||
impl ToExpr for UntypedTuple {
|
||||
async fn to_gen(self) -> GExpr {
|
||||
let exprs = join_all(self.0.into_iter().map(async |expr| expr.serialize().await)).await;
|
||||
Expr::deserialize(dep_req::<StdSystem, _>(CreateTuple(exprs)).await).await.to_gen().await
|
||||
Expr::deserialize(sys_req::<StdSystem, _>(CreateTuple(exprs)).await).await.to_gen().await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ pub struct Args {
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum Commands {
|
||||
Lex {
|
||||
#[arg(short, long)]
|
||||
#[arg()]
|
||||
file: Utf8PathBuf,
|
||||
},
|
||||
Parse {
|
||||
|
||||
Reference in New Issue
Block a user