Skip to content

Commit 214ec8d

Browse files
authored
Merge pull request #13 from cratelyn/lints
πŸ’ final pass, address lints and polish formatting
2 parents 8c53847 + cb4a07a commit 214ec8d

File tree

6 files changed

+50
-48
lines changed

6 files changed

+50
-48
lines changed

β€ŽREADME.md

+16
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,22 @@ voice feels like, and why people do it.
139139

140140
#### 🐣 j
141141

142+
**πŸ” main loop**
143+
144+
above we looked at the Incunabulum's main event loop. here is j's equivalent entrypoint:
145+
146+
```rust
147+
mod p;use{p::*,j::*,std::io::Write};
148+
fn main()->R<()>{let mut st=ST::default(); // define symbol table
149+
let prompt =| |{print!(" ");std::io::stdout().flush()?;ok!()}; // (callback) print whitespace
150+
let read =|_ |{let mut l=S::new();stdin().read_line(&mut l)?;Ok(l)}; // (callback) read input
151+
let mut eval=|s:S|{eval(&s,&mut st)}; // (callback) read and evaluate once
152+
let print =|a:A|{println!("{a}")}; // (callback) print array
153+
loop{prompt().and_then(read).and_then(&mut eval)?.map(print);}; /* !!! main event loop !!! */ }
154+
```
155+
156+
**πŸƒ verbs**
157+
142158
the core of the four dyadic verbs `[`, `]`, `+`, and `*` is shown below. the definitions of the `A`
143159
array type and the `D` dyadic verb enum are included for reference.
144160

β€Žsrc/a.rs

