Began implementing fully isomorphic macros

Like Rust's Proc macros. Now we have preprocessor recursion to worry about. I also made a cool macro for enums
This commit is contained in:
2024-10-14 00:13:09 +02:00
parent 84cbcdd4fe
commit 3a3ae98aff
66 changed files with 2302 additions and 1164 deletions

View File

@@ -1,10 +1,9 @@
use never::Never;
use orchid_api_derive::Coding;
use orchid_base::error::OrcRes;
use orchid_extension::atom::{AtomFactory, Atomic, AtomicFeatures, ReqPck, ToAtom, TypAtom};
use orchid_extension::atom::{AtomFactory, MethodSet, Atomic, AtomicFeatures, ToAtom, TypAtom};
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
use orchid_extension::conv::TryFromExpr;
use orchid_extension::expr::ExprHandle;
use orchid_extension::expr::Expr;
use ordered_float::NotNan;
#[derive(Clone, Debug, Coding)]
@@ -12,13 +11,13 @@ pub struct Int(pub i64);
impl Atomic for Int {
type Variant = ThinVariant;
type Data = Self;
type Req = Never;
}
impl ThinAtom for Int {
fn handle_req(&self, pck: impl ReqPck<Self>) { pck.never() }
fn reg_reqs() -> MethodSet<Self> {
MethodSet::new()
}
}
impl ThinAtom for Int {}
impl TryFromExpr for Int {
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self> {
fn try_from_expr(expr: Expr) -> OrcRes<Self> {
TypAtom::<Int>::try_from_expr(expr).map(|t| t.value)
}
}
@@ -28,13 +27,11 @@ pub struct Float(pub NotNan<f64>);
impl Atomic for Float {
type Variant = ThinVariant;
type Data = Self;
type Req = Never;
}
impl ThinAtom for Float {
fn handle_req(&self, pck: impl ReqPck<Self>) { pck.never() }
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
}
impl ThinAtom for Float {}
impl TryFromExpr for Float {
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self> {
fn try_from_expr(expr: Expr) -> OrcRes<Self> {
TypAtom::<Float>::try_from_expr(expr).map(|t| t.value)
}
}
@@ -44,10 +41,10 @@ pub enum Numeric {
Float(NotNan<f64>),
}
impl TryFromExpr for Numeric {
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self> {
Int::try_from_expr(expr.clone()).map(|t| Numeric::Int(t.0)).or_else(|e| {
Float::try_from_expr(expr).map(|t| Numeric::Float(t.0)).map_err(|e2| [e, e2].concat())
})
fn try_from_expr(expr: Expr) -> OrcRes<Self> {
Int::try_from_expr(expr.clone())
.map(|t| Numeric::Int(t.0))
.or_else(|e| Float::try_from_expr(expr).map(|t| Numeric::Float(t.0)).map_err(|e2| e + e2))
}
}
impl ToAtom for Numeric {

View File

@@ -20,7 +20,7 @@ impl Lexer for NumLexer {
Ok(Numeric::Float(f)) => Float(f).factory(),
Ok(Numeric::Uint(uint)) => Int(uint.try_into().unwrap()).factory(),
Ok(Numeric::Decimal(dec)) => Float(NotNan::new(dec.try_into().unwrap()).unwrap()).factory(),
Err(e) => return Err(vec![num_to_err(e, ctx.pos(all))]),
Err(e) => return Err(num_to_err(e, ctx.pos(all)).into()),
};
Ok((tail, GenTok::X(fac).at(ctx.pos(all)..ctx.pos(tail))))
}

View File

@@ -1,11 +1,13 @@
use std::sync::Arc;
use never::Never;
use orchid_base::interner::Tok;
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
use orchid_extension::entrypoint::ExtReq;
use orchid_extension::fs::DeclFs;
use orchid_extension::system::{System, SystemCard};
use orchid_extension::system_ctor::SystemCtor;
use orchid_extension::tree::{comments, fun, module, root_mod, GenMemberKind};
use orchid_extension::tree::{comments, fun, module, root_mod, MemKind};
use crate::number::num_atom::{Float, Int};
use crate::string::str_atom::{IntStrAtom, StrAtom};
@@ -23,14 +25,17 @@ impl SystemCtor for StdSystem {
}
impl SystemCard for StdSystem {
type Ctor = Self;
const ATOM_DEFS: &'static [Option<&'static dyn AtomDynfo>] =
&[Some(Int::INFO), Some(Float::INFO), Some(StrAtom::INFO), Some(IntStrAtom::INFO)];
type Req = Never;
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomDynfo>>> {
[Some(Int::dynfo()), Some(Float::dynfo()), Some(StrAtom::dynfo()), Some(IntStrAtom::dynfo())]
}
}
impl System for StdSystem {
fn request(_: ExtReq, req: Self::Req) -> orchid_base::reqnot::Receipt { match req {} }
fn lexers() -> Vec<orchid_extension::lexer::LexerObj> { vec![&StringLexer] }
fn parsers() -> Vec<orchid_extension::parser::ParserObj> { vec![] }
fn vfs() -> DeclFs { DeclFs::Mod(&[]) }
fn env() -> Vec<(Tok<String>, GenMemberKind)> {
fn env() -> Vec<(Tok<String>, MemKind)> {
vec![root_mod("std", [], [module(true, "string", [], [comments(
["Concatenate two strings"],
fun(true, "concat", |left: OrcString, right: OrcString| {

View File

@@ -1,52 +1,53 @@
use std::borrow::Cow;
use std::io;
use std::num::NonZeroU64;
use std::ops::Deref;
use std::sync::Arc;
use never::Never;
use orchid_api_derive::Coding;
use orchid_api_traits::{Encode, Request};
use orchid_base::error::{mk_err, OrcRes};
use orchid_base::id_store::IdStore;
use orchid_base::error::{mk_errv, OrcRes};
use orchid_base::intern;
use orchid_base::interner::{deintern, intern, Tok};
use orchid_extension::atom::{Atomic, ReqPck, TypAtom};
use orchid_extension::atom::{AtomMethod, Atomic, MethodSet, Supports, TypAtom};
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
use orchid_extension::conv::TryFromExpr;
use orchid_extension::expr::ExprHandle;
use orchid_extension::expr::Expr;
use orchid_extension::system::SysCtx;
pub static STR_REPO: IdStore<Arc<String>> = IdStore::new();
#[derive(Copy, Clone, Coding)]
pub struct StringGetVal;
impl Request for StringGetVal {
type Response = String;
type Response = Arc<String>;
}
impl AtomMethod for StringGetVal {
const NAME: &str = "std::string_get_val";
}
impl Supports<StringGetVal> for StrAtom {
fn handle(&self, _: SysCtx, _: StringGetVal) -> <StringGetVal as Request>::Response {
self.0.clone()
}
}
pub struct StrAtom(NonZeroU64);
#[derive(Clone)]
pub struct StrAtom(Arc<String>);
impl Atomic for StrAtom {
type Variant = OwnedVariant;
type Data = NonZeroU64;
type Req = StringGetVal;
type Data = ();
fn reg_reqs() -> MethodSet<Self> { MethodSet::new().handle::<StringGetVal>() }
}
impl StrAtom {
pub fn new(str: Arc<String>) -> Self { Self(STR_REPO.add(str).id()) }
pub fn new(str: Arc<String>) -> Self { Self(str) }
pub fn value(&self) -> Arc<String> { self.0.clone() }
}
impl Clone for StrAtom {
fn clone(&self) -> Self { Self::new(self.local_value()) }
}
impl StrAtom {
fn try_local_value(&self) -> Option<Arc<String>> { STR_REPO.get(self.0).map(|r| r.clone()) }
fn local_value(&self) -> Arc<String> { self.try_local_value().expect("no string found for ID") }
impl Deref for StrAtom {
type Target = str;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl OwnedAtom for StrAtom {
type Refs = ();
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.0) }
fn same(&self, _: SysCtx, other: &Self) -> bool { self.local_value() == other.local_value() }
fn handle_req(&self, pck: impl ReqPck<Self>) { self.local_value().encode(pck.unpack().1) }
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
fn serialize(&self, _: SysCtx, sink: &mut (impl io::Write + ?Sized)) -> Self::Refs {
self.local_value().encode(sink)
self.deref().encode(sink)
}
fn deserialize(mut ctx: impl DeserializeCtx, _: Self::Refs) -> Self {
Self::new(Arc::new(ctx.read::<String>()))
@@ -58,7 +59,7 @@ pub struct IntStrAtom(Tok<String>);
impl Atomic for IntStrAtom {
type Variant = OwnedVariant;
type Data = orchid_api::TStr;
type Req = Never;
fn reg_reqs() -> MethodSet<Self> { MethodSet::new() }
}
impl From<Tok<String>> for IntStrAtom {
fn from(value: Tok<String>) -> Self { Self(value) }
@@ -66,8 +67,7 @@ impl From<Tok<String>> for IntStrAtom {
impl OwnedAtom for IntStrAtom {
type Refs = ();
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.0.marker()) }
fn handle_req(&self, pck: impl ReqPck<Self>) { pck.never() }
fn print(&self, _ctx: SysCtx) -> String { format!("{:?}i", self.0.as_str()) }
fn print(&self, _ctx: SysCtx) -> String { format!("{:?}i", *self.0) }
fn serialize(&self, _: SysCtx, write: &mut (impl io::Write + ?Sized)) { self.0.encode(write) }
fn deserialize(ctx: impl DeserializeCtx, _: ()) -> Self { Self(intern(&ctx.decode::<String>())) }
}
@@ -81,22 +81,19 @@ impl<'a> OrcString<'a> {
pub fn get_string(&self) -> Arc<String> {
match &self {
Self::Int(tok) => deintern(tok.value).arc(),
Self::Val(atom) => match STR_REPO.get(**atom) {
Some(rec) => rec.clone(),
None => Arc::new(atom.request(StringGetVal)),
},
Self::Val(atom) => atom.request(StringGetVal),
}
}
}
impl TryFromExpr for OrcString<'static> {
fn try_from_expr(expr: ExprHandle) -> OrcRes<OrcString<'static>> {
if let Ok(v) = TypAtom::<StrAtom>::downcast(expr.clone()) {
fn try_from_expr(expr: Expr) -> OrcRes<OrcString<'static>> {
if let Ok(v) = TypAtom::<StrAtom>::try_from_expr(expr.clone()) {
return Ok(OrcString::Val(v));
}
match TypAtom::<IntStrAtom>::downcast(expr) {
match TypAtom::<IntStrAtom>::try_from_expr(expr) {
Ok(t) => Ok(OrcString::Int(t)),
Err(e) => Err(vec![mk_err(intern!(str: "A string was expected"), "", [e.0.clone().into()])]),
Err(e) => Err(mk_errv(intern!(str: "A string was expected"), "", e.pos_iter())),
}
}
}

View File

@@ -1,11 +1,11 @@
use itertools::Itertools;
use orchid_base::error::{mk_err, OrcErr, OrcRes};
use orchid_base::error::{mk_err, mk_errv, OrcErr, OrcRes};
use orchid_base::interner::intern;
use orchid_base::location::Pos;
use orchid_base::tree::{vname_tv, wrap_tokv};
use orchid_base::{intern, vname};
use orchid_extension::atom::AtomicFeatures;
use orchid_extension::lexer::{err_lexer_na, LexContext, Lexer};
use orchid_extension::lexer::{err_not_applicable, LexContext, Lexer};
use orchid_extension::tree::{GenTok, GenTokTree};
use super::str_atom::IntStrAtom;
@@ -96,33 +96,31 @@ pub struct StringLexer;
impl Lexer for StringLexer {
const CHAR_FILTER: &'static [std::ops::RangeInclusive<char>] = &['"'..='"'];
fn lex<'a>(all: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)> {
let mut tail = all.strip_prefix('"').ok_or_else(err_lexer_na)?;
let mut parts = Vec::<GenTokTree<'a>>::new();
let mut tail = all.strip_prefix('"').ok_or_else(err_not_applicable)?;
let mut ret = GenTok::X(IntStrAtom::from(intern!(str: "")).factory()).at(ctx.tok_ran(0, all));
let mut cur = String::new();
let mut errors = vec![];
let commit_str =
|str: &mut String, tail: &str, err: &mut Vec<OrcErr>, parts: &mut Vec<GenTokTree<'a>>| {
let str_val = parse_string(str)
.inspect_err(|e| err.push(e.clone().into_proj(ctx.pos(tail) - str.len() as u32)))
.unwrap_or_default();
let tok = GenTok::X(IntStrAtom::from(intern(&*str_val)).factory());
parts.push(tok.at(ctx.tok_ran(str.len() as u32, tail)));
*str = String::new();
};
let str_to_gen = |str: &mut String, tail: &str, err: &mut Vec<OrcErr>| {
let str_val = parse_string(&str.split_off(0))
.inspect_err(|e| err.push(e.clone().into_proj(ctx.pos(tail) - str.len() as u32)))
.unwrap_or_default();
GenTok::X(IntStrAtom::from(intern(&*str_val)).factory())
.at(ctx.tok_ran(str.len() as u32, tail))
};
let add_frag = |prev: GenTokTree<'a>, new: GenTokTree<'a>| {
let range = prev.range.start..new.range.end;
wrap_tokv(vname_tv(&vname!(std::string::concat), new.range.end).chain([prev, new]), range)
};
loop {
if let Some(rest) = tail.strip_prefix('"') {
commit_str(&mut cur, tail, &mut errors, &mut parts);
return Ok((rest, wrap_tokv(parts, ctx.pos(all)..ctx.pos(rest))));
return Ok((rest, add_frag(ret, str_to_gen(&mut cur, tail, &mut errors))));
} else if let Some(rest) = tail.strip_prefix('$') {
commit_str(&mut cur, tail, &mut errors, &mut parts);
parts.push(GenTok::Name(intern!(str: "++")).at(ctx.tok_ran(1, rest)));
parts.extend(vname_tv(&vname!(std::string::convert), ctx.tok_ran(1, rest)));
ret = add_frag(ret, str_to_gen(&mut cur, tail, &mut errors));
let (new_tail, tree) = ctx.recurse(rest)?;
tail = new_tail;
parts.push(tree);
ret = add_frag(ret, tree);
} else if tail.starts_with('\\') {
// parse_string will deal with it, we just have to make sure we skip the next
// char
// parse_string will deal with it, we just have to skip the next char
tail = &tail[2..];
} else {
let mut ch = tail.chars();
@@ -131,12 +129,9 @@ impl Lexer for StringLexer {
tail = ch.as_str();
} else {
let range = ctx.pos(all)..ctx.pos("");
commit_str(&mut cur, tail, &mut errors, &mut parts);
return Err(vec![mk_err(
intern!(str: "No string end"),
"String never terminated with \"",
[Pos::Range(range.clone()).into()],
)]);
return Err(mk_errv(intern!(str: "No string end"), "String never terminated with \"", [
Pos::Range(range.clone()).into(),
]));
}
}
}