whalesong/simulator.rkt

207 lines
6.1 KiB
Racket

#lang typed/racket/base
;; An evaluator for the intermediate language, so I can do experiments.
(require "il-structs.rkt"
"simulator-structs.rkt"
racket/list
racket/match)
(provide new-machine can-step? step)
(: new-machine ((Listof Statement) -> machine))
(define (new-machine program-text)
(make-machine (void) (void) '() '() 0 (list->vector program-text)))
(: can-step? (machine -> Boolean))
;; Produces true if we can make a further step in the simulation.
(define (can-step? m)
(< (machine-pc m)
(vector-length (machine-text m))))
(: step (machine -> machine))
;; Take one simulation step.
(define (step m)
(let: ([i : Statement (current-instruction m)])
(increment-pc
(cond
[(symbol? i)
m]
[(AssignImmediateStatement? i)
(step-assign-immediate m i)]
[(AssignPrimOpStatement? i)
(error 'step)]
[(PerformStatement? i)
(error 'step)]
[(GotoStatement? i)
(step-goto m i)]
[(TestAndBranchStatement? i)
(error 'step)]
[(PopEnvironment? i)
(error 'step)]
[(PushEnvironment? i)
(error 'step)]
[(PushControlFrame? i)
(error 'step)]
[(PopControlFrame? i)
(error 'step)]))))
(: step-goto (machine GotoStatement -> machine))
(define (step-goto m a-goto)
(let: ([t : (U Label Reg) (GotoStatement-target a-goto)])
(cond [(Label? t)
(jump m (Label-name t))]
[(Reg? t)
(let: ([reg : RegisterSymbol (Reg-name t)])
(cond [(AtomicRegisterSymbol? reg)
(cond [(eq? reg 'val)
(jump m (ensure-symbol (machine-val m)))]
[(eq? reg 'proc)
(jump m (ensure-symbol (machine-proc m)))])]
[else
(error 'step-goto "Register '~s is supposed to be either 'val or 'proc"
reg)]))])))
(: step-assign-immediate (machine AssignImmediateStatement -> machine))
(define (step-assign-immediate m stmt)
(let: ([t : Target (AssignImmediateStatement-target stmt)]
[v : Any (evaluate-oparg m (AssignImmediateStatement-value stmt))])
(cond [(eq? t 'proc)
(proc-update m v)]
[(eq? t 'val)
(val-update m v)]
[(EnvLexicalReference? t)
(env-mutate m (EnvLexicalReference-depth t) v)])))
(: evaluate-oparg (machine OpArg -> Any))
(define (evaluate-oparg m an-oparg)
(cond
[(Const? an-oparg)
(Const-const an-oparg)]
[(Label? an-oparg)
(Label-name an-oparg)]
[(Reg? an-oparg)
(let: ([n : AtomicRegisterSymbol (Reg-name an-oparg)])
(cond
[(eq? n 'proc)
(machine-proc m)]
[(eq? n 'val)
(machine-val m)]))]
[(EnvLexicalReference? an-oparg)
(list-ref (machine-env m) (EnvLexicalReference-depth an-oparg))]
[(EnvWholePrefixReference? an-oparg)
;; TODO: check that the value is a prefix value.
(list-ref (machine-env m) (EnvWholePrefixReference-depth an-oparg))]))
(: ensure-symbol (Any -> Symbol))
;; Make sure the value is a symbol.
(define (ensure-symbol v)
(cond
[(symbol? v)
v]
[else
(error 'ensure-symbol)]))
(: current-instruction (machine -> Statement))
(define (current-instruction m)
(match m
[(struct machine (val proc env control pc text))
(vector-ref text pc)]))
(: val-update (machine Any -> machine))
(define (val-update m v)
(match m
[(struct machine (val proc env control pc text))
(make-machine v proc env control pc text)]))
(: proc-update (machine Any -> machine))
(define (proc-update m v)
(match m
[(struct machine (val proc env control pc text))
(make-machine val v env control pc text)]))
(: env-push (machine Any -> machine))
(define (env-push m v)
(match m
[(struct machine (val proc env control pc text))
(make-machine val proc (cons v env) control pc text)]))
(: env-ref (machine Natural -> Any))
(define (env-ref m i)
(match m
[(struct machine (val proc env control pc text))
(list-ref env i)]))
(: env-mutate (machine Natural Any -> machine))
(define (env-mutate m i v)
(match m
[(struct machine (val proc env control pc text))
(make-machine val proc (list-replace env i v) control pc text)]))
(: list-replace (All (A) (Listof A) Natural A -> (Listof A)))
(define (list-replace l i v)
(cond
[(= i 0)
(cons v (rest l))]
[else
(cons (first l)
(list-replace (rest l) (sub1 i) v))]))
(: env-pop (machine Natural Natural -> machine))
(define (env-pop m n skip)
(match m
[(struct machine (val proc env control pc text))
(make-machine val proc (append (take env skip)
(drop env (+ skip n)))
control pc text)]))
(: control-push (machine Symbol -> machine))
(define (control-push m l)
(match m
[(struct machine (val proc env control pc text))
(make-machine val proc env (cons (make-frame l) control) pc text)]))
(: control-pop (machine Symbol -> (values machine Symbol)))
(define (control-pop m l)
(match m
[(struct machine (val proc env control pc text))
(values (make-machine val proc env (rest control) pc text)
(frame-return (first control)))]))
(: increment-pc (machine -> machine))
(define (increment-pc m)
(match m
[(struct machine (val proc env control pc text))
(make-machine val proc env control (add1 pc) text)]))
(: jump (machine Symbol -> machine))
;; Jumps directly to the instruction at the given label.
(define (jump m l)
(match m
[(struct machine (val proc env control pc text))
(make-machine val proc env control (vector-find text l) text)]))
(: vector-find (All (A) (Vectorof A) A -> Natural))
(define (vector-find vec x)
(let: loop : Natural ([i : Natural 0])
(cond
[(eq? (vector-ref vec i) x)
i]
[else
(loop (add1 i))])))