diff --git a/include/noun/allocate.h b/include/noun/allocate.h index d2a8a55b66..8533158d99 100644 --- a/include/noun/allocate.h +++ b/include/noun/allocate.h @@ -256,6 +256,15 @@ ? u3a_north_is_senior(r, som) \ : u3a_south_is_senior(r, som) ) +# define u3a_is_mutable(r, som) \ + ( _(u3a_is_atom(som)) \ + ? c3n \ + : _(u3a_is_senior(r, som)) \ + ? c3n \ + : _(u3a_is_junior(r, som)) \ + ? c3n \ + : (u3a_botox(u3a_to_ptr(som))->use_w == 1) \ + ? c3y : c3n ) /** Globals. **/ diff --git a/include/noun/imprison.h b/include/noun/imprison.h index efda35fab3..f552c87f5e 100644 --- a/include/noun/imprison.h +++ b/include/noun/imprison.h @@ -55,6 +55,14 @@ u3_noun u3i_qual(u3_noun a, u3_noun b, u3_noun c, u3_noun d); + /* u3i_edit(): + ** + ** Mutate `big` at axis `axe` with new value `som` + ** `axe` is RETAINED. + */ + u3_noun + u3i_edit(u3_noun big, u3_noun axe, u3_noun som); + /* u3i_string(): ** ** Produce an LSB-first atom from the C string `a`. diff --git a/noun/imprison.c b/noun/imprison.c index c08e967f40..c0d16c3dc8 100644 --- a/noun/imprison.c +++ b/noun/imprison.c @@ -262,6 +262,150 @@ u3i_qual(u3_noun a, u3_noun b, u3_noun c, u3_noun d) return u3i_cell(a, u3i_trel(b, c, d)); } +static u3_noun +_edit_cat(u3_noun big, c3_l axe_l, u3_noun som) +{ + if ( c3n == u3du(big) ) { + return u3m_bail(c3__exit); + } + else { + u3_noun pro; + switch ( axe_l ) { + case 2: + pro = u3nc(som, u3k(u3t(big))); + break; + case 3: + pro = u3nc(u3k(u3h(big)), som); + break; + default: { + c3_l mor_l = u3x_mas(axe_l); + pro = ( 2 == u3x_cap(axe_l) ) + ? u3nc(_edit_cat(u3k(u3h(big)), mor_l, som), u3k(u3t(big))) + : u3nc(u3k(u3h(big)), _edit_cat(u3k(u3t(big)), mor_l, som)); + break; + } + } + u3z(big); + return pro; + } +} + +static u3_noun +_edit(u3_noun big, u3_noun axe, u3_noun som) +{ + if ( c3y == u3a_is_cat(axe) ) { + return _edit_cat(big, (c3_l) axe, som); + } + else if ( c3n == u3du(big) ) { + return u3m_bail(c3__exit); + } + else { + u3_noun mor = u3qc_mas(axe), + pro = ( 2 == u3qc_cap(axe) ) + ? u3nc(_edit(u3k(u3h(big)), mor, som), u3k(u3t(big))) + : u3nc(u3k(u3h(big)), _edit(u3k(u3t(big)), mor, som)); + u3z(mor); + u3z(big); + return pro; + } +} + +static u3_noun _edit_or_mutate_cat(u3_noun, c3_l, u3_noun); +static u3_noun _edit_or_mutate(u3_noun, u3_noun, u3_noun); + +static void +_mutate_cat(u3_noun big, c3_l axe_l, u3_noun som) +{ + if ( c3n == u3du(big) ) { + u3m_bail(c3__exit); + } + else { + u3a_cell* cel_u = (void*) u3a_to_ptr(big); + switch ( axe_l ) { + case 2: + u3z(cel_u->hed); + cel_u->hed = som; + break; + case 3: + u3z(cel_u->tel); + cel_u->tel = som; + break; + default: { + u3_noun* tar = ( 2 == u3x_cap(axe_l) ) + ? &(cel_u->hed) + : &(cel_u->tel); + *tar = _edit_or_mutate_cat(*tar, u3x_mas(axe_l), som); + } + } + } +} + +static void +_mutate(u3_noun big, u3_noun axe, u3_noun som) +{ + if ( c3y == u3a_is_cat(axe) ) { + _mutate_cat(big, (c3_l) axe, som); + } + else if ( c3n == u3du(big) ) { + u3m_bail(c3__exit); + } + else { + u3a_cell* cel_u = (void*) u3a_to_ptr(big); + u3_noun mor = u3qc_mas(axe); + u3_noun* tar = ( 2 == u3qc_cap(axe) ) + ? &(cel_u->hed) + : &(cel_u->tel); + *tar = _edit_or_mutate(*tar, mor, som); + u3z(mor); + } +} + +static u3_noun +_edit_or_mutate_cat(u3_noun big, c3_l axe_l, u3_noun som) +{ + if ( c3y == u3a_is_mutable(u3R, big) ) { + _mutate_cat(big, axe_l, som); + return big; + } + else { + return _edit_cat(big, axe_l, som); + } +} + +static u3_noun +_edit_or_mutate(u3_noun big, u3_noun axe, u3_noun som) +{ + if ( c3y == u3a_is_cat(axe) ) { + return _edit_or_mutate_cat(big, (c3_l) axe, som); + } + else if ( c3y == u3a_is_mutable(u3R, big) ) { + _mutate(big, axe, som); + return big; + } + else { + return _edit(big, axe, som); + } +} + +/* u3i_edit(): +** +** Mutate `big` at axis `axe` with new value `som`. +** `axe` is RETAINED. +*/ +u3_noun +u3i_edit(u3_noun big, u3_noun axe, u3_noun som) +{ + switch ( axe ) { + case 0: + return u3m_bail(c3__exit); + case 1: + u3z(big); + return som; + default: + return _edit_or_mutate(big, axe, som); + } +} + /* u3i_string(): ** ** Produce an LSB-first atom from the C string `a`. diff --git a/noun/nock.c b/noun/nock.c index 1ac6de74f9..2150ae223e 100644 --- a/noun/nock.c +++ b/noun/nock.c @@ -1591,30 +1591,6 @@ _n_kale(u3_noun a) return a; } - -/* _n_edit(): PRODUCE a modified big with its axe axis - * changed to som. axe is RETAINED. - */ -static u3_noun -_n_edit(u3_noun big, u3_noun axe, u3_noun som) -{ - if ( c3y == u3a_is_cat(axe) ) { - return u3i_molt(big, axe, som, 0); - } - else { - u3_noun mor = u3qc_mas(axe); - if ( c3n == u3du(big) ) { - u3m_bail(c3__exit); - } - u3_noun pro = ( 2 == u3qc_cap(axe) ) - ? u3nc(_n_edit(u3k(u3h(big)), mor, som), u3k(u3t(big))) - : u3nc(u3k(u3h(big)), _n_edit(u3k(u3t(big)), mor, som)); - u3z(mor); - u3z(big); - return pro; - } -} - typedef struct { u3n_prog* pog_u; c3_w ip_w; @@ -2325,7 +2301,7 @@ _n_burn(u3n_prog* pog_u, u3_noun bus, c3_ys mov, c3_ys off) _n_toss(mov, off); top = _n_peek(off); edit_in: - *top = _n_edit(*top, x, o); + *top = u3i_edit(*top, x, o); BURN(); } }