;;; $Id: ch3-7-modified-in-class.scm,v 1.4 2006/01/05 22:24:09 leavens Exp $ ;;; Interpreter with variable assignment. (module ch3-7-modified-in-class (lib "typedscm.ss" "typedscm") (provide read-eval-print eval-program run scan&parse just-scan run-all run-one equal-external-reps?) (require (lib "environment-3-7.scm" "lib342") (lib "reference-3-7.scm" "lib342") (lib "test-suite.scm" "lib342")) ;;;;;;;;;;;;;;;; top level and tests ;;;;;;;;;;;;;;;; (deftype run (-> (string) datum)) (define run (lambda (string) (eval-program (scan&parse string)))) (deftype run-all (-> () void)) (define run-all (lambda () (run-experiment run use-execution-outcome '(lang3-1 lang3-5 lang3-6 lang3-7) (all-tests)))) (deftype run-one (-> (symbol) datum)) (define run-one (lambda (test-name) (run-test run test-name))) ;; needed for testing (deftype equal-external-reps? (-> (datum datum) boolean)) (define equal-external-reps? (lambda (x y) (equal? x y))) ;;;;;;;;;;;;;;;; grammatical specification ;;;;;;;;;;;;;;;; (define the-lexical-spec '((whitespace (whitespace) skip) (comment ("%" (arbno (not #\newline))) skip) (identifier (letter (arbno (or letter digit "_" "-" "?"))) symbol) (number (digit (arbno digit)) number))) (define the-grammar '((program (expression) a-program) (expression (number) lit-exp) (expression (identifier) var-exp) (expression (primitive "(" (separated-list expression ",") ")") primapp-exp) (expression ("if" expression "then" expression "else" expression) if-exp) (expression ("let" (arbno identifier "=" expression) "in" expression) let-exp) (expression ("proc" "(" (separated-list identifier ",") ")" expression) proc-exp) (expression ("(" expression (arbno expression) ")") app-exp) (expression ("begin" expression (arbno ";" expression) "end") begin-exp) (expression ("letrec" (arbno identifier "(" (separated-list identifier ",") ")" "=" expression) "in" expression) letrec-exp) (expression ("set" identifier "=" expression) varassign-exp) (expression ("setdynamic" identifier "=" expression "during" expression) setdynamic-exp) (primitive ("+") add-prim) (primitive ("-") subtract-prim) (primitive ("*") mult-prim) (primitive ("add1") incr-prim) (primitive ("sub1") decr-prim) (primitive ("zero?") zero-test-prim) )) (deftype show-the-datatypes (-> () (list-of datum))) (define show-the-datatypes (lambda () (sllgen:make-define-datatypes the-lexical-spec the-grammar) (sllgen:list-define-datatypes the-lexical-spec the-grammar))) ;; The following is generated by calling show-the-datatypes ;; (and then removing the outer lists, indenting, and renaming fields). (define-datatype program program? (a-program (exp expression?))) (define-datatype expression expression? (lit-exp (datum number?)) (var-exp (id symbol?)) (primapp-exp (prim primitive?) (rands (list-of expression?))) (if-exp (test-exp expression?) (true-exp expression?) (false-exp expression?)) (let-exp (ids (list-of symbol?)) (rands (list-of expression?)) (body expression?)) (proc-exp (ids (list-of symbol?)) (body expression?)) (app-exp (rator expression?) (rands (list-of expression?))) (begin-exp (first expression?) (rest (list-of expression?))) (letrec-exp (proc-names (list-of symbol?)) (idss (list-of (list-of symbol?))) (bodies (list-of expression?)) (letrec-body expression?)) (varassign-exp (id symbol?) (rhs-exp expression?)) (setdynamic-exp (id symbol?) (rhs-exp expression?) (body-exp expression?)) ) (define-datatype primitive primitive? (add-prim) (subtract-prim) (mult-prim) (incr-prim) (decr-prim) (zero-test-prim) ) (deftype scan&parse (-> (string) program)) (define scan&parse (lambda (ptext) ((sllgen:make-string-parser the-lexical-spec the-grammar) ptext))) (deftype just-scan (forall (TOK) (-> (string) (list-of TOK)))) (define just-scan (lambda (ptext) ((sllgen:make-string-scanner the-lexical-spec the-grammar) ptext))) (deftype read-eval-print (-> () poof)) (define read-eval-print (lambda () ((sllgen:make-rep-loop "--> " (lambda (pgm) (eval-program pgm)) (sllgen:make-stream-parser the-lexical-spec the-grammar))))) ;;; Domains for this interpreter: ;;; ;;; Expressed-Value = Number + ProcVal + List(Expressed-Value) ;;; Denoted-Value = Ref(Expressed-Value) ;;; ADTs used ;;;;;;;;;;;;;;;; ProcVal ;;;;;;;;;;;;;;;; (deftype procval? (type-predicate-for procval)) (deftype closure (-> ((list-of symbol) expression environment) procval)) (deftype apply-procval (-> (procval (list-of Expressed-Value)) Expressed-Value)) (define-datatype procval procval? (closure (ids (list-of symbol?)) (body expression?) (env environment?))) (define apply-procval (lambda (proc args) (cases procval proc (closure (ids body env) (eval-expression body (extend-env ids args env)))))) ;;; Anonymous figure : page 80 (deftype true-value? (-> (Expressed-Value) boolean)) (define true-value? (lambda (x) (not (zero? (expressed->number x))))) ;;;;;;;;; Expressed-Value ;;;;;;;;;;;;;;;;;;;;;;;;; ;; upcasts (deftype number->expressed (-> (number) Expressed-Value)) (deftype procval->expressed (-> (Procval) Expressed-Value)) (deftype list->expressed (-> ((list-of Expressed-Value)) Expressed-Value)) ;; downcasts (deftype expressed->number (-> (Expressed-Value) number)) (deftype expressed->procval (-> (Expressed-Value) Procval)) (deftype expressed->list (-> (Expressed-Value) (list-of Expressed-Value))) ;; debugging (deftype expressed->printable (-> (Expressed-Value) datum)) ;; tests (deftype number->expressed? (-> (Expressed-Value) boolean)) (deftype procval->expressed? (-> (Expressed-Value) boolean)) (deftype list->expressed? (-> (Expressed-Value) boolean)) (define-datatype Expressed-Value expval? (number->expressed (num number?)) (procval->expressed (pv procval?)) (list->expressed (lst (list-of expval?)))) (define expressed->number (lambda (ev) (cases Expressed-Value ev (number->expressed (num) num) (else (error "expressed->number passed non-number argument: " ev))))) (define expressed->procval (lambda (ev) (cases Expressed-Value ev (procval->expressed (pv) pv) (else (error "expressed->procval passed non-procval argument: " ev))))) (define expressed->list (lambda (ev) (cases Expressed-Value ev (list->expressed (lst) lst) (else (error "expressed->list passed non-list argument: " ev))))) (define expressed->printable (lambda (ev) (cases Expressed-Value ev (number->expressed (num) (has-type datum num)) (procval->expressed (pv) (cases procval pv (closure (ids body env) (has-type datum (list 'closure ids body ""))))) (list->expressed (lst) (has-type datum (map expressed->printable lst)))))) (define number->expressed? (lambda (ev) (cases Expressed-Value ev (number->expressed (num) #t) (else #f)))) (define procval->expressed? (lambda (ev) (cases Expressed-Value ev (procval->expressed (pv) #t) (else #f)))) (define list->expressed? (lambda (ev) (cases Expressed-Value ev (list->expressed (lst) #t) (else #f)))) ;; adaptation of environment-3-7 to this file (deftype extend-env-recursively (-> ((list-of symbol) (list-of (list-of symbol)) (list-of expression) environment) environment)) (define extend-env-recursively (extend-env-recursively-maker (lambda (ids body env) (procval->expressed (closure ids body env))) (procval->expressed (closure '() (lit-exp 0) (empty-env))))) ;;;;;;;;;;;;;;;; the interpreter ;;;;;;;;;;;;;;;; (deftype eval-program (-> (program) datum)) (define eval-program (lambda (pgm) (cases program pgm (a-program (body) (expressed->printable (eval-expression body (init-env))))))) (deftype eval-expression (-> (expression environment) Expressed-Value)) (define eval-expression (lambda (exp env) (cases expression exp (lit-exp (datum) (number->expressed datum)) (var-exp (id) (apply-env env id)) (primapp-exp (prim rands) (let ((args (eval-rands rands env))) (apply-primitive prim args))) (if-exp (test-exp true-exp false-exp) (if (true-value? (eval-expression test-exp env)) (eval-expression true-exp env) (eval-expression false-exp env))) (begin-exp (exp1 exps) (let loop ((acc (eval-expression exp1 env)) (exps exps)) (if (null? exps) acc (loop (eval-expression (car exps) env) (cdr exps))))) (let-exp (ids rands body) (let ((args (eval-rands rands env))) (eval-expression body (extend-env ids args env)))) (proc-exp (ids body) (procval->expressed (closure ids body env))) (app-exp (rator rands) (let ((proc (eval-expression rator env)) (args (eval-rands rands env))) (if (procval->expressed? proc) (apply-procval (expressed->procval proc) args) (eopl:error 'eval-expression "Attempt to apply non-procedure ~s" proc)))) (letrec-exp (proc-names idss bodies letrec-body) (eval-expression letrec-body (extend-env-recursively proc-names idss bodies env))) (varassign-exp (id rhs-exp) (begin (setref! (apply-env-ref env id) (eval-expression rhs-exp env)) (number->expressed 1))) (setdynamic-exp (id rhs-exp body-exp) (let* ((ref (apply-env-ref env id)) (old-val (deref ref))) (setref! ref (eval-expression rhs-exp env)) (let ((res (eval-expression body-exp env))) (setref! ref old-val) res))) (else (eopl:error 'eval-expression "Missing case:~s" exp)) ))) (deftype eval-rands (-> ((list-of expression) environment) (list-of Expressed-Value))) (define eval-rands (lambda (rands env) (map (lambda (x) (eval-rand x env)) rands))) (deftype eval-rand (-> (expression environment) Expressed-Value)) (define eval-rand (lambda (rand env) (eval-expression rand env))) (deftype apply-primitive (-> (primitive (list-of Expressed-Value)) Expressed-Value)) (define apply-primitive (lambda (prim args) (cases primitive prim (add-prim () (number->expressed (+ (expressed->number (car args)) (expressed->number (cadr args))))) (subtract-prim () (number->expressed (- (expressed->number (car args)) (expressed->number (cadr args))))) (mult-prim () (number->expressed (* (expressed->number (car args)) (expressed->number (cadr args))))) (incr-prim () (number->expressed (+ (expressed->number (car args)) 1))) (decr-prim () (number->expressed (- (expressed->number (car args)) 1))) (zero-test-prim () (number->expressed (if (zero? (expressed->number (car args))) 1 0))) ))) (deftype init-env (-> () environment)) (define init-env (lambda () (extend-env '(i v x) (map number->expressed '(1 5 10)) (empty-env)))) ) ;; end module