On this page:

8 Reading code

So far, all test programs have been fed pre-parsed code in a list. To read code (or data, it’s all the same) from a file, we can use port-read-value (defined in Ports). However, the interpreter doesn’t know how to do that, so we need a way of using it when the program expects to read more code.

So here it is. This read-eval loop checks quote-read-syntax? to read code from source-input-port, and basically reimplements the core interpreter loop. If you wanted, you could redefine source-input-port to read from a different file or syntax-read to change the character-level syntax.

; Add definitions to support a read-eval-loop from the given input port.
(: read-eval-loop-definitions
   (-> (Immutable-HashTable Symbol Function) Input-Port
       (Immutable-HashTable Symbol Function)))
(define (read-eval-loop-definitions builtins source-input-port)
    'source-input-port `(,source-input-port)
    'syntax-read '(; read a value from the current source file
                   source-input-port port-read-value swap drop)
    'quote-read-syntax? '(; This could be consolidated
                          builtin-quote current-context-root? uplevel)
    ; Override quote to read from the source input file
    ; at the toplevel
    'builtin-quote (hash-ref (*builtins*) 'quote)
    'quote '(builtin-quote builtin-quote
                           builtin-quote syntax-read
                           builtin-quote quote-read-syntax? uplevel
                           builtin-quote swap when drop uplevel)
    'read-eval-loop '(; Loop
                      ; Read next value
                      quote quote uplevel
                      ; Leave <eof> here (this is a little wonky)
                      eof-object? quote current-context-clear when
                      ; Eval symbols; leave everything else on stack
                      ; Stack dance to get everything in place
                      quote call swap
                      quote drop swap
                      quote uplevel swap
                      ; 'eval 'drop 'uplevel #t 'swap when drop
                      ; => 'eval 'uplevel
                      ; 'eval 'drop 'uplevel #f 'swap when drop
                      ; => 'eval 'drop
                      quote swap when drop
                      ; Loop!