This blog is written in Retro and has served as my primary means of posting things concerning Retro since 2010. The core code for Corpse is included in the Retro releases and can be freely studied and deployed.

The most recent posts are shown below. You can also view a list of all posts.

Post 188 of 223


On the Implementation of Quotes

Quotations (Retro's terminology for anonymous, nestable functions) form a significant part of the Retro language. This post explores their current implementation and alternative approaches.

  : foo 1 [ 2 ] dip ;

This compiles down to:

  000  label: foo
  001  LIT
  002  1
  004  8
  005  LIT
  006  2
  007  RETURN
  008  CALL DIP
  009  RETURN
  010  RETURN

Quotes are handled by a function named quote. This is defined in the initial kernel:

  t: quote ( -a  )  pop, 1+, dup, @, 1-, push, 1+, ;

Or, in slightly cleaner higher-level Retro:

  : quote ( -a  )  pop 1+ dup @ 1- push 1+ ;

The cell following the call to quote contains the address of the cell following the end of the quote. When quote is invoked, it looks up this cell, replacing the return address with this to skip over the quote. It also leaves a pointer to the first cell in the quote on the stack.

A quote is created by [ and ends with ]. Looking at these:

  t: [ ( -af )  ' quote # , here 0 # , compiler # @, compiler # on ;
  t: ] ( fa- )  ;; compiler # !, here over !,
                    compiler # @, 0 # =if 1+, ; then drop, ;

Again, cleaning it up:

  : [  ( -af )  "e , here 0 , @compiler compiler on ; immediate
  : ]  ( af- )  ` ;; !compiler here over ! @compiler [ 1+ ] [ drop ] if ; immediate

[ lays down a call to quote, pushes the address of the following cell to the data stack and then lays down a dummy value. It then pushes the current compiler flag value to the stack and turns compiler on.

] lays down a return instruction using ;;, then restores compiler to the prior status. It then patches the address following the call to quote. Finally, if the compiler is now off, it leaves the address of the quote on the stack. Otherwise it discards it.

The pushing/restoring of the compiler state allows the quotes to be created at the interpreter or inside other function definitions.

To clarify the behavior at the listener level: [ acts the same way as it does in a definition. The only difference is that compiler is off at this point, so the flag pushed to the stack is 0. After this, compiler is turned on. ] will patch the destination address, and set compiler back to the flag value on the stack (which is off in this case).

View comments for this article