#lang plait
#| BNF for the AE language:
<AE> ::= <num>
| { + <AE> <AE> }
| { - <AE> <AE> }
| { * <AE> <AE> }
| { / <AE> <AE> }
|#
;; AE abstract syntax trees
(define-type AE
[Num (val : Number)]
[Add (l : AE) (r : AE)]
[Sub (l : AE) (r : AE)]
[Mul (l : AE) (r : AE)]
[Div (l : AE) (r : AE)])
;; to convert s-expressions into AEs
(define (parse-sx sx)
(let ([rec (lambda (fn)
(parse-sx (fn (s-exp->list sx))))])
(cond
[(s-exp-match? `NUMBER sx)
(Num (s-exp->number sx))]
[(s-exp-match? `(+ ANY ANY) sx)
(Add (rec second) (rec third))]
[(s-exp-match? `(- ANY ANY) sx)
(Sub (rec second) (rec third))]
[(s-exp-match? `(* ANY ANY) sx)
(Mul (rec second) (rec third))]
[(s-exp-match? `(/ ANY ANY) sx)
(Div (rec second) (rec third))]
[else (error 'parse-sx (to-string sx))])))
(define (eval expr)
(type-case AE expr
[(Num n) n]
[(Add l r) (+ (eval l) (eval r))]
[(Sub l r) (- (eval l) (eval r))]
[(Mul l r) (* (eval l) (eval r))]
[(Div l r) (/ (eval l) (eval r))]))
(define (run sx)
(eval (parse-sx sx)))
(test (run `3) 3)
(test (run `{+ 3 4}) 7)
(test (run `{+ {- 3 4} 7}) 6)