File: typecheck-gen.lsp

package info (click to toggle)
nyquist 3.24%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 58,156 kB
  • sloc: ansic: 74,757; lisp: 18,169; java: 10,942; cpp: 6,688; sh: 175; xml: 58; makefile: 40; python: 15
file content (170 lines) | stat: -rw-r--r-- 5,891 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
;; typecheck-gen.lsp - functions to support regression testing
;;   of examples that would normally raise errors. This redefines
;;   error handling and generates unit tests by running the code.
;;   unit tests are written to typechecks<N>.sal

(defun ny:error (src index typ val &optional multi (val2 nil second-val))
  (display "ny:error" src index typ val)
  (setf *expect-nyerror* (list src index typ))
  (setf *error-msg* 
        (strcat "In " src "," (index-to-string index) " argument"
          (if (second typ) (strcat " (" (second typ) ")") "")
          " must be a "
          (ny:type-list-as-string (first typ) multi)
          ", got " (param-to-string val)
          (if second-val (strcat ", and" (param-to-string val2)) "")))
  (throw 'simulated-error))

(defun sal-print (&rest args)
  (if (/= (length args) 1)
      (error-original "redefined sal-print expects single argument" args))
  (setf *expect-print* (car args)))

(defun s-plot (snd &optional (dur 2) (n 1000))
  ;; these are copied from the "real" s-plot:
  (ny:typecheck (not (soundp snd))
    (ny:error "S-PLOT (or PLOT command)" 1 '((SOUND) nil) snd))
  (ny:typecheck (not (numberp dur))
    (ny:error "S-PLOT (or PLOT command)" 2 '((NUMBER) "dur") dur))
  (ny:typecheck (not (integerp n))
    (ny:error "S-PLOT (or PLOT command)" 3 '((INTEGER) nil) n))

  (setf *expect-plot* t))

(setfn error-original error)

(defun error (x &optional y)
  (setf *expect-error* x)
  (throw 'simulated-error))


(defun print-arg (arg outf)
  (cond ((arrayp arg)
         (princ "vector(" outf)
         (let (need-comma)
           (dotimes (i (length arg))
             (if need-comma (princ ", " outf) (setf need-comma t))
             (print-arg (aref arg i) outf))
           (princ ")" outf)))
        ((listp arg)
         (princ "{" outf)
         (let (need-space)
           (dolist (a arg)
             (if need-space (princ " " outf) (setf need-space t))
             (print-arg a outf)))
         (princ "}" outf))
        (t
         (prin1 arg outf))))


(defun escaped (line)
  (let ((rslt "\"") ch)
    (dotimes (i (length line))
      (setf ch (char line i))
      (setf rslt (strcat rslt (if (equal ch #\") "\\\""
                                                 (string ch)))))
    (strcat rslt "\"")))


;; this function generates the "unit test" to check for what
;; just happened when we executed the previous command
;; what can be :print :plot :error or :nyerror 
;; command looks like:
;;   (ny:expect expression what val)
;;
(defun expect-gen (line outf)
  (princ "exec ny:expect(" outf)
  (princ line outf)
  (princ ",\n               " outf)
  (cond (*expect-print*
         (princ ":print, " outf)
         (print-arg *expect-print* outf))
        (*expect-plot*
         (princ ":plot, " outf)
         (prin1 *expect-plot* outf))
        (*expect-nyerror*
         (princ ":nyerror, " outf)
         (print-arg *expect-nyerror* outf))
        (*expect-error*
         (princ ":error, " outf)
         (prin1 *expect-error* outf))
        (t
         (close outf)
         (error-original "in expect-gen, nothing happened?")))
   (princ ")\n" outf)
   (princ "exec #print(" outf)
   (princ line outf)
   (princ ")\n" outf))


(defun is-a-command (line)
  (and (> (length line) 0)
       (not (eql #\; (char line 0)))))


(defun generate-line (line outf)
  (setf *expect-print* nil *expect-plot* nil 
        *expect-error* nil *expect-nyerror* nil 
        *error-msg* nil)
  (catch 'simulated-error
    (sal-compile line t nil "<typecheck-gen>"))
  ;; after execution, see what happened and generate unit test
  (setf line (escaped line))
  (expect-gen line outf)
  (format outf "exec catch(quote(simulated-error), ~%")
  (format outf "           sal-compile(~A, #t, #f,~%" line)
  (format outf "                       \"<in typecheck.sal>\"))~%")
  (if *error-msg* (format outf "; ERROR MSG: ~A~%" *error-msg*))
  (format outf "~%"))


;; There was a stack overflow problem putting everything into
;; a 3000-line SAL file, so separate the tests into multiple files
(setf *tests-per-file* 100)

(defun generate ()
  (let ((inf (open "typechecks.txt"))
        (mainf (open "typechecks.lsp" :direction :output))
        outf
        outf-name
        (file-count 0)
        (test-count *tests-per-file*)
        line)
    ;; test for successful open file operations
    (if (not inf) (error-original "could not open typechecks.txt"))
    (if (not mainf) (error-original "could not open for output typechecks.lsp"))

    ;; write header info
    (format mainf "; typechecks.lsp -- unit tests for typechecks~%")
    (format mainf "; ~%")
    (format mainf "; This code was generated from typechecks.txt by~%")
    (format mainf "; typecheck-gen.lsp~%~%")

    ;; process every test
    (while (setf line (read-line inf))
      (cond ((is-a-command line)
            (cond ((>= test-count *tests-per-file*)
                   (if outf (close outf))
                   (setf test-count 0)
                   (setf file-count (1+ file-count))
                   (setf outf-name (format nil "typechecks~A.sal" file-count))
                   (setf outf (open outf-name :direction :output))
                   (if (not outf) (error-original "could not open" outf-name))

                   ;; add file to main file
                   (format mainf "(sal-load \"~A\")\n" outf-name)

                   ;; write the header information
                   (format outf "; ~A -- unit tests for typechecks~%" outf-name)
                   (format outf "; ~%")
                   (format outf "; This code was generated from typechecks.txt by~%")
                   (format outf "; typecheck-gen.lsp~%~%")))

             (format t "line: |~s|\n" line)
             (generate-line line outf)
             (setf test-count (1+ test-count)))))
    (close outf)
    (close inf)
    (close mainf)))

(generate)