; This will be used on the server to validate all source code by the participants before running it
; Allowed procedures and special-forms will vary with each challenge

#lang racket

(require "challenge.rkt")
(require "either.rkt")

(provide validate run)

(define (validate str allowed)
  (call/cc
    (lambda (c)
      (call-with-exception-handler
        (lambda (e)
          (c (left (exn-message e))))
        (lambda ()
          (define expr (read (open-input-string str)))
          (if (check-allowed expr allowed)
            (right expr)
            (left "Error: you used a procedure, special form or variable name that has been disabled.")))))))

(define (check-allowed expr allowed)
  (if (pair? expr)
    (andmap (lambda (x) (check-allowed x allowed)) expr)
    (or (not (symbol? expr)) (member expr allowed))))

; Allowing for functions with multiple arguments is something I leave for the future generation to implement
; It should be quite trivial add
(define (run challenge code)
  (call/cc 
    (lambda (c)
      (call-with-exception-handler
        (lambda (e)
          (c (left (exn-message e))))
        (lambda ()
          (define input (challenge-input challenge))
          (define func (eval code (make-base-namespace)))
          (define res (map (lambda (in) (apply func (list in))) input))
          (if (equal? res (challenge-output challenge))
            (right "")
            (left res)))))))
