New macro system and stdlib additions
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
pub mod str_atom;
|
||||
pub mod str_lexer;
|
||||
pub mod str_lib;
|
||||
pub mod to_string;
|
||||
|
||||
@@ -11,9 +11,11 @@ use orchid_base::format::{FmtCtx, FmtUnit};
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TAtom};
|
||||
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||
use orchid_extension::context::i;
|
||||
use orchid_extension::conv::TryFromExpr;
|
||||
use orchid_extension::expr::Expr;
|
||||
use orchid_extension::system::SysCtx;
|
||||
|
||||
use crate::std::string::to_string::ToStringMethod;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Coding)]
|
||||
pub struct StringGetVal;
|
||||
@@ -24,8 +26,11 @@ impl AtomMethod for StringGetVal {
|
||||
const NAME: &str = "std::string_get_val";
|
||||
}
|
||||
impl Supports<StringGetVal> for StrAtom {
|
||||
async fn handle(&self, _: SysCtx, _: StringGetVal) -> <StringGetVal as Request>::Response {
|
||||
self.0.clone()
|
||||
async fn handle(&self, _: StringGetVal) -> <StringGetVal as Request>::Response { self.0.clone() }
|
||||
}
|
||||
impl Supports<ToStringMethod> for StrAtom {
|
||||
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response {
|
||||
self.0.as_str().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +51,7 @@ impl Deref for StrAtom {
|
||||
impl OwnedAtom for StrAtom {
|
||||
type Refs = ();
|
||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||
async fn serialize(&self, _: SysCtx, sink: Pin<&mut (impl AsyncWrite + ?Sized)>) -> Self::Refs {
|
||||
async fn serialize(&self, sink: Pin<&mut (impl AsyncWrite + ?Sized)>) -> Self::Refs {
|
||||
self.deref().encode(sink).await
|
||||
}
|
||||
async fn print_atom<'a>(&'a self, _: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||
@@ -58,7 +63,7 @@ impl OwnedAtom for StrAtom {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IntStrAtom(Tok<String>);
|
||||
pub struct IntStrAtom(pub(crate) Tok<String>);
|
||||
impl Atomic for IntStrAtom {
|
||||
type Variant = OwnedVariant;
|
||||
type Data = orchid_api::TStr;
|
||||
@@ -72,19 +77,28 @@ impl OwnedAtom for IntStrAtom {
|
||||
async fn print_atom<'a>(&'a self, _: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||
format!("{:?}i", *self.0).into()
|
||||
}
|
||||
async fn serialize(&self, _: SysCtx, write: Pin<&mut (impl AsyncWrite + ?Sized)>) {
|
||||
async fn serialize(&self, write: Pin<&mut (impl AsyncWrite + ?Sized)>) {
|
||||
self.0.encode(write).await
|
||||
}
|
||||
async fn deserialize(mut ctx: impl DeserializeCtx, _: ()) -> Self {
|
||||
let s = ctx.decode::<String>().await;
|
||||
Self(ctx.sys().i().i(&s).await)
|
||||
async fn deserialize(mut dctx: impl DeserializeCtx, _: ()) -> Self {
|
||||
let s = dctx.decode::<String>().await;
|
||||
Self(i().i(&s).await)
|
||||
}
|
||||
}
|
||||
impl TryFromExpr for IntStrAtom {
|
||||
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
||||
Ok(IntStrAtom(i().ex(TAtom::<IntStrAtom>::try_from_expr(expr).await?.value).await))
|
||||
}
|
||||
}
|
||||
impl Supports<ToStringMethod> for IntStrAtom {
|
||||
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response {
|
||||
self.0.as_str().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OrcString {
|
||||
kind: OrcStringKind,
|
||||
ctx: SysCtx,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -95,7 +109,7 @@ pub enum OrcStringKind {
|
||||
impl OrcString {
|
||||
pub async fn get_string(&self) -> Rc<String> {
|
||||
match &self.kind {
|
||||
OrcStringKind::Int(tok) => self.ctx.i().ex(**tok).await.rc(),
|
||||
OrcStringKind::Int(tok) => i().ex(**tok).await.rc(),
|
||||
OrcStringKind::Val(atom) => atom.request(StringGetVal).await,
|
||||
}
|
||||
}
|
||||
@@ -104,12 +118,11 @@ impl OrcString {
|
||||
impl TryFromExpr for OrcString {
|
||||
async fn try_from_expr(expr: Expr) -> OrcRes<OrcString> {
|
||||
if let Ok(v) = TAtom::<StrAtom>::try_from_expr(expr.clone()).await {
|
||||
return Ok(OrcString { ctx: expr.ctx(), kind: OrcStringKind::Val(v) });
|
||||
return Ok(OrcString { kind: OrcStringKind::Val(v) });
|
||||
}
|
||||
let ctx = expr.ctx();
|
||||
match TAtom::<IntStrAtom>::try_from_expr(expr).await {
|
||||
Ok(t) => Ok(OrcString { ctx: t.untyped.ctx().clone(), kind: OrcStringKind::Int(t) }),
|
||||
Err(e) => Err(mk_errv(ctx.i().i("A string was expected").await, "", e.pos_iter())),
|
||||
Ok(t) => Ok(OrcString { kind: OrcStringKind::Int(t) }),
|
||||
Err(e) => Err(mk_errv(i().i("A string was expected").await, "", e.pos_iter())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ use orchid_base::location::SrcRange;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::parse::ParseCtx;
|
||||
use orchid_base::sym;
|
||||
use orchid_base::tree::wrap_tokv;
|
||||
use orchid_base::tree::{Paren, wrap_tokv};
|
||||
use orchid_extension::context::i;
|
||||
use orchid_extension::gen_expr::sym_ref;
|
||||
use orchid_extension::lexer::{LexContext, Lexer, err_not_applicable};
|
||||
use orchid_extension::parser::p_tree2gen;
|
||||
use orchid_extension::tree::{GenTokTree, ref_tok, x_tok};
|
||||
use orchid_extension::tree::{GenTok, GenTokTree, ref_tok, x_tok};
|
||||
|
||||
use super::str_atom::IntStrAtom;
|
||||
|
||||
@@ -97,9 +99,9 @@ fn parse_string(str: &str) -> Result<String, StringError> {
|
||||
pub struct StringLexer;
|
||||
impl Lexer for StringLexer {
|
||||
const CHAR_FILTER: &'static [std::ops::RangeInclusive<char>] = &['"'..='"', '`'..='`'];
|
||||
async fn lex<'a>(all: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree)> {
|
||||
async fn lex<'a>(all: &'a str, lctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree)> {
|
||||
let Some(mut tail) = all.strip_prefix('"') else {
|
||||
return Err(err_not_applicable(ctx.ctx.i()).await);
|
||||
return Err(err_not_applicable().await);
|
||||
};
|
||||
let mut ret = None;
|
||||
let mut cur = String::new();
|
||||
@@ -121,19 +123,27 @@ impl Lexer for StringLexer {
|
||||
}
|
||||
let add_frag = |prev: Option<GenTokTree>, new: GenTokTree| async {
|
||||
let Some(prev) = prev else { return new };
|
||||
let concat_fn = ref_tok(sym!(std::string::concat; ctx.i()).await)
|
||||
let concat_fn = ref_tok(sym!(std::string::concat; lctx.i()))
|
||||
.await
|
||||
.at(SrcRange::zw(prev.sr.path(), prev.sr.start()));
|
||||
wrap_tokv([concat_fn, prev, new])
|
||||
};
|
||||
loop {
|
||||
if let Some(rest) = tail.strip_prefix('"') {
|
||||
return Ok((rest, add_frag(ret, str_to_gen(&mut cur, tail, &mut errors, ctx).await).await));
|
||||
return Ok((
|
||||
rest,
|
||||
add_frag(ret, str_to_gen(&mut cur, tail, &mut errors, lctx).await).await,
|
||||
));
|
||||
} else if let Some(rest) = tail.strip_prefix('$') {
|
||||
ret = Some(add_frag(ret, str_to_gen(&mut cur, tail, &mut errors, ctx).await).await);
|
||||
let (new_tail, tree) = ctx.recurse(rest).await?;
|
||||
ret = Some(add_frag(ret, str_to_gen(&mut cur, tail, &mut errors, lctx).await).await);
|
||||
let (new_tail, tree) = lctx.recurse(rest).await?;
|
||||
tail = new_tail;
|
||||
ret = Some(add_frag(ret, p_tree2gen(tree)).await);
|
||||
// wrap the received token in a call to to_str
|
||||
let to_str = sym_ref(sym!(std::string::to_str; i()));
|
||||
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);
|
||||
ret = Some(add_frag(ret, to_str_call).await);
|
||||
} else if tail.starts_with('\\') {
|
||||
// parse_string will deal with it, we just have to skip the next char
|
||||
tail = &tail[2..];
|
||||
@@ -143,11 +153,11 @@ impl Lexer for StringLexer {
|
||||
cur.push(c);
|
||||
tail = ch.as_str();
|
||||
} else {
|
||||
let range = ctx.pos(all)..ctx.pos("");
|
||||
let range = lctx.pos(all)..lctx.pos("");
|
||||
return Err(mk_errv(
|
||||
ctx.i().i("No string end").await,
|
||||
lctx.i().i("No string end").await,
|
||||
"String never terminated with \"",
|
||||
[SrcRange::new(range.clone(), ctx.src())],
|
||||
[SrcRange::new(range.clone(), lctx.src())],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,60 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use orchid_extension::tree::{GenMember, comments, fun, prefix};
|
||||
use orchid_base::format::fmt;
|
||||
use orchid_base::sym;
|
||||
use orchid_extension::atom::ForeignAtom;
|
||||
use orchid_extension::context::i;
|
||||
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::tree::{GenMember, cnst, comments, fun, prefix};
|
||||
|
||||
use super::str_atom::StrAtom;
|
||||
use crate::OrcString;
|
||||
use crate::std::protocol::types::get_impl;
|
||||
use crate::std::string::to_string::{AsStrTag, ToStringMethod};
|
||||
|
||||
pub fn gen_str_lib() -> Vec<GenMember> {
|
||||
prefix("std::string", [comments(
|
||||
["Concatenate two strings"],
|
||||
fun(true, "concat", |left: OrcString, right: OrcString| async move {
|
||||
StrAtom::new(Rc::new(left.get_string().await.to_string() + &right.get_string().await))
|
||||
}),
|
||||
)])
|
||||
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__; i()));
|
||||
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 StrAtom::new(Rc::new(fmt(&input, &i()).await)).to_gen().await;
|
||||
})
|
||||
.await
|
||||
}),
|
||||
),
|
||||
prefix("to_string", [
|
||||
cnst(true, "__type_tag__", AsStrTag),
|
||||
fun(true, "resolve", async |atom: ForeignAtom| {
|
||||
exec(async |mut h| {
|
||||
let proto = h.exec(sym_ref(sym!(std::string::to_string; i()))).await?;
|
||||
Ok(call(get_impl(atom.clone(), proto).await?.to_gen().await, [atom.to_gen().await]))
|
||||
})
|
||||
.await
|
||||
}),
|
||||
]),
|
||||
])
|
||||
}
|
||||
|
||||
36
orchid-std/src/std/string/to_string.rs
Normal file
36
orchid-std/src/std/string/to_string.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use orchid_api_derive::Coding;
|
||||
use orchid_api_traits::Request;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports};
|
||||
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
|
||||
use orchid_extension::context::i;
|
||||
|
||||
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod};
|
||||
|
||||
#[derive(Coding, Clone, Debug)]
|
||||
pub struct AsStrTag;
|
||||
impl Atomic for AsStrTag {
|
||||
type Data = AsStrTag;
|
||||
type Variant = ThinVariant;
|
||||
fn reg_reqs() -> MethodSetBuilder<Self> {
|
||||
MethodSetBuilder::new().handle::<GetTagIdMethod>().handle::<GetImplMethod>()
|
||||
}
|
||||
}
|
||||
impl ThinAtom for AsStrTag {}
|
||||
impl Supports<GetTagIdMethod> for AsStrTag {
|
||||
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response {
|
||||
Sym::parse("std::string::to_string", &i()).await.unwrap().to_api()
|
||||
}
|
||||
}
|
||||
impl Supports<GetImplMethod> for AsStrTag {
|
||||
async fn handle(&self, _: GetImplMethod) -> <GetImplMethod as Request>::Response { None }
|
||||
}
|
||||
|
||||
#[derive(Coding, Clone, Debug)]
|
||||
pub struct ToStringMethod;
|
||||
impl Request for ToStringMethod {
|
||||
type Response = String;
|
||||
}
|
||||
impl AtomMethod for ToStringMethod {
|
||||
const NAME: &str = "std::string::to_string";
|
||||
}
|
||||
Reference in New Issue
Block a user