;; Data Definitions

;; An expr is
;;  - number
;;  - symbol
;;  - (make-add expr expr)
;;  - (make-mult expr expr)
;;  - (make-proc symbol expr)
;;  - (make-call expr expr)

(define-struct add (left right))
(define-struct mult (left right))
(define-struct proc (param body))
(define-struct call (func arg))

;; A dsub is a (make-dsub symbol value)

(define-struct dsub (var val))

;; An env is a list[dsub]

;;--------------------------------------------------------------------

;; Implementing Environments

;; empty-env : -> empty
;; returns a new (empty) environment
(define (empty-env) empty)

;; lookup-env : symbol env -> value
;; finds dsub for symbol in env and returns corresponding value

;; extend-env : symbol value env -> env
;; adds a new dsub to env that associates symbol with value

;;--------------------------------------------------------------------

;; The Interpreter itself

;; interp-d : expr env -> value
;; evaluates exp with given function def, uses dsubs
(define (interp-d anexpr env)
  (cond [(number? anexpr) anexpr]
        [(symbol? anexpr) (lookup-env anexpr env)]
	[(proc? anexpr) anexpr]
        [(add? anexpr)
	 (+ (interp-d (add-left anexpr) env)
	    (interp-d (add-right anexpr) env))]
        [(mult? anexpr)
	 (* (interp-d (mult-left anexpr) env)
	    (interp-d (mult-right anexpr) env))]
        [(call? anexpr)
	 (interp-d (proc-body (interp-d (call-func anexpr) env))
		   (extend-env (proc-param (interp-d (call-func anexpr) env))
			       (interp-d (call-arg anexpr) env)
			       env))]))

;; interp : expr -> value
;; calls interp-d with an initial (empty) environment
(define (interp anexpr)
  (interp-d anexpr (empty-env)))

