UNB/ CS/ David Bremner/ teaching/ cs4613/ lectures/ lecture04/ parse.rkt
#lang plait
(define-type Exp
  [numE (n : Number)]
  [plusE (left : Exp) (right : Exp)]
  [timesE (left : Exp) (right : Exp)]
  [lamE (var : Symbol) (body : Exp)]
  [appE (fun : Exp) (arg : Exp)]
  [varE (name : Symbol)]
  [let1E (var : Symbol)
         (value : Exp)
         (body : Exp)])

(define (parse s)
  (local
      [(define (sx n) (list-ref (s-exp->list s) n))
       (define (px n) (parse (sx n)))
       (define (? pat) (s-exp-match? pat s))]
    (cond
      [(? `SYMBOL) (varE (s-exp->symbol s))]
      [(? `NUMBER) (numE (s-exp->number s))]
      [(? `(+ ANY ANY)) (plusE (px 1) (px 2))]
      [(? `(* ANY ANY)) (timesE (px 1) (px 2))]
      [(? `(let1 (SYMBOL ANY) ANY))
       (let* ([def (sx 1)]
              [parts (s-exp->list def)]
              [var (s-exp->symbol (list-ref parts 0))]
              [val (parse (list-ref parts 1))]
              [body (px 2)])
         (let1E var val body))]
      [(? `(lam SYMBOL ANY))
       (lamE (s-exp->symbol (sx 1)) (px 2))]
      [(? `(ANY ANY)) (appE (px 0) (px 1))]
      [else (error 'parse (to-string s))])))


(test (parse 
       `{let1 {x 3}
              {let1 {f {lam y {+ x y}}}
                    {f 3}}})
      (let1E 'x (numE 3)
             (let1E 'f (lamE 'y (plusE (varE 'x) (varE 'y)))
                    (appE (varE 'f) (numE 3)))))