From 012554e1b6f02cd77028e5f2c463b11738fa2c59 Mon Sep 17 00:00:00 2001 Message-Id: <012554e1b6f02cd77028e5f2c463b11738fa2c59.1718429492.git.mdw@distorted.org.uk> From: Mark Wooding Date: Tue, 17 Nov 2015 20:27:44 +0000 Subject: [PATCH] src/lexer-*.lisp: Add option to `error' to ignore non-consuming failure. Organization: Straylight/Edgeware From: Mark Wooding Maybe you're using `error' somewhere where a totally missing thing is OK: the new :ignore-unconsumed option lets you tell it that this isn't a problem. --- src/lexer-impl.lisp | 22 +++++++++++++--------- src/lexer-proto.lisp | 12 +++++++++--- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/lexer-impl.lisp b/src/lexer-impl.lisp index ffc8446..7e953ef 100644 --- a/src/lexer-impl.lisp +++ b/src/lexer-impl.lisp @@ -59,17 +59,21 @@ (defun skip-until (scanner token-types &key keep-end) (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 diff --git a/src/lexer-proto.lisp b/src/lexer-proto.lisp index 7ed7924..d6d33cb 100644 --- a/src/lexer-proto.lisp +++ b/src/lexer-proto.lisp @@ -116,7 +116,8 @@ (defparse skip-until (:context (context token-scanner-context) (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 @@ -126,10 +127,15 @@ (defparse error (:context (context token-scanner-context) 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. -- [mdw]