BitterSuite: Filtering student code prior to execution

Warning: This has not yet been tested in BitterSuite 3. This needs to be tested, modified as needed, and verified to a reasonably strong degree that this works correctly before this warning is removed.

NB: The following code assumes that the submission was made in a teaching language, and will not work on submissions in the module language as written.

Create a file called runTests-preprocess in the root of the testing directory (i.e. at the same level as in and provided). Make sure this file is executable (e.g. by using chmod +x runTests-preprocess), and put the following code in it:

#!/xhbin/bash

filter_filename=aXqY
filter_code="mzscheme -u filter-code.ss"
mangle=/u/isg/bittersuite3/languages/scheme/plt370mangle

if [ -e "$filter_filename.ss" ]; then
        echo "filtering $filter_filename.ss..."
        $mangle < $filter_filename.ss | $filter_code > $filter_filename.filt.ss
elif [ -e "$filter_filename.scm" ]; then
        echo "filtering $filter_filename.scm..."
        $mangle < $filter_filename.scm | $filter_code > $filter_filename.filt.scm
else
        echo "$filter_filename.ss/scm not found: no filtering performed"
fi

# don't let errors from this script stop runTests
exit 0

Change aXqY to the file to be filtered. If you need to filter more than one file, put this script in provided/ and make runTests-preprocess call it for each file which should be filtered. This is left as an exercise for the reader.

In the file provided/filter-code.ss, put this code:

#lang scheme

(define (do-read)
  (define cur-read
      (with-handlers ((void (lambda (exn)
                              (begin (fprintf (current-error-port) "read error: ~a\n" (exn-message exn))
                                     (void)))))
        (read)))
  (cond
    [(eof-object? cur-read) (void)]
    [(void? cur-read) (do-read)]
    [.1. .2. (do-read)]
    [else (write cur-read)
          (do-read)]))

(do-read)

or, equivalently but without repeating the explicit calls to (do-read),

#lang scheme

(let do-read ()
  (let ([cur-read
         (with-handlers ((void (lambda (exn)
                                 (begin (fprintf (current-error-port) 
                                                 "read error: ~a\n" 
                                                 (exn-message exn))
                                        (void)))))
           (read))])
    (unless (eof-object? cur-read)
      (unless (void? cur-read)
        (cond
          [.1. .2.]
          [else (write cur-read)]))
      (do-read))))

The ".1." in the above script should be replaced by the filtering condition, and the ".2" should be replaced by the filtering you want to perform. There can also be as many filtering conditions as you want in succession in this cond. For example, if we want to strip out all instances of the statement (define-struct foo ...) we can use the code

    [(and (list? cur-read)
          (>= (length cur-read) 2)
          (equal? (first cur-read) 'define-struct)
          (equal? (second cur-read) 'foo))
     (void)]
with the S-expression starting with and replacing ".1." and (void) replacing ".2." since we simply want to drop this expression instead of transforming it into something else. This will remove any (define-struct foo ...) S-expressions from the student's code while leaving everything else intact.

Now, instead of using (loadcode "aXqY.ss") in options.ss, you can use (loadcode "aXqY.filt.ss") to load the filtered code. Note that the language must be one of the teaching languages explicitly. In beginning student, for example, this would require a (language scheme/beginner) context or for the loadcode to be modified to (loadcode beginner "aXqY.filt.ss").

Topic revision: r3 - 2010-02-16 - TerryVaskor
 
This site is powered by the TWiki collaboration platform Powered by PerlCopyright © 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback