#lang scheme
(define-struct success (results))
(define-struct failure (results))
(define-struct program (source expansion evaluation output-port error-port))
(define (build-program module-path definitions interactions)
(let* ([source (make-source module-path definitions interactions)]
[output-port (open-output-string)]
[error-port (open-output-string)]
[expansion (delay (expand-program source output-port error-port))]
[evaluation (delay (eval-program expansion output-port error-port))])
(make-program source expansion evaluation output-port error-port)))
(define (program-expands? program)
(success? (force (program-expansion program))))
(define (program-evals? program)
(success? (force (program-evaluation program))))
(define (program-original-syntax program)
(program-source program))
(define (program-expanded-syntax program)
(success-results (force (program-expansion program))))
(define (program-expansion-error program)
(failure-results (force (program-expansion program))))
(define (program-repl-values program)
(success-results (force (program-evaluation program))))
(define (program-evaluation-error program)
(failure-results (force (program-evaluation program))))
(define (program-output program)
(get-output-string (program-output-port program)))
(define (program-error-output program)
(get-output-string (program-error-port program)))
(provide/contract
[program? (-> any/c boolean?)]
[rename build-program make-program
(->* [module-path? (listof any/c)] [(listof any/c)] program?)]
[program-source (-> program? (listof syntax?))]
[program-expand? (-> program? boolean?)]
[program-expanded (-> program? (listof syntax?))]
[program-expand-error (-> program? any/c)]
[program-eval? (-> program? boolean?)]
[program-value (-> program any)]
[program-eval-error (-> program any/c)]
[program-output (-> program string?)]
[program-error-output (-> program string?)])