chiark / gitweb /
src/final.lisp: Add convenient macro for testing parsers at the REPL.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 10 Jan 2016 13:51:04 +0000 (13:51 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 29 May 2016 13:40:40 +0000 (14:40 +0100)
Nothing especially awesome.

doc/SYMBOLS
doc/misc.tex
src/final.lisp

index d9587ee34b1e0b37939e1531aa7b224f1559bf7f..59df7630053a26128effe370db06565c84f539bc 100644 (file)
@@ -408,6 +408,7 @@ final.lisp
   *sod-version*                                 variable
   exercise                                      function
   test-module                                   function
+  test-parser                                   macro
 
 fragment-parse.lisp
   parse-delimited-fragment                      function
index 8c8b9c17f03599457b23c5905ce837f1a23430a1..06791f4e99f41ed49255e86773ebeb9b99a80b22 100644 (file)
@@ -533,6 +533,11 @@ These symbols are defined in the @!optparse| package.
 \begin{describe}{fun}{test-module @<path> @<reason>}
 \end{describe}
 
+\begin{describe}{mac}
+    {test-parser (@<scanner>) @<parser> @<input>
+      @> @<success-flag> @<result> @<remainder>}
+\end{describe}
+
 \begin{describe}{fun}{exercise}
 \end{describe}
 
index 7d4468e68b2a61454ace5950820bc901ddafaf2b..071ebc9b056bd15afecbb03259c66310c57f095c 100644 (file)
@@ -50,6 +50,31 @@ (defun test-module (path reason)
                   :if-does-not-exist :create)
     (output-module (read-module path) reason out)))
 
+(export 'test-parser)
+(defmacro test-parser ((scanner &key) parser input)
+  "Convenient macro for testing parsers at the REPL.
+
+   This is a macro so that the parser can use the fancy syntax.  The name
+   SCANNER is bound to a `sod-token-scanner' reading tokens from the INPUT
+   string.  Then the PARSER is invoked and three values are returned: a
+   `successp' flag indicating whether the parser succeeded; the result,
+   output or error indicator, of the parser; and a list consisting of the
+   lookahead token type and value, and a string containing the untokenized
+   remaining input."
+  (once-only (input)
+    (with-gensyms (char-scanner value winp consumedp where)
+      `(let* ((,char-scanner (make-string-scanner ,input))
+             (,scanner (make-instance 'sod-token-scanner
+                                      :char-scanner ,char-scanner
+                                      :filename "<test-input>")))
+        (with-parser-context (token-scanner-context :scanner ,scanner)
+          (multiple-value-bind (,value ,winp ,consumedp) (parse ,parser)
+            (declare (ignore ,consumedp))
+            (let ((,where (scanner-capture-place ,char-scanner)))
+              (values ,winp ,value
+                      (list (token-type ,scanner) (token-value ,scanner)
+                            (subseq ,input ,where))))))))))
+
 ;;;--------------------------------------------------------------------------
 ;;; Calisthenics.