The reference interpreter was intended to have eager evaluation, but due to its implementation in Haskell, some parts have lazy evaluation. The language tutorial states that the operational semantics are defined by that implementation, in lieu of a formal specification. A maximally compliant implementation can consider this lazy behavior to be standard, although all known implementations so far, except for lazy-wspace use the obvious strict semantics.
Whitespace’s lazy semantics are difficult to reason about, as execution interleaves instruction effects, with exceptions potentially occurring long in the program execution from the originating instruction. This document codifies those semantics.
push n
: lazy literal parse n
; eager push n
dup
: eager pop n
; eager push n
and n
copy n
: lazy literal parse n
; lazy copy from n
; eager push stack!!n
swap
: eager pop n
and m
; eager push m
and n
drop
: eager pop n
slide n
: eager pop n
; lazy literal parse n
; lazy drop by n
add
: eager pop y
and x
; lazy add on x
and y
; eager pushsub
: eager pop y
and x
; lazy sub on x
and y
; eager pushmul
: eager pop y
and x
; lazy mul on x
and y
; eager pushdiv
: eager pop y
and x
; lazy div on x
and y
; eager pushmod
: eager pop y
and x
; lazy mod on x
and y
; eager pushstore
: eager pop n
and loc
; eager evaluate loc
;
eager store n
to loc
retrieve
: eager pop loc
; lazy evaluate loc
; lazy retrieve from loc
;
eager push heap!!(fromInteger loc)
label l
; skipcall l
: eager program parse until label l
; eager push pc
to call stack;
eager jumpjmp l
: eager program parse until label l
; eager jumpjz l
: eager pop n
; eager evaluate n
;
if n is zero, eager program parse until label l
and eager jumpjn l
: eager pop n
; eager evaluate n
;
if n is negative, eager program parse until label l
and eager jumpret
: eager call stack pop cs
; eager jump to cs
end
: eager exitprintc
: eager pop n
; eager evaluate n
; eager char validate n
printi
: eager pop n
; eager evaluate n
readc
: eager pop loc
; eager parse next input char as ch
;
eager evaluate loc
; eager store ch
at loc
readi
: eager pop loc
; eager parse next input line as ch
;
eager evaluate loc
; eager store ch
at loc
; lazy number parse ch
pc
(it may be a findLabel l prog
expression)pc
end
: terminate executiondup
, drop
, slide
, retrieve
, jz
, jn
, printc
, printi
,
readc
, readi
: evaluate stack
to length 1, then pop 1 value x
or
panic with underflowswap
, add
, sub
, mul
, div
, mod
, store
: evaluate stack
to
length 2, then pop 2 values y
and x
or panic with underflowret
: pop 1 value pc2
from the call stack or panicslide n
: set stack
to drop ((parseNumber n) :: Int) stack
stack
that will be droppedstack
, panic if n
is an empty list (has no sign)store
, jz
, jn
, printc
, printi
: evaluate x
push n
: push parseNumber n
n
is an empty list (has no sign)dup
: push x
, x
copy n
: push stack!!((parseNumber n) :: Int)
stack
, so can
cause space leaksn
and let i = (parseNumber n) :: Int
or panic if n
is an
empty list (has no sign)stack
up to length i
i < 0
or i >= length stack
swap
: push y
and x
slide
: push x
add
: push x + y
y
, then evaluate x
sub
: push x - y
y
, then evaluate x
mul
: push x * y
x
, then evaluate y
div
: push x `div` y
y
, then panic if y
is 0
, then evaluate x
mod
: push x `mod` y
y
, then panic if y
is 0
, then evaluate x
retrieve
: push heap!!(fromInteger x)
heap
, so can
cause space leaksx
, then panic if fromInteger x < 0
or
fromInteger x >= length heap
call
: push pc
to the call stackreadc
: read the next character from stdin as ch
or panic on IO errorreadi
: read the next line from stdin as ch
or panic on IO errorstore
: store y
at index fromInteger x
in heap
heap
to a shallow copy of the first (fromInteger x) - 1
elements, followed by y
, consed with a reference to the tail of heap
at index fromInteger x
(this constructs fromInteger x
cons cells)readc
: store store (toInteger (fromEnum ch))
at index fromInteger x
in heap
readi
: store store ((read ch) :: Integer)
at index fromInteger x
in
heap
pc
:
call l
, jmp l
, jz l
if x == 0
, jn l
if x < 0
: set pc
to
findLabel l prog
ret
: set pc
to pc2
pc
to pc+1