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")
.