; 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") (require racket/format) (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))) (check-allowed expr allowed)))))) (define (check-allowed expr allowed) (define (get-symbols expr) (if (pair? expr) (flatten (map get-symbols expr)) (if (symbol? expr) (list expr) '()))) (define syms (get-symbols expr)) (define bad-syms (filter (lambda (s) (not (member s allowed))) syms)) (if (null? bad-syms) (right expr) (left (apply string-append (cons "error: you used one or more procedures, special forms or variable names that has been disabled: " (map (lambda (s) (string-append " " s " ")) (map symbol->string bad-syms))))))) ; 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)))))))