(return (values token-types nil consumedp)))
(scanner-step scanner)))
-(defun parse-error-recover (scanner parser recover)
+(defun parse-error-recover (scanner parser recover &key ignore-unconsumed)
"This is the implementation of the `error' parser."
(multiple-value-bind (result win consumedp) (funcall parser)
- (cond ((or win (and (not consumedp) (scanner-at-eof-p scanner)))
- ;; If we succeeded then there's nothing for us to do here. On the
- ;; other hand, if we failed, didn't consume any tokens, and we're
- ;; at end-of-file, then there's not much hope of making onward
- ;; progress, so in this case we propagate the failure rather than
- ;; trying to recover. And we assume that the continuation will
- ;; somehow arrange to report the problem, and avoid inundating the
- ;; user with error reports.
+ (cond ((or win
+ (and (not consumedp)
+ (or ignore-unconsumed
+ (scanner-at-eof-p scanner))))
+ ;; If we succeeded, or if we didn't consume any tokens and the
+ ;; caller's OK with that, then there's nothing for us to do here.
+ ;; On the other hand, if we failed, didn't consume any tokens, and
+ ;; we're at end-of-file, then there's not much hope of making
+ ;; onward progress, so in this case we propagate the failure
+ ;; rather than trying to recover. And we assume that the
+ ;; continuation will somehow arrange to report the problem, and
+ ;; avoid inundating the user with error reports.
(values result win consumedp))
(t
;; Now we have to do some kind of sensible error recovery. The
(export 'error)
(defparse error (:context (context token-scanner-context)
- (&key) sub &optional (recover t))
+ (&key ignore-unconsumed)
+ sub &optional (recover t))
"Try to parse SUB; if it fails then report an error, and parse RECOVER.
This is the main way to recover from errors and continue parsing. Even
were never here. Otherwise, try to recover in a sensible way so we can
continue parsing. The details of this recovery are subject to change, but
the final action is generally to invoke the RECOVER parser and return its
- result."
+ result.
+
+ If IGNORE-UNCONSUMED evaluates non-nil, then just propagate a failure of
+ SUB if it didn't consume input. (This makes it suitable for use where the
+ parser containing `error' might be optional.)"
`(parse-error-recover ,(parser-scanner context)
(parser () ,sub)
- (parser () ,recover)))
+ (parser () ,recover)
+ :ignore-unconsumed ,ignore-unconsumed))
;;;--------------------------------------------------------------------------
;;; Lexical analysis utilities.