#lang planet plai/plai
;; You need the PLAI language installed before you can run this.
;; To get it, evaluate the following expression with your PLT interpreter:
;; (require (planet plai/plai)) 

(define-type Binding
  [binding (name symbol?) (named-expr CFCFWAE?)])

(define-type CFCFWAE
  [num (n number?)]
  [binop (op procedure?) (lhs CFCFWAE?) (rhs CFCFWAE?)]
  [with (lob (listof Binding?)) (body CFCFWAE?)]
  [id (name symbol?)]
  [if0 (test-e CFCFWAE?) (then-e CFCFWAE?) (else-e CFCFWAE?)]
  [fun (params (listof symbol?)) (body CFCFWAE?)]
  [app (fun CFCFWAE?) (args (listof CFCFWAE?))])

(define-type CFCFWAE-Value
  [numV (n number?)]
  [closureV (params (listof symbol?)) (body CFCFWAE?) (ds DefrdSub?)])

(define-type DefrdSub
  [mtSub]
  [aSub (name symbol?) (value CFCFWAE-Value?) (ds DefrdSub?)])

;; lookup : symbol DefrdSub -> CFCFWAE-Value
;; gets the value bound to an identifier in the environment, or throws an error
;; (feel free to replace this with your own implementation if you prefer)
(define (lookup name ds)
  (type-case DefrdSub ds
     [mtSub () (error 'lookup "no binding for identifier: ~s" name)]
     [aSub (bound-name bound-value rest-ds)
           (if (symbol=? bound-name name)
               bound-value
               (lookup name rest-ds))]))

(define cfcfwae-keywords '(fun with if0))

;; cfcfwae-keyword? : symbol -> boolean
;; true only if the symbol is a syntactic keyword of this language
(define (cfcfwae-keyword? sym)
  (member sym cfcfwae-keywords))

;; cfcfwae-op? : symbol -> boolean
;; true only if the symbol is an operator name
(define (cfcfwae-op? sym)
  (error "not implemented"))

;; cfcfwae-reserved? : symbol -> boolean
;; true only if the symbol is a keyword or operator name
(define (cfcfwae-reserved? sym)
  (or (cfcfwae-keyword? sym) (cfcfwae-op? sym)))

;; parse : s-exp -> CFCFWAE
;; consumes an s-expression and generates the corresponding CFCFWAE
;; indicates parsing errors using (error 'parse "appropriate message")
(define (parse sexp)
  (error "not implemented"))

;; interp : CFCFWAE [DefrdSub] -> CFCFWAE-Value
;; evaluates a CFCFWAE expression to its associated value
;; if a DefrdSub is given, evaluates the expression in that environment
(define interp
  (case-lambda
    [(expr) (interp expr (mtSub))]
    [(expr ds) (error "not implemented")]))
; not strictly necessary, but useful for transition
(define calc interp)

;; numV-binop : proc numV numV -> numV
;; applies proc to the numbers in the two numV parameters
;; returns a numV containing the resulting number
(define (numV-binop proc n1 n2)
  (numV (proc (numV-n n1) (numV-n n2))))