+13-15
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ use super::*; use std::marker::PhantomData as PD;
1515
fn oob(&self,i:U,j:U)->R<()>{let A{m,n,..}=*self;
1616
if(i==0||j==0||i>m||j>n){bail!("({i},{j}) is out-of-bounds of ({m},{n})")}ok!()}
1717
/// returns the scalar `A_ij` within this array. returns an error if position is out-of-bounds.
18-
pub fn index(&self,i:U,j:U)->R<U> {self.oob(i,j)?;let A{m,n,..}=*self;let(i,j)=(i-1,j-1);Ok((i*n)+j)}
18+
pub fn index(&self,i:U,j:U)->R<U> {self.oob(i,j)?;let(i,j)=(i-1,j-1);Ok((i*self.n)+j)}
1919
/// returns the scalar `A_ij` within this array. does not check if the position is in bounds.
20-
pub fn index_uc(&self,i:U,j:U)->R<U>{ let A{m,n,..}=*self;let(i,j)=(i-1,j-1);Ok((i*n)+j)}
20+
pub fn index_uc(&self,i:U,j:U)->R<U>{ let(i,j)=(i-1,j-1);Ok((i*self.n)+j)}
2121
}
2222
// === test helpers ===
2323
/// `A::index` test case generator. check that indexing at a position returns the expected value.
@@ -27,17 +27,17 @@ use super::*; use std::marker::PhantomData as PD;
2727
#[macro_export] macro_rules! toob{($f:ident,$a:ident,$i:literal,$j:literal)=>
2828
{#[test] fn $f()->R<()>{is!($a()?.index($i,$j).is_err());ok!()}}}
2929
// === 1x1 array indexing ===
30-
fn sca()->R<A>{let Ok(a@A{m:1,n:1,..})=A::from_i(42)else{bail!("bad dims")};Ok(a)}
30+
#[cfg(test)] fn sca()->R<A>{let Ok(a@A{m:1,n:1,..})=A::from_i(42)else{bail!("bad dims")};Ok(a)}
3131
toob!(i00_for_scalar,sca,0,0);toob!(i10_for_scalar,sca,1,0);toob!(i01_for_scalar,sca,0,1);
3232
toob!(i21_for_scalar,sca,2,1);toob!(i12_for_scalar,sca,1,2);toob!(i22_for_scalar,sca,2,2);
3333
ti!(i11_for_scalar,sca,1,1,0);
3434
// === 2x3 array indexing ===
35-
fn arr2x3()->R<A>{let Ok(a@A{m:2,n:3,..})=A::zeroed(2,3)else{bail!("bad dims")};Ok(a)}
35+
#[cfg(test)] fn arr2x3()->R<A>{let Ok(a@A{m:2,n:3,..})=A::zeroed(2,3)else{bail!("bad dims")};Ok(a)}
3636
toob!(i00_for_2x3,arr2x3,0,0);toob!(i01_for_2x3,arr2x3,0,1);toob!(i10_for_2x3,arr2x3,1,0);
3737
ti!(i11_for_2x3,arr2x3,1,1,0);ti!(i12_for_2x3,arr2x3,1,2,1);ti!(i13_for_2x3,arr2x3,1,3,2);
3838
ti!(i21_for_2x3,arr2x3,2,1,3);ti!(i22_for_2x3,arr2x3,2,2,4);ti!(i23_for_2x3,arr2x3,2,3,5);
3939
// === 3x3 array indexing ===
40-
fn arr3x3()->R<A>{let Ok(a@A{m:3,n:3,..})=A::zeroed(3,3)else{bail!("bad dims")};Ok(a)}
40+
#[cfg(test)] fn arr3x3()->R<A>{let Ok(a@A{m:3,n:3,..})=A::zeroed(3,3)else{bail!("bad dims")};Ok(a)}
4141
toob!(i00_for_3x3,arr3x3,0,0);toob!(i01_for_3x3,arr3x3,0,1);toob!(i14_for_3x3,arr3x3,1,4);
4242
toob!(i41_for_3x3,arr3x3,4,1);toob!(i44_for_3x3,arr3x3,4,4);
4343
ti!(i11_for_3x3,arr3x3,1,1,0);ti!(i21_for_3x3,arr3x3,2,1,3);ti!(i22_for_3x3,arr3x3,2,2,4);
@@ -111,8 +111,7 @@ use super::*; use std::marker::PhantomData as PD;
111111
impl A<MI>{ // only allow matrix access for initialized arrays
112112
pub fn into_matrix(&self)->R<Vec<&[I]>>{let(A{m,n,..})=*self;
113113
(0..m).map(|m|{self.ptr_at(m+1,1)}).map(|r|r.map(|d|unsafe{from_raw_parts(d as *mut I, n as U)})).collect()}}
114-
impl TF<&[&[I]]> for A{type Error=E;fn try_from(s:&[&[I]])->R<A>{todo!("TF<&[I]> for A")}}
115-
impl PE<&[&[I]]> for A{fn eq(&self,r:&&[&[I]])->bool{let(A{m,n,..})=self;
114+
impl PE<&[&[I]]> for A{fn eq(&self,r:&&[&[I]])->bool{
116115
if(r.len()!=self.m){r!(false)}for(i,r_i)in(r.into_iter().enumerate()){
117116
if(r_i.len()!=self.n){r!(false)}for(j,r_ij)in(r_i.into_iter().enumerate()){
118117
let(i,j)=(i+1,j+1);let(a_ij)=match(self.get(i,j)){Ok(v)=>v,Err(_)=>r!(false)};
@@ -121,7 +120,7 @@ use super::*; use std::marker::PhantomData as PD;
121120
/**monadic verbs*/impl A{
122121
pub fn m_same(self)->R<A>{Ok(self)}
123122
pub fn m_idot(self)->R<A>{let(a@A{m,n,..})=self;let gi=|i,j|a.get(i,j)?.try_into().map_err(E::from);
124-
if let(1,1)=(m,n){let(m,n)=(1,gi(1,1)?);let(mut o)=A::new(1,n)?;
123+
if let(1,1)=(m,n){let(n)=(gi(1,1)?);let(mut o)=A::new(1,n)?;
125124
for(j)in(1..=n){o.set(1,j,(j-1).try_into()?)?;}Ok(unsafe{o.finish()})}
126125
else if let(1,2)=(m,n){let(m,n)=(gi(1,1)?,gi(1,2)?);
127126
let(mut v)=0_u32;let(f)=move |_,_|{let(v_o)=v;v+=1;Ok(v_o)};A::new(m,n)?.init_with(f)}
@@ -136,9 +135,9 @@ use super::*; use std::marker::PhantomData as PD;
136135
/*return dyad function**/ pub fn f(&self)->fn(I,I)->I{use D::*;
137136
match(self){Plus=>D::add, Mul=>D::mul, Left=>D::left, Right=>D::right} }
138137
/*add two numbers*/fn add (x:I,y:I)->I{x+y} /*multiply two numbers*/fn mul (x:I,y:I)->I{x*y}
139-
/*left */fn left(x:I,y:I)->I{x } /*right */fn right(x:I,y:I)->I{ y}
138+
/*left */fn left(x:I,_:I)->I{x } /*right */fn right(_:I,y:I)->I{ y}
140139
} impl A{
141-
pub fn d_left (self,r:A)->R<A>{Ok(self) }
140+
pub fn d_left (self,_:A)->R<A>{Ok(self) }
142141
pub fn d_right(self,r:A)->R<A>{Ok(r) }
143142
pub fn d_plus(self,r:A) ->R<A>{A::d_do(self,r,D::add)}
144143
pub fn d_mul (self,r:A) ->R<A>{A::d_do(self,r,D::mul)}
@@ -171,7 +170,7 @@ use super::*; use std::marker::PhantomData as PD;
171170
// === monadic `/`, `Ym::Insert` tests
172171
macro_rules! test_insert{($f:ident,$d:expr,$a:expr,$o:expr)=>
173172
{#[test]fn $f()->R<()>{let(a):R<A>={$a};let(d):D={$d}; // typecheck macro arguments.
174-
let i:I=a.and_then(|a:A|Ym::insert($d,a)).and_then(|a|a.as_i())?;
173+
let i:I=a.and_then(|a:A|Ym::insert(d,a)).and_then(|a|a.as_i())?;
175174
eq!(i,$o);ok!()}}}
176175
test_insert!(add_a_scalar, D::Plus, A::from_i(42), 42 );
177176
test_insert!(add_a_sequence, D::Plus, <A as TF<&[I]>>::try_from(&[1,2,3,4,5]), (1+2+3+4+5) );
@@ -188,15 +187,14 @@ use super::*; use std::marker::PhantomData as PD;
188187
let f=|i,j|->R<I>{let(x,y)=(l[i-1],r[j-1]);Ok(d(x,y))};
189188
A::new(m,n)?.init_with(f)}
190189
else {bail!("unexpected fallthrough in Yd::table")}}
191-
fn infix(d:D,l:A,r:A)->R<A>{let(s)=r.as_slice().map_err(|_|err!("infix rhs must be a slice"))?;
190+
fn infix(_:D,l:A,r:A)->R<A>{let(s)=r.as_slice().map_err(|_|err!("infix rhs must be a slice"))?;
192191
let(il)=l.as_i() .map_err(|_|err!("infix lhs must be a scalar"))?.try_into()?;
193192
let(ic)=(s.len()-il)+1;
194193
A::new(ic,il)?.init_with(|i,j|Ok(s[(i-1)+(j-1)]))}}}
195194

196-
/**deep-copy*/impl A<MI>{
197-
pub fn deep_copy(&self)->R<A>{let A{m,n,l:li,d:di,i:_}=*self;A::new(m,n)?.init_with(|i,j|{self.get(i,j)})}}
195+
/**deep-copy*/impl A<MI>{pub fn deep_copy(&self)->R<A>{A::new(self.m,self.n)?.init_with(|i,j|{self.get(i,j)})}}
198196

199197
/**display*/mod fmt{use super::*;
200198
impl DS for A<MI>{
201-
fn fmt(&self,fmt:&mut FMT)->FR{let A{m,n,..}=*self;for(i,j)in(self.iter())
199+
fn fmt(&self,fmt:&mut FMT)->FR{let A{n,..}=*self;for(i,j)in(self.iter())
202200
{let(x)=self.get_uc(i,j).map_err(|_|std::fmt::Error)?;write!(fmt,"{x}{}",if(j==n){'\n'}else{' '})?;}ok!()}}}

β€Žsrc/j.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
#![allow(dead_code,unused_variables,unreachable_code,unused_imports,unused_parens)]
2-
/**prelude*/mod p;use p::*;#[cfg(test)]use p::tp::*;
3-
/**array*/mod a; /**read input*/mod r; /**symbol table*/mod s;
4-
pub use self::{a::*,r::*,s::*};
1+
#![allow(unused_parens)] /**prelude*/mod p;use p::*; /*test prelude*/#[cfg(test)]use p::tp::*;
2+
/**symbol table*/mod s; /**array*/ mod a; /**lex/parse input*/mod r;use r::*;
3+
pub use self::{a::*,s::*};
54
pub fn eval(input:&str,st:&mut ST)->R<O<A>>{
65
let(mut ts)=lex(input)?;let(ast)=match(parse(&mut ts)?){Some(x)=>x,None=>rrn!()};eval_(ast,st)}
76
fn eval_(ast:B<N>,st:&mut ST)->R<O<A>>{use{M::*,D::*};

β€Žsrc/p.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! prelude; shorthand aliases for common types and traits, macros for common patterns.
1+
#![allow(unused_imports)] //! prelude; shorthand aliases for common types and traits, macros for common patterns.
22
pub(crate)use{Box as B,char as C,u32 as I,usize as U,Option as O,String as S,TryFrom as TF,TryInto as TI,Vec as V};
33
pub(crate)use{std::{alloc::Layout as L,clone::Clone as CL,cmp::{PartialEq as PE,PartialOrd as PO},
44
collections::{BTreeMap as BM,VecDeque as VD},fmt::{Debug as DBG,Display as DS,Formatter as FMT,Result as FR},

β€Žsrc/r.rs

+8-22
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ mod lex{use crate::*;
44
/*assignment*/ E ,
55
/* NB: this does not identify whether possible verbs */ /*(ad)verb*/ V(S) ,
66
/* are monadic or dyadic. that is done during parsing.*/ /*symbol*/ SY(SY) }
7-
impl T{pub(super) fn is_noun(&self)->bool{use T::*;matches!(self,A(_)|SY(_))}}
8-
pub(crate) fn lex(input:&str)->R<V<T>>{use std::ops::Deref;
7+
pub(crate) fn lex(input:&str)->R<V<T>>{
98
let(mut ts)=input.split_whitespace().peekable(); let(mut o)=V::with_capacity(ts.size_hint().0);
109
while let Some(t) =ts.next(){
1110
if t == "=:" {o.push(T::E)} // assignment
@@ -16,7 +15,7 @@ mod lex{use crate::*;
1615
while let Some(i)=peek!(){put!(i);} o.push(T::A(v));}
1716
else {o.push(T::V(S::from(t)))} // otherwise, a verb or adverb
1817
} r!(Ok(o)) }
19-
#[cfg(test)]mod t{use super::{*,T::A as TA,T::V as TV,T::SY as TSY};
18+
#[cfg(test)]mod t{use super::{*,T::A as TA,T::V as TV};
2019
/// test helper: lex an expression and check the output
2120
macro_rules! t{($f:ident,$i:literal,$o:expr)=>{#[test]fn $f()->R<()>{eq!(lex($i)?,$o);ok!()}}}
2221
macro_rules! sy{($i:literal)=>{$i.parse().map(T::SY).unwrap()}}
@@ -31,7 +30,7 @@ mod lex{use crate::*;
3130
t!(lex_symbol, "abc", v![sy!("abc")] );
3231
t!(lex_assign, "a =: 1", v![sy!("a"), T::E, TA(v![1])] );
3332
}
34-
}/**input parsing*/mod parse{use {crate::*,super::lex::{T,lex}};
33+
}/**input parsing*/mod parse{use {crate::*,super::lex::T};
3534
/**dyadic verb */ #[derive(DBG,PE,PO)] pub enum D {Plus,Mul, Left, Right }
3635
/**monadic verb */ #[derive(DBG,PE,PO)] pub enum M {Idot,Shape,Tally,Transpose,Same,Inc}
3736
/**dyadic adverb */ #[derive(DBG )] pub enum Yd{/**dyadic `/` */ Table ,
@@ -55,7 +54,6 @@ mod lex{use crate::*;
5554
fn parse_(ts:&mut V<T>,ctx:&mut V<B<N>>)->R<()>{
5655
// push a new AST node onto the `ctx` stack and return, indicating a successful parsing "step."
5756
macro_rules! step{($n:expr)=>{ctx.push(b!($n));r!(ok!());}}
58-
5957
let(v):S=match ts.pop(){
6058
Some(T::V(v)) =>v, /*take the next verb, or return if done*/ None=>r!(ok!()),
6159
Some(T::A(v)) =>{let(n)=v.try_into()?;step!(n);} // array literal
@@ -71,7 +69,6 @@ mod lex{use crate::*;
7169
/*first, process monadic and dyadic verbs*/
7270
if let Some(l)=lhs{let(d)=D::new(&v).ok_or(err!("invalid dyad {v:?}"))?;step!(N::D{l,r:rhs,d});}
7371
else if let Some(m)=M::new(&v){step!(N::M{m,o:rhs});}
74-
7572
/*otherwise, we should treat this as an adverb*/
7673
let(y)=v;let(d)=ts.pop().ok_or(err!("adverbs need a verb to apply"))?;
7774
macro_rules! ym {()=>{
@@ -88,20 +85,7 @@ mod lex{use crate::*;
8885
/*monadic adverb*/ /*dyadic adverb */
8986
None =>{ ym!();} Some(T::A(v)) =>{let(l)=b!(v.try_into()?);yd!(l);}
9087
Some(t@T::E|t@T::V(_))=>{ts.push(t);ym!();} Some(T::SY(sy))=>{let(l)=b!(sy.into()); yd!(l);}
91-
}
92-
bail!("fallthrough: unexpected parsing error");
93-
}
94-
/**get a tuple, representing a window peeking on the next two elements in this token stream.*/
95-
fn lhs_window(ts:&[T])->(O<&T>,O<&T>){match ts{
96-
[]=>(None,None), [a]=>(None,Some(&a)), [a,b]=>(Some(&a),Some(&b)), [..,a,b]=>(Some(&a),Some(&b)) } }
97-
#[cfg(test)]mod lhs_t{use super::*;
98-
#[test] fn lhs_window_works_on_empty(){is!(matches!(lhs_window(&[]), (None, None))) }
99-
#[test] fn lhs_window_works_on_one (){is!(matches!(lhs_window(&[T::E]), (None, Some(_)))) }
100-
#[test] fn lhs_window_works_on_two (){is!(matches!(lhs_window(&[T::E,T::A(v![])]),(Some(T::E),Some(T::A(_)))))}
101-
#[test] fn lhs_window_works_on_three(){
102-
is!(matches!(lhs_window(&[T::E,T::A(v![]),T::V(S::from("+"))]),(Some(T::A(_)),Some(_))))}
103-
}
104-
88+
}}
10589
impl M {fn new(s:&str)->O<M> {use M::*; Some(match s{"i."=>Idot ,"$" =>Shape ,"|:"=>Transpose ,
10690
"#" =>Tally ,"[" =>Same ,"]" =>Same ,
10791
">:"=>Inc, _=>r!(None)})}}
@@ -110,8 +94,10 @@ mod lex{use crate::*;
11094
impl Ym{fn new(s:&str)->O<Ym>{use Ym::*;Some(match s{"/" =>Insert,"\\"=>Prefix, _=>r!(None)})}}
11195
impl Yd{fn new(s:&str)->O<Yd>{use Yd::*;Some(match s{"/" =>Table ,"\\"=>Infix , _=>r!(None)})}}
11296
#[cfg(test)]mod t{use super::*;
113-
macro_rules! t{($f:ident,$i:literal)=>{#[test]fn $f()->R<()>{let(mut ts)=lex($i)?;let ast=parse(&mut ts)?;ok!()}}}
114-
macro_rules! tf{($f:ident,$i:literal)=>{#[test] #[should_panic]fn $f(){let(mut ts)=lex($i).unwrap();let ast=parse(&mut ts).unwrap();}}}
97+
macro_rules! t {($f:ident,$i:literal)=>{
98+
#[test] fn $f()->R<()>{let(mut ts)=lex($i)?; let _=parse(&mut ts)?;ok!()}}}
99+
macro_rules! tf{($f:ident,$i:literal)=>{
100+
#[test] #[should_panic]fn $f() {let(mut ts)=lex($i).unwrap();let _=parse(&mut ts).unwrap();}}}
115101
/*parsing unit tests; t!(..) asserts a success, while tf asserts a failure.*/
116102
t!(parse_1x1,"1"); t!(parse_1x3,"1 2 3");
117103
t!(parse_tally_1,"# 1"); t!(parse_tally_1x3,"# 1 2 3");

β€Žsrc/x.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
//! a J interpreter fragment, implemented in Rust.
2-
#![allow(dead_code,unused_variables,unreachable_code,unused_imports,unused_parens)]
3-
mod p; use{p::*,j::*}; fn main()->R<()>{use std::io::Write;let(mut st)=ST::default();
4-
let(pr)=||{print!(" ");std::io::stdout().flush()};
5-
let(rl)=||{let(mut l)=S::new();stdin().read_line(&mut l)?;Ok::<_,E>(l)};let(mut ev)=|l:S|eval(&l,&mut st);
6-
loop{pr()?;let(o)=rl().and_then(|l|ev(l))?;if let Some(o)=o{println!("{}",o)}}ur!();}
1+
/**a J interpreter fragment, implemented in Rust.*/
2+
mod p;use{p::*,j::*,std::io::Write};
3+
/// main interpreter entrypoint and event-loop.
4+
fn main()->R<()>{let mut st=ST::default(); // define symbol table
5+
let prompt =| |{print!(" ");std::io::stdout().flush()?;ok!()}; // (callback) print whitespace
6+
let read =|_ |{let mut l=S::new();stdin().read_line(&mut l)?;Ok(l)}; // (callback) read input
7+
let mut eval=|s:S|{eval(&s,&mut st)}; // (callback) read and evaluate once
8+
let print =|a:A|{println!("{a}")}; // (callback) print array
9+
loop{prompt().and_then(read).and_then(&mut eval)?.map(print);}; /* !!! main event loop !!! */ }

0 commit comments

Comments
Β (0)