@@ -186,21 +186,54 @@ pub(crate) struct RcBlock {
186186 pub ( crate ) words : Vec < ( Span , Unsigned36Bit ) > ,
187187}
188188
189- impl RcAllocator for RcBlock {
190- fn allocate ( & mut self , span : Span , value : Unsigned36Bit ) -> Address {
189+ impl RcBlock {
190+ fn end ( & self ) -> Address {
191191 match Unsigned18Bit :: try_from ( self . words . len ( ) ) {
192- Ok ( offset) => {
193- let addr = self . address . index_by ( offset) ;
194- self . words . push ( ( span, value) ) ;
195- addr
196- }
192+ Ok ( offset) => self . address . index_by ( offset) ,
197193 Err ( _) => {
198194 panic ! ( "program is too large" ) ; // TODO: fixme: use Result
199195 }
200196 }
201197 }
202198}
203199
200+ impl RcAllocator for RcBlock {
201+ fn allocate ( & mut self , span : Span , value : Unsigned36Bit ) -> Address {
202+ let addr = self . end ( ) ;
203+ self . words . push ( ( span, value) ) ;
204+ addr
205+ }
206+
207+ fn update ( & mut self , address : Address , value : Unsigned36Bit ) {
208+ if address < self . address {
209+ panic ! (
210+ "out of range access to address {address} of RC-block starting at {}" ,
211+ self . address
212+ ) ;
213+ }
214+ match Unsigned18Bit :: from ( address) . checked_sub ( Unsigned18Bit :: from ( self . address ) ) {
215+ Some ( offset) => match self . words . get_mut ( usize:: from ( offset) ) {
216+ Some ( ( _span, spot) ) => {
217+ * spot = value;
218+ }
219+ None => {
220+ panic ! (
221+ "out of range access to address {address} of RC-block ending at {}" ,
222+ self . end( )
223+ ) ;
224+ }
225+ } ,
226+ None => {
227+ // The checks above should ensure that address >= self.address.
228+ panic ! (
229+ "inconsistent checks; {address:o} should be greater than {:o}" ,
230+ self . address
231+ ) ;
232+ }
233+ }
234+ }
235+ }
236+
204237#[ cfg( test) ]
205238pub ( crate ) fn make_empty_rc_block_for_test ( location : Address ) -> RcBlock {
206239 RcBlock {
@@ -427,15 +460,27 @@ impl Evaluate for Atom {
427460 ) ,
428461 Atom :: Parens ( _script, expr) => expr. evaluate ( target_address, symtab, rc_allocator, op) ,
429462 Atom :: RcRef ( span, tagged_program_instructions) => {
430- let value: Unsigned36Bit = evaluate_and_combine_values (
431- tagged_program_instructions,
432- target_address,
433- symtab,
434- rc_allocator,
435- op,
436- ) ?;
437- let addr: Address = rc_allocator. allocate ( * span, value) ;
438- Ok ( addr. into ( ) )
463+ let mut first_addr: Option < Address > = None ;
464+ for inst in tagged_program_instructions. iter ( ) {
465+ let rc_word_addr: Address = rc_allocator. allocate ( * span, Unsigned36Bit :: ZERO ) ;
466+ if first_addr. is_none ( ) {
467+ first_addr = Some ( rc_word_addr) ;
468+ }
469+ // Within the RC-word, # ("here") resolves to the
470+ // address of the RC-word itself. So before we
471+ // evaluate the value to be placed in the RC-word,
472+ // we need to know the value that # will take
473+ // during the evaluation process.
474+ let here = HereValue :: Address ( rc_word_addr) ;
475+ let value: Unsigned36Bit = inst. evaluate ( & here, symtab, rc_allocator, op) ?;
476+ rc_allocator. update ( rc_word_addr, value) ;
477+ }
478+ match first_addr {
479+ Some ( addr) => Ok ( addr. into ( ) ) ,
480+ None => {
481+ unreachable ! ( "RC-references should not occupy zero words of storage" ) ;
482+ }
483+ }
439484 }
440485 }
441486 }
0 commit comments