#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))))