diff --git a/src/a.rs b/src/a.rs index aa29f70..8072d32 100644 --- a/src/a.rs +++ b/src/a.rs @@ -41,8 +41,7 @@ use super::*; use std::marker::PhantomData as PD; toob!(i00_for_3x3,arr3x3,0,0);toob!(i01_for_3x3,arr3x3,0,1);toob!(i14_for_3x3,arr3x3,1,4); toob!(i41_for_3x3,arr3x3,4,1);toob!(i44_for_3x3,arr3x3,4,4); ti!(i11_for_3x3,arr3x3,1,1,0);ti!(i21_for_3x3,arr3x3,2,1,3);ti!(i22_for_3x3,arr3x3,2,2,4); - ti!(i31_for_3x3,arr3x3,3,1,6);ti!(i33_for_3x3,arr3x3,3,3,8); -} + ti!(i31_for_3x3,arr3x3,3,1,6);ti!(i33_for_3x3,arr3x3,3,3,8); } /**array allocation*/mod alloc{use{super::*,std::alloc::{alloc,alloc_zeroed,dealloc}}; /**sealed trait, memory markers*/pub trait MX{} impl MX for MU {} impl MX for MI {} @@ -50,23 +49,18 @@ use super::*; use std::marker::PhantomData as PD; /**marker: memory initialized*/ #[derive(CL,DBG)]pub struct MI; impl A{ pub fn new(m:U,n:U)->R{Self::alloc(m,n).map(|(l,d)|A{m,n,d,l,i:PD})} - // TODO: use `A::iter` - // TODO: use `set_unchecked` here. pub fn init_withR>(mut self,mut f:F)->R>{let(A{m,n,..})=self; for(i)in(1..=m){for(j)in(1..=n){let(v)=f(i,j)?;self.set(i,j,v)?;}}Ok(unsafe{self.finish()})} - pub unsafe fn finish(self)->A{std::mem::transmute(self)} - } + pub unsafe fn finish(self)->A{std::mem::transmute(self)}} impl A{ pub fn zeroed(m:U,n:U)->R{let(l,d)=Self::allocz(m,n)?;Ok(A{m,n,d,l,i:PD})} pub fn from_i(i:I)->R{let mut a=A::new(1,1)?;a.set(1,1,i)?;Ok(unsafe{a.finish()})}} impl TF for A{type Error=E;fn try_from(i:I)->R{A::from_i(i)}} impl A{ - fn alloc(m:U,n:U)->R<(L,*mut u8)>{let(l)=Self::l(m,n)?;let d=unsafe{alloc(l)};Ok((l,d))} + fn alloc (m:U,n:U)->R<(L,*mut u8)>{let(l)=Self::l(m,n)?;let d=unsafe{alloc(l)}; Ok((l,d))} fn allocz(m:U,n:U)->R<(L,*mut u8)>{let(l)=Self::l(m,n)?;let d=unsafe{alloc_zeroed(l)};Ok((l,d))} - fn l(m:U,n:U)->R{L::array::(m*n).map_err(E::from)} - } + fn l(m:U,n:U)->R{L::array::(m*n).map_err(E::from)}} impl Drop for A{fn drop(&mut self){let(A{d,l,..})=self;unsafe{dealloc(*d,*l)}}} - // TODO: add compile_fail checks to ensure that e.g. `get` cannot be used on an uninitialized array } pub use self::alloc::{MI,MU,MX}; /**array access*/mod access{use{super::*,std::mem::size_of}; @@ -86,8 +80,7 @@ use super::*; use std::marker::PhantomData as PD; pub(crate)fn ptr_at_uc(&self,i:U,j:U)->R<*mut I>{self.ptr_at_impl(i,j,Self::index_uc)} fn ptr_at_implR>(&self,i:U,j:U,f:F)->R<*mut I>{ let(o):isize=f(self,i,j).map(|x|x*size_of::())?.try_into()?;let(d)=unsafe{(self.d.offset(o) as *mut I)}; - Ok(d)} - }} + Ok(d)}}} /**scalar conversion/comparison*/mod scalars{use super::*; /*todo...*/ impl A{pub fn as_i(&self)->R{let a@A{m:1,n:1,..}=self else{bail!("not a scalar")};a.get(1,1)}} @@ -123,8 +116,7 @@ use super::*; use std::marker::PhantomData as PD; if(r.len()!=self.m){r!(false)}for(i,r_i)in(r.into_iter().enumerate()){ if(r_i.len()!=self.n){r!(false)}for(j,r_ij)in(r_i.into_iter().enumerate()){ let(i,j)=(i+1,j+1);let(a_ij)=match(self.get(i,j)){Ok(v)=>v,Err(_)=>r!(false)}; - if(a_ij)!=(*r_ij){r!(false)}}}true}} -} + if(a_ij)!=(*r_ij){r!(false)}}}true}}} /**monadic verbs*/impl A{ pub fn m_same(self)->R{Ok(self)} @@ -138,8 +130,7 @@ use super::*; use std::marker::PhantomData as PD; pub fn m_tally(self)->R{let A{m,n,..}=self;let(i)=I::try_from(m*n)?;A::from_i(i)} pub fn m_trans(self)->R{let(i@A{m:m_i,n:n_i,..})=self;let(m_o,n_o)=(n_i,m_i); let(f)=|i_o,j_o|{i.get(j_o,i_o)};A::new(m_o,n_o)?.init_with(f)} - pub fn m_inc(self)->R{let(a@A{m,n,..})=self;A::new(m,n)?.init_with(|i,j|a.get(i,j).map(|x|x+1))} -} + pub fn m_inc(self)->R{let(a@A{m,n,..})=self;A::new(m,n)?.init_with(|i,j|a.get(i,j).map(|x|x+1))}} /**dyadic verbs*/impl D{ /*return dyad function**/ pub fn f(&self)->fn(I,I)->I{use D::*; @@ -163,8 +154,7 @@ use super::*; use std::marker::PhantomData as PD; else if (ml==nr)&&(nl==mr) /*NB: inherit the dimensions of the right-hand operand.*/ // rotation {let(f)=|i,j|{let(x)=l.get(j,i)?;let(y)=r.get(i,j)?;Ok(f(x,y))};r!(A::new(mr,nr)?.init_with(f))} bail!("length error"); - } -} + }} /**monadic adverbs*/mod adverbs_m{use super::*; impl Ym{ @@ -177,8 +167,7 @@ use super::*; use std::marker::PhantomData as PD; else if let Ok(s)=a.as_slice(){let (m,n)=(s.len(),s.len()); let p=|i,j|if(j>i){Ok(0)}else{a.get(1,j).map(d_)}; A::new(m,n)?.init_with(p)} - else { bail!("monadic `\\` is not implemented for matrices") }} - } + else { bail!("monadic `\\` is not implemented for matrices") }}} // === monadic `/`, `Ym::Insert` tests macro_rules! test_insert{($f:ident,$d:expr,$a:expr,$o:expr)=> {#[test]fn $f()->R<()>{let(a):R={$a};let(d):D={$d}; // typecheck macro arguments. @@ -186,8 +175,7 @@ use super::*; use std::marker::PhantomData as PD; eq!(i,$o);ok!()}}} test_insert!(add_a_scalar, D::Plus, A::from_i(42), 42 ); test_insert!(add_a_sequence, D::Plus, >::try_from(&[1,2,3,4,5]), (1+2+3+4+5) ); - test_insert!(mul_a_sequence, D::Mul , >::try_from(&[1,2,3,4,5]), (1*2*3*4*5) ); -} + test_insert!(mul_a_sequence, D::Mul , >::try_from(&[1,2,3,4,5]), (1*2*3*4*5) ); } /**dyadic adverbs*/mod adverbs_d{use super::*; impl Yd{ @@ -203,17 +191,12 @@ use super::*; use std::marker::PhantomData as PD; fn infix(d:D,l:A,r:A)->R{let(s)=r.as_slice().map_err(|_|err!("infix rhs must be a slice"))?; let(il)=l.as_i() .map_err(|_|err!("infix lhs must be a scalar"))?.try_into()?; let(ic)=(s.len()-il)+1; - A::new(ic,il)?.init_with(|i,j|Ok(s[(i-1)+(j-1)]))} - } -} + A::new(ic,il)?.init_with(|i,j|Ok(s[(i-1)+(j-1)]))}}} /**deep-copy*/impl A{ - pub fn deep_copy(&self)->R{let A{m,n,l:li,d:di,i:_}=*self;A::new(m,n)?.init_with(|i,j|{self.get(i,j)})} -} + pub fn deep_copy(&self)->R{let A{m,n,l:li,d:di,i:_}=*self;A::new(m,n)?.init_with(|i,j|{self.get(i,j)})}} /**display*/mod fmt{use super::*; impl DS for A{ - // TODO: buffer stdout, flush after loops - // TODO: use `unchecked` to elide bounds checks in printing fn fmt(&self,fmt:&mut FMT)->FR{let A{m,n,..}=*self;for(i,j)in(self.iter()) {let(x)=self.get_uc(i,j).map_err(|_|std::fmt::Error)?;write!(fmt,"{x}{}",if(j==n){'\n'}else{' '})?;}ok!()}}} diff --git a/src/j.rs b/src/j.rs index beb5613..057189f 100644 --- a/src/j.rs +++ b/src/j.rs @@ -5,16 +5,15 @@ pub use self::{a::*,r::*,s::*}; pub fn eval(input:&str,st:&mut ST)->R>{ let(mut ts)=lex(input)?;let(ast)=match(parse(&mut ts)?){Some(x)=>x,None=>rrn!()};eval_(ast,st)} fn eval_(ast:B,st:&mut ST)->R>{use{M::*,D::*}; - let(mut rec)=|a|->R{match(eval_(a,st)){Ok(Some(a))=>Ok(a),Err(e)=>Err(e), // recursively evaluate subexpression. + let(mut rec)=|a|->R{match(eval_(a,st)){Ok(Some(a))=>Ok(a),Err(e)=>Err(e),/*recursively evaluate*/ Ok(None)=>Err(err!("expression did not result in a value"))}}; - match *ast{ - N::A{a} =>Ok(a), - N::M{m,o} =>{let(a)=rec(o)?; match m{Idot=>a.m_idot(), Shape=>a.m_shape(), Same=>a.m_same(), - Tally=>a.m_tally(),Transpose=>a.m_trans(), Inc=>a.m_inc()}} - N::D{d,l,r}=>{let(l,r)=(rec(l)?,rec(r)?);match d{Plus=>l.d_plus(r), Mul=>l.d_mul(r), - Left=>l.d_left(r), Right=>l.d_right(r)}} - N::Ym{ym,d,o}=>{rec(o).and_then(|a|ym.apply(d,a))} - N::Yd{yd,d,l,r}=>{let(l,r)=(rec(l)?,rec(r)?);yd.apply(d,l,r)} - N::S{sy} =>{st.get(&sy).ok_or(err!("undefined symbol: {sy:?}")).and_then(A::deep_copy)} - N::E{sy,e} =>{let(a)=rec(e)?;st.insert(sy,a);r!(Ok(None))} -}.map(O::Some)} + match *ast{N::A{a}=>Ok(a), // array literal + N::M{m,o }=>{let(a)=rec(o)?; match m{Idot=>a.m_idot(),Shape=>a.m_shape(),Transpose=>a.m_trans(), // monadic verb + Same=>a.m_same(),Tally=>a.m_tally(),Inc=>a.m_inc()}} + N::D{d,l,r }=>{let(l,r)=(rec(l)?,rec(r)?);match d{Plus=>l.d_plus(r),Mul=>l.d_mul(r), // dyadic verb + Left=>l.d_left(r),Right=>l.d_right(r)}} + N::Ym{ym,d,o }=>{rec(o).and_then(|a|ym.apply(d,a))} // monadic adverb + N::Yd{yd,d,l,r}=>{let(l,r)=(rec(l)?,rec(r)?);yd.apply(d,l,r)} // dyadic adverb + N::E {sy,e }=>{let(a)=rec(e)?;st.insert(sy,a);r!(Ok(None))} // symbol assignment + N::S {sy }=>{st.get(&sy).ok_or(err!("undefined symbol: {sy:?}")).and_then(A::deep_copy)} // symbol + }.map(O::Some)} diff --git a/src/p.rs b/src/p.rs index a5f822d..2aa0471 100644 --- a/src/p.rs +++ b/src/p.rs @@ -13,7 +13,4 @@ pub(crate)use{anyhow::{Context,Error as E,anyhow as err,bail}}; #[macro_export] /**`unreachable!()`*/ macro_rules! ur {()=>{unreachable!()}} /**`Result`*/ pub type R = Result; #[cfg(test)]/**test prelude*/pub(crate) mod tp{ - pub(crate) use{assert_eq as eq,assert_ne as neq,assert as is,vec as v}; -} -// todo: extension trait for abbreviated `try_into`, `try_from` -// todo: extension trait for abbreviated `map`, `and_then`, `unwrap` + pub(crate) use{assert_eq as eq,assert_ne as neq,assert as is,vec as v}; } diff --git a/src/s.rs b/src/s.rs index 1cd0c58..ea382ba 100644 --- a/src/s.rs +++ b/src/s.rs @@ -9,12 +9,12 @@ use super::*; use std::ops::Not; let(sv)=|c:&char|c.is_ascii_lowercase()||c.is_ascii_digit()||*c=='_'; // validate if(sc.iter().all(sv).not()){bail!("symbols may only contain a-z, 0-9, or `_`")} Ok(SY(s.to_owned()))}} - #[test] fn simple_symbol_succeeds() {assert!(SY::from_str("abc") .is_ok())} - #[test] fn underscore_symbol_succeeds() {assert!(SY::from_str("abc_def").is_ok())} - #[test] fn trailing_number_symbol_succeeds(){assert!(SY::from_str("a1") .is_ok())} - #[test] fn empty_symbol_fails() {assert!(SY::from_str("") .is_err())} - #[test] fn number_symbol_fails() {assert!(SY::from_str("1") .is_err())} - #[test] fn leading_number_symbol_fails() {assert!(SY::from_str("1a") .is_err())} + #[test] fn simple_symbol_succeeds() {is!(SY::from_str("abc") .is_ok())} + #[test] fn underscore_symbol_succeeds() {is!(SY::from_str("abc_def").is_ok())} + #[test] fn trailing_number_symbol_succeeds(){is!(SY::from_str("a1") .is_ok())} + #[test] fn empty_symbol_fails() {is!(SY::from_str("") .is_err())} + #[test] fn number_symbol_fails() {is!(SY::from_str("1") .is_err())} + #[test] fn leading_number_symbol_fails() {is!(SY::from_str("1a") .is_err())} } impl ST{