for a moment, everything works

This commit is contained in:
2025-02-21 23:53:31 +01:00
parent 9e7648bc72
commit cfa8b6ee52
23 changed files with 491 additions and 371 deletions

View File

@@ -16,4 +16,5 @@ 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" }
ordered-float = "4.6.0"
rust_decimal = "1.36.0"
tokio = { version = "1.43.0", features = ["full"] }

View File

@@ -1,6 +1,7 @@
use orchid_api_derive::Coding;
use orchid_base::error::OrcRes;
use orchid_base::format::FmtUnit;
use orchid_base::number::Numeric;
use orchid_extension::atom::{
AtomFactory, Atomic, AtomicFeatures, MethodSetBuilder, ToAtom, TypAtom,
};
@@ -9,6 +10,7 @@ use orchid_extension::conv::TryFromExpr;
use orchid_extension::expr::Expr;
use orchid_extension::system::SysCtx;
use ordered_float::NotNan;
use rust_decimal::prelude::Zero;
#[derive(Clone, Debug, Coding)]
pub struct Int(pub i64);
@@ -38,27 +40,56 @@ impl ThinAtom for Float {
}
impl TryFromExpr for Float {
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
TypAtom::<Float>::try_from_expr(expr).await.map(|t| t.value)
Ok(Self(Num::try_from_expr(expr).await?.0.to_f64()))
}
}
pub enum Numeric {
Int(i64),
Float(NotNan<f64>),
}
impl TryFromExpr for Numeric {
pub struct Num(pub Numeric);
impl TryFromExpr for Num {
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
match Int::try_from_expr(expr.clone()).await {
Ok(t) => Ok(Numeric::Int(t.0)),
Err(e) => Float::try_from_expr(expr).await.map(|t| Numeric::Float(t.0)).map_err(|e2| e + e2),
let e = match Int::try_from_expr(expr.clone()).await {
Ok(t) => return Ok(Num(Numeric::Int(t.0))),
Err(e) => e,
};
match TypAtom::<Float>::try_from_expr(expr).await {
Ok(t) => Ok(Num(Numeric::Float(t.0))),
Err(e2) => Err(e + e2),
}
}
}
impl ToAtom for Numeric {
impl ToAtom for Num {
fn to_atom_factory(self) -> AtomFactory {
match self {
Self::Float(f) => Float(f).factory(),
Self::Int(i) => Int(i).factory(),
match self.0 {
Numeric::Float(f) => Float(f).factory(),
Numeric::Int(i) => Int(i).factory(),
}
}
}
/// A homogenous fixed length number array that forces all of its elements into
/// the weakest element type. This describes the argument casting behaviour of
/// most numeric operations.
pub enum HomoArray<const N: usize> {
Int([i64; N]),
Float([NotNan<f64>; N]),
}
impl<const N: usize> HomoArray<N> {
pub fn new(n: [Numeric; N]) -> Self {
let mut ints = [0i64; N];
for i in 0..N {
if let Numeric::Int(val) = n[i] {
ints[i] = val
} else {
let mut floats = [NotNan::zero(); N];
for (i, int) in ints.iter().take(i).enumerate() {
floats[i] = NotNan::new(*int as f64).expect("i64 cannot convert to f64 NaN");
}
for j in i..N {
floats[j] = n[j].to_f64();
}
return Self::Float(floats);
}
}
Self::Int(ints)
}
}

View File

@@ -1,13 +1,12 @@
use std::ops::RangeInclusive;
use orchid_base::error::OrcRes;
use orchid_base::number::{Numeric, num_to_err, parse_num};
use orchid_extension::atom::AtomicFeatures;
use orchid_base::number::{num_to_err, parse_num};
use orchid_extension::atom::ToAtom;
use orchid_extension::lexer::{LexContext, Lexer};
use orchid_extension::tree::{GenTok, GenTokTree};
use ordered_float::NotNan;
use super::num_atom::{Float, Int};
use super::num_atom::Num;
#[derive(Default)]
pub struct NumLexer;
@@ -17,9 +16,7 @@ impl Lexer for NumLexer {
let ends_at = all.find(|c: char| !c.is_ascii_hexdigit() && !"xX._pP".contains(c));
let (chars, tail) = all.split_at(ends_at.unwrap_or(all.len()));
let fac = match parse_num(chars) {
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(),
Ok(numeric) => Num(numeric).to_atom_factory(),
Err(e) => return Err(num_to_err(e, ctx.pos(all), ctx.i).await.into()),
};
Ok((tail, GenTok::X(fac).at(ctx.pos(all)..ctx.pos(tail))))

View File

@@ -1,6 +1,7 @@
use std::rc::Rc;
use never::Never;
use orchid_base::number::Numeric;
use orchid_base::reqnot::Receipt;
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
use orchid_extension::entrypoint::ExtReq;
@@ -8,9 +9,10 @@ use orchid_extension::fs::DeclFs;
use orchid_extension::system::{System, SystemCard};
use orchid_extension::system_ctor::SystemCtor;
use orchid_extension::tree::{MemKind, comments, fun, module, root_mod};
use ordered_float::NotNan;
use crate::OrcString;
use crate::number::num_atom::{Float, Int};
use crate::number::num_atom::{Float, HomoArray, Int, Num};
use crate::number::num_lexer::NumLexer;
use crate::string::str_atom::{IntStrAtom, StrAtom};
use crate::string::str_lexer::StringLexer;
@@ -37,11 +39,39 @@ impl System for StdSystem {
fn parsers() -> Vec<orchid_extension::parser::ParserObj> { vec![] }
fn vfs() -> DeclFs { DeclFs::Mod(&[]) }
fn env() -> Vec<(String, MemKind)> {
vec![root_mod("std", [], [module(true, "string", [], [comments(
["Concatenate two strings"],
fun(true, "concat", |left: OrcString<'static>, right: OrcString<'static>| async move {
StrAtom::new(Rc::new(left.get_string().await.to_string() + &right.get_string().await))
}),
)])])]
vec![root_mod("std", [], [
module(true, "string", [], [comments(
["Concatenate two strings"],
fun(true, "concat", |left: OrcString<'static>, right: OrcString<'static>| async move {
StrAtom::new(Rc::new(left.get_string().await.to_string() + &right.get_string().await))
}),
)]),
module(true, "number", [], [
fun(true, "add", |a: Num, b: Num| async move {
Num(match HomoArray::new([a.0, b.0]) {
HomoArray::Int([a, b]) => Numeric::Int(a + b),
HomoArray::Float([a, b]) => Numeric::Float(a + b),
})
}),
fun(true, "neg", |a: Num| async move {
Num(match a.0 {
Numeric::Int(i) => Numeric::Int(-i),
Numeric::Float(f) => Numeric::Float(-f),
})
}),
fun(true, "mul", |a: Num, b: Num| async move {
Num(match HomoArray::new([a.0, b.0]) {
HomoArray::Int([a, b]) => Numeric::Int(a * b),
HomoArray::Float([a, b]) => Numeric::Float(a * b),
})
}),
fun(true, "idiv", |a: Int, b: Int| async move { Int(a.0 / b.0) }),
fun(true, "imod", |a: Int, b: Int| async move { Int(a.0 % b.0) }),
fun(true, "fdiv", |a: Float, b: Float| async move { Float(a.0 / b.0) }),
fun(true, "fmod", |a: Float, b: Float| async move {
Float(a.0 - NotNan::new((a.0 / b.0).trunc()).unwrap() * b.0)
}),
]),
])]
}
}

View File

@@ -74,7 +74,7 @@ impl OwnedAtom for IntStrAtom {
}
async fn deserialize(mut ctx: impl DeserializeCtx, _: ()) -> Self {
let s = ctx.decode::<String>().await;
Self(ctx.sys().i.i(&s).await)
Self(ctx.sys().i().i(&s).await)
}
}
@@ -92,7 +92,7 @@ pub enum OrcStringKind<'a> {
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) => self.ctx.i().ex(**tok).await.rc(),
OrcStringKind::Val(atom) => atom.request(StringGetVal).await,
}
}
@@ -106,7 +106,7 @@ impl TryFromExpr for OrcString<'static> {
let ctx = expr.ctx();
match TypAtom::<IntStrAtom>::try_from_expr(expr).await {
Ok(t) => Ok(OrcString { ctx: t.data.ctx(), kind: OrcStringKind::Int(t) }),
Err(e) => Err(mk_errv(ctx.i.i("A string was expected").await, "", e.pos_iter())),
Err(e) => Err(mk_errv(ctx.i().i("A string was expected").await, "", e.pos_iter())),
}
}
}