From 3e21ae3fa660b188bc20caec8c96c1f678405c25 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Sun, 10 Jan 2016 13:51:04 +0000 Subject: [PATCH] src/final.lisp: Add convenient macro for testing parsers at the REPL. Nothing especially awesome. --- doc/SYMBOLS | 1 + doc/misc.tex | 5 +++++ src/final.lisp | 25 +++++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/doc/SYMBOLS b/doc/SYMBOLS index d9587ee..59df763 100644 --- a/doc/SYMBOLS +++ b/doc/SYMBOLS @@ -408,6 +408,7 @@ final.lisp *sod-version* variable exercise function test-module function + test-parser macro fragment-parse.lisp parse-delimited-fragment function diff --git a/doc/misc.tex b/doc/misc.tex index 8c8b9c1..06791f4 100644 --- a/doc/misc.tex +++ b/doc/misc.tex @@ -533,6 +533,11 @@ These symbols are defined in the @!optparse| package. \begin{describe}{fun}{test-module @ @} \end{describe} +\begin{describe}{mac} + {test-parser (@) @ @ + @> @ @ @} +\end{describe} + \begin{describe}{fun}{exercise} \end{describe} diff --git a/src/final.lisp b/src/final.lisp index 7d4468e..071ebc9 100644 --- a/src/final.lisp +++ b/src/final.lisp @@ -50,6 +50,31 @@ :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 ""))) + (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. -- 2.11.0