UNB/ CS/ David Bremner/ teaching/ cs4613/ lectures/ lecture01/ parse-s-exp.rkt
#lang plait
(define-type Exp
  [num (n : Number)]
  [plus (left : Exp) (right : Exp)]
  [times (left : Exp) (right : Exp)])

(define (parse-s-exp s-exp)
  (local [(define (sx n)
            (list-ref (s-exp->list s-exp) n))
          (define (px n) (parse-s-exp (sx n)))
          (define (? pat) (s-exp-match? pat s-exp))]
    (cond
      [(? `(ae ANY "+" ANY)) (plus (px 1) (px 3))]
      [(? `(ae (fac ANY ...))) (px 1)]
      [(? `(fac ANY "*" ANY)) (times (px 1) (px 3))]
      [(? `(fac (atom ANY ...))) (px 1)]
      [(? `(atom NUMBER)) (num (s-exp->number (sx 1)))]
      [(? `(atom "(" ANY ")")) (px 2)]
      [else (error 'parse-s-exp (to-string s-exp))])))

(test
 (parse-s-exp
  `(ae (fac (atom 1)) "+"
       (ae (fac (atom 2) "*" (fac (atom 3))))))
 (plus (num 1)
       (times (num 2) (num 3))))
(test
 (parse-s-exp
  `(ae (fac (atom 1) "*" (fac (atom 2))) "+"
       (ae (fac (atom 3)))))
 (plus (times (num 1) (num 2))
       (num 3)))
(test
 (parse-s-exp
  `(ae
    (fac
     (atom "(" (ae (fac (atom 1)) "+" (ae (fac (atom 2)))) ")")
     "*"
     (fac (atom "(" (ae (fac (atom 3)) "+" (ae (fac (atom 4)))) ")")))))
 (times
  (plus (num 1) (num 2))
  (plus (num 3) (num 4))))