src/parser/parser-proto.lisp: Fix bogus indentation.
[sod] / src / parser / parser-proto.lisp
index d458e70..f7b5993 100644 (file)
@@ -7,7 +7,7 @@
 
 ;;;----- Licensing notice ---------------------------------------------------
 ;;;
-;;; This file is part of the Sensble Object Design, an object system for C.
+;;; This file is part of the Sensible Object Design, an object system for C.
 ;;;
 ;;; SOD is free software; you can redistribute it and/or modify
 ;;; it under the terms of the GNU General Public License as published by
@@ -77,6 +77,7 @@
 ;;;--------------------------------------------------------------------------
 ;;; Utilities.
 
+(export 'combine-parser-failures)
 (defun combine-parser-failures (failures)
   "Combine the failure indicators listed in FAILURES.
 
          failures
          :initial-value nil))
 
+(export 'parse-empty)
+(defun parse-empty (&optional value)
+  "Return a parser which parses nothing, successfully.
+
+   The parser returns VALUE and consumes nothing."
+  (lambda () (values value t nil)))
+
+(export 'parse-fail)
+(defun parse-fail (indicator &optional consumedp)
+  "Return a parser which fails.
+
+   The parser reports the INDICATOR and (falsely) claims to have consumed
+   input if CONSUMEDP is true."
+  (lambda () (values indicator nil consumedp)))
+
 ;;;--------------------------------------------------------------------------
 ;;; Basic protocol.
 
             ((,context ,ctxclass) (,head (eql ',name)) ,tail)
           ,@doc
           (declare (ignorable ,context))
-          (block ,name
-            (destructuring-bind ,bvl ,tail
-              ,@decls
-              ,@body)))))))
+          (destructuring-bind ,bvl ,tail
+            ,@decls
+            (block ,name ,@body)))))))
 
 (export '(with-parser-context parse))
 (defmacro with-parser-context ((class &rest initargs) &body body)
    If a parser with the given TAG is already attached to SYMBOL then the new
    parser replaces the old one; otherwise it is added to the collection."
 
-  `(pluggable-parser-add ',symbol ',tag (lambda ,bvl ,@body)))
+  (multiple-value-bind (docs decls body) (parse-body body)
+    `(pluggable-parser-add ',symbol ',tag
+                          (lambda ,bvl
+                            ,@docs ,@decls
+                            (block ,symbol ,@body)))))
 
 ;;;--------------------------------------------------------------------------
 ;;; Rewindable parser context protocol.
    The return value may later be used with `parser-restore-place'.  Be
    careful: all of this is happening at macro-expansion time.")
     (:method (context)
-      (error "Parser context ~S doesn't support rewinding." context)))
+      (error "Parser context ~S doesn't support rewinding" context)))
 
   (export 'parser-restore-place)
   (defgeneric parser-restore-place (context place)
           `(let ((,,place ,(parser-capture-place ,context)))
              ,(if (parser-places-must-be-released-p ,context)
                   `(unwind-protect ,(,bodyfunc)
-                       ,(parser-release-place ,context ,place))
+                     (when ,,place
+                       ,(parser-release-place ,context ,place)))
                   (,bodyfunc))))))))
 
 (export 'peek)
   "Attempt to run PARSER, but rewind the underlying source if it fails."
   (with-gensyms (value win consumedp)
     (with-parser-place (place context)
-      `(multiple-value-bind (,value ,win ,consumedp) (parse ,parser)
-        (cond (,win
-               (values ,value ,win ,consumedp))
-              (t
-               ,(parser-restore-place context place)
-               (values ,value ,win nil)))))))
+      `(macrolet ((commit-peeked-place ()
+                   `(progn
+                      ,',(parser-release-place context place)
+                      (setf ,',place nil))))
+        (multiple-value-bind (,value ,win ,consumedp) (parse ,parser)
+          (cond ((or ,win (null ,place))
+                 (values ,value ,win ,consumedp))
+                (t
+                 ,(parser-restore-place context place)
+                 (values ,value ,win nil))))))))
+
+(defun commit-peeked-place ()
+  "Called by `commit' not lexically within `peek'."
+  (error "`commit' is not within `peek'"))
+
+(export 'commit)
+(defparse commit ()
+  "Commit to the current parse.
+
+   This releases the place captured by the innermost lexically enclosing
+  `peek'."
+  '(progn
+     (commit-peeked-place)
+     (values nil t nil)))
 
 ;;;--------------------------------------------------------------------------
 ;;; Character parser context protocol.
    "Return the parser's current token's semantic value."))
 
 (export 'token)
-(defparse token (:context (context token-parser-context)
-                type &optional (value nil valuep) &key peekp)
-  "Match tokens of a particular type.
+(locally  (declare #+sbcl (sb-ext:muffle-conditions style-warning))
+  (defparse token (:context (context token-parser-context)
+                           type &optional (value nil valuep) &key peekp)
+    "Match tokens of a particular type.
 
    A token matches under the following conditions:
 
    If the match fails then the failure indicator is either TYPE or (TYPE
    VALUE), depending on whether a VALUE was specified."
 
-  (once-only (type value peekp)
-    (with-gensyms (tokty tokval)
-      `(let ((,tokty ,(parser-token-type context))
-            (,tokval ,(parser-token-value context)))
-        (if ,(if (eq type t)
-                 `(not (eq ,tokty :eof))
-                 (flet ((check-value (cond)
-                          (if valuep
-                              `(and ,cond (equal ,tokval ,value))
-                              cond)))
-                   (if (constantp type)
-                       (check-value `(eql ,tokty ,type))
-                       `(if (eq ,type t)
-                            (not (eq ,tokty :eof))
-                            ,(check-value `(eql ,tokty ,type))))))
-            ,(let* ((result `(values ,tokval t ,(if (constantp peekp)
-                                                    (not peekp)
-                                                    `(not ,peekp))))
-                    (step (parser-step context)))
-                   (cond ((not (constantp peekp))
-                          `(multiple-value-prog1 ,result
-                             (unless ,peekp ,step)))
-                         (peekp
-                          result)
-                         (t
-                          `(multiple-value-prog1 ,result
-                             ,step))))
-            (values (list ,(if valuep `(list ,type ,value) type))
-                    nil nil))))))
+    (once-only (type value peekp)
+      (with-gensyms (tokty tokval)
+       `(let ((,tokty ,(parser-token-type context))
+              (,tokval ,(parser-token-value context)))
+          (if ,(if (eq type t)
+                   `(not (eq ,tokty :eof))
+                   (flet ((check-value (cond)
+                            (if valuep
+                                `(and ,cond (equal ,tokval ,value))
+                                cond)))
+                     (if (constantp type)
+                         (check-value `(eql ,tokty ,type))
+                         `(if (eq ,type t)
+                              (not (eq ,tokty :eof))
+                              ,(check-value `(eql ,tokty ,type))))))
+              ,(let* ((result `(values ,tokval t ,(if (constantp peekp)
+                                                      (not peekp)
+                                                      `(not ,peekp))))
+                      (step (parser-step context)))
+                 (cond ((not (constantp peekp))
+                        `(multiple-value-prog1 ,result
+                           (unless ,peekp ,step)))
+                       (peekp
+                        result)
+                       (t
+                        `(multiple-value-prog1 ,result
+                           ,step))))
+              (values (list ,(if valuep `(list ,type ,value) type))
+                      nil nil)))))))
 
 (defmethod expand-parser-spec ((context token-parser-context) spec)
   (if (atom spec)