chiark / gitweb /
src/final.lisp (test-module): Make it useful for testing error reporting.
[sod] / src / final.lisp
1 ;;; -*-lisp-*-
2 ;;;
3 ;;; Finishing touches for Sod
4 ;;;
5 ;;; (c) 2015 Straylight/Edgeware
6 ;;;
7
8 ;;;----- Licensing notice ---------------------------------------------------
9 ;;;
10 ;;; This file is part of the Sensible Object Design, an object system for C.
11 ;;;
12 ;;; SOD is free software; you can redistribute it and/or modify
13 ;;; it under the terms of the GNU General Public License as published by
14 ;;; the Free Software Foundation; either version 2 of the License, or
15 ;;; (at your option) any later version.
16 ;;;
17 ;;; SOD is distributed in the hope that it will be useful,
18 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;;; GNU General Public License for more details.
21 ;;;
22 ;;; You should have received a copy of the GNU General Public License
23 ;;; along with SOD; if not, write to the Free Software Foundation,
24 ;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 (cl:in-package #:sod)
27
28 ;;;--------------------------------------------------------------------------
29 ;;; Miscellaneous details.
30
31 (export '*sod-version*)
32 (defparameter *sod-version* sod-sysdef:*version*
33   "The version of the SOD translator system, as a string.")
34
35 ;;;--------------------------------------------------------------------------
36 ;;; Debugging utilities.
37
38 (export '*debugout-pathname*)
39 (defvar *debugout-pathname* #p"debugout.c")
40
41 (export 'test-module)
42 (defun test-module (path reason)
43   "Reset the translator's state, read a module from PATH and output it with
44    REASON, returning the result as a string."
45   (multiple-value-bind (module nerror nwarning)
46       (count-and-report-errors () (read-module path))
47     (when reason
48       (with-open-file (out *debugout-pathname*
49                        :direction :output
50                        :if-exists :supersede
51                        :if-does-not-exist :create)
52         (output-module module reason out)))
53     (list nerror nwarning)))
54
55 (export 'test-parse-c-type)
56 (defun test-parse-c-type (string)
57   "Parse STRING as a C type, with optional kernel, and show the results."
58   (with-input-from-string (in string)
59     (let* ((*module-type-map* (make-hash-table))
60            (charscan (make-instance 'charbuf-scanner
61                                     :stream in
62                                     :filename "<string>"))
63            (tokscan (make-instance 'sod-token-scanner
64                                    :char-scanner charscan
65                                    :filename "<string>")))
66       (with-parser-context (token-scanner-context :scanner tokscan)
67         (multiple-value-bind (value winp consumedp)
68             (parse (seq ((decls (parse-c-type tokscan))
69                          (type (parse-declarator tokscan decls :abstractp t))
70                          :eof)
71                      type))
72           (declare (ignore consumedp))
73           (if winp
74               (values t (car value) (cdr value)
75                       (princ-to-string (car value)))
76               (values nil value)))))))
77
78 (export 'test-parser)
79 (defmacro test-parser ((scanner &key backtrace) parser input)
80   "Convenient macro for testing parsers at the REPL.
81
82    This is a macro so that the parser can use the fancy syntax.  The name
83    SCANNER is bound to a `sod-token-scanner' reading tokens from the INPUT
84    string.  Then the PARSER is invoked and three values are returned: the
85    result of the parse, or `nil' if the main parse failed; a list containing
86    the number of errors and warnings (respectively) reported during the
87    parse; and a list consisting of the lookahead token type and value, and a
88    string containing the untokenized remaining input.
89
90    If BACKTRACE is nil (the default) then leave errors to the calling
91    environment to sort out (e.g., by entering the Lisp debugger); otherwise,
92    catch and report them as they happen so that you can test error recovery
93    strategies."
94   (once-only (input)
95     (with-gensyms (char-scanner value winp body consumedp where nerror nwarn)
96       `(let ((,char-scanner nil) (,scanner nil))
97          (with-parser-context (token-scanner-context :scanner ,scanner)
98            (multiple-value-bind (,value ,nerror ,nwarn)
99                (flet ((,body ()
100                         (setf ,char-scanner (make-string-scanner ,input)
101                               ,scanner (make-instance
102                                         'sod-token-scanner
103                                         :char-scanner ,char-scanner))
104                         (multiple-value-bind (,value ,winp ,consumedp)
105                             (parse ,parser)
106                           (declare (ignore ,consumedp))
107                           (cond (,winp ,value)
108                                 (t (syntax-error ,scanner ,value)
109                                    nil)))))
110                  (if ,backtrace (,body)
111                      (count-and-report-errors ()
112                        (with-default-error-location (,scanner)
113                          (,body)))))
114              (let ((,where (scanner-capture-place ,char-scanner)))
115                (values ,value
116                        (list ,nerror ,nwarn)
117                        (and ,scanner (list (token-type ,scanner)
118                                            (token-value ,scanner)
119                                            (subseq ,input ,where)))))))))))
120
121 ;;;--------------------------------------------------------------------------
122 ;;; Calisthenics.
123
124 (export 'exercise)
125 (defun exercise ()
126   "Exercise the pieces of the metaobject protocol.
127
128    In some Lisps, the compiler is run the first time methods are called, to
129    do fancy just-in-time optimization things.  This is great, only the
130    program doesn't actually run for very long and a lot of that work is
131    wasted because we're going to have to do it again next time the program
132    starts.  Only, if we exercise the various methods, or at least a large
133    fraction of them, before we dump an image, then everything will be fast.
134
135    That's the theory anyway.  Call this function before you dump an image and
136    see what happens."
137
138   (dolist (reason '(:h :c))
139     (with-output-to-string (bitbucket)
140       (output-module *builtin-module* reason bitbucket)))
141
142   (clear-the-decks))
143
144 ;;;--------------------------------------------------------------------------
145 ;;; Make sure things work after loading the system.
146
147 (clear-the-decks)
148
149 ;;;----- That's all, folks --------------------------------------------------