X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/aa14a4cddcb96b681d5c19a2ec8bad382f43b264..2b8759bf0239b0a98ac830952ed69572580826c1:/src/parser/parser-proto.lisp diff --git a/src/parser/parser-proto.lisp b/src/parser/parser-proto.lisp index 5a10b77..189e503 100644 --- a/src/parser/parser-proto.lisp +++ b/src/parser/parser-proto.lisp @@ -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. @@ -103,13 +104,16 @@ (:documentation "Expand a parser list-form given by HEAD and TAIL, in CONTEXT.") (:method (context head tail) + (declare (ignore context)) (cons head tail))) (export 'wrap-parser) (defgeneric wrap-parser (context form) (:documentation "Enclose FORM in whatever is necessary to make the parser work.") - (:method (context form) form))) + (:method (context form) + (declare (ignore context)) + form))) (export 'defparse) (defmacro defparse (name bvl &body body) @@ -124,10 +128,6 @@ body FORMs. The BVL is a destructuring lambda-list to be applied to the tail of the form. The body forms are enclosed in a block called NAME. - Within the FORMs, a function `expand' is available: it takes a parser - specifier as its argument and returns its expansion in the parser's - context. - If the :context key is provided, then the parser form is specialized on a particular class of parser contexts SPEC; specialized expanders take priority over less specialized or unspecialized expanders -- so you can @@ -151,10 +151,10 @@ `(defmethod expand-parser-form ((,context ,ctxclass) (,head (eql ',name)) ,tail) ,@doc - (block ,name - (destructuring-bind ,bvl ,tail - ,@decls - ,@body))))))) + (declare (ignorable ,context)) + (destructuring-bind ,bvl ,tail + ,@decls + (block ,name ,@body))))))) (export '(with-parser-context parse)) (defmacro with-parser-context ((class &rest initargs) &body body) @@ -335,10 +335,12 @@ (defmethod expand-parser-spec (context (spec (eql t))) "Always matches without consuming input." + (declare (ignore context)) '(values t t nil)) (defmethod expand-parser-spec (context (spec (eql nil))) "Always fails without consuming input. The failure indicator is `:fail'." + (declare (ignore context)) '(values '(:fail) nil nil)) (export 'seq) @@ -457,8 +459,7 @@ (,func (lambda (,new) (declare (ignorable ,new)) (setf ,accvar ,update)) - (lambda () - ,final) + (lambda () ,final) (parser () ,parser) ,@(and sepp (list `(parser () ,sep))) ,@(and minp `(:min ,min)) @@ -467,14 +468,14 @@ (export 'list) (defparse list ((&rest keys) parser &optional (sep nil sepp)) - "Like MANY, but simply returns a list of the parser results." + "Like `many', but simply returns a list of the parser results." (with-gensyms (acc) `(parse (many (,acc nil (cons it ,acc) :final (nreverse ,acc) ,@keys) ,parser ,@(and sepp (list sep)))))) (export 'skip-many) (defparse skip-many ((&rest keys) parser &optional (sep nil sepp)) - "Like MANY, but ignores the results." + "Like `many', but ignores the results." `(parse (many (nil nil nil ,@keys) ,parser ,@(and sepp (list sep))))) @@ -571,7 +572,11 @@ 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. @@ -605,7 +610,9 @@ underlying scanner can use this call to determine whether there are outstanding captured places, and thereby optimize its behaviour. Be careful: all of this is happening at macro-expansion time.") - (:method (context place) nil)) + (:method (context place) + (declare (ignore context place)) + nil)) (export 'parser-places-must-be-released-p) (defgeneric parser-places-must-be-released-p (context) @@ -620,7 +627,9 @@ the correct cleanup. If it returns false, then the `unwind-protect' is omitted so that the runtime code does't have to register cleanup handlers.") - (:method (context) t))) + (:method (context) + (declare (ignore context)) + t))) (export 'with-parser-place) (defmacro with-parser-place ((place context) &body body) @@ -637,7 +646,8 @@ `(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) @@ -645,12 +655,30 @@ "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. @@ -843,7 +871,7 @@ A token matches under the following conditions: * If the value of TYPE is `t' then the match succeeds if and only if the - parser it not at end-of-file. + parser is not at end-of-file. * If the value of TYPE is not `eql' to the token type then the match fails.