diff options
Diffstat (limited to 'core.lisp')
-rw-r--r-- | core.lisp | 62 |
1 files changed, 28 insertions, 34 deletions
@@ -1,17 +1,8 @@ (in-package #:monparser) -(defun opposite (p) - (lambda (input &key lazy) - (let ((result (funcall p input))) - (cond ((parsing-p result) - (make-failure :place input :message "Unexpected match.")) - ((failure-p result) - (make-parsing :tree nil :left input)) - (t (error "Unexpected result type.")))))) - -(defun fail (message) - (lambda (input &key lazy) - (make-failure :place input :message message))) +(defun fail (message &key (priority 1)) + (lambda (input) + (make-failure :place input :message message :priority priority))) (defmacro unit (&optional predicate) (cond ((null predicate) @@ -29,44 +20,47 @@ (and (symbolp x) (string-equal (symbol-name x) "IT"))) predicate)))) (t (error (format nil "Invalid predicate: ~a." predicate)))) - `(lambda (input &key lazy) - (declare (ignore lazy)) + `(lambda (input) (if (has-data? input) (let ((it (peek input))) (if ,predicate (make-parsing :tree it :left (advance input)) (make-failure :place input - :message (format nil "Expected: ~a, Got: ~a" ',predicate it)))) + :message (format nil "Expected: ~a, Got: ~:c." ',predicate it)))) (make-failure :place input - :message (format nil "Reached end of input. Expected: ~a" ',predicate))))) + :message (format nil "Reached end of input. Expected: ~a." ',predicate))))) + +(defparameter end + (lambda (input) + (if (has-data? input) + (make-failure :place input :message "Didn't reach end of input.") + (make-parsing :tree nil :left input)))) -(defun lazily-select-parser (input parsers) - (let ((intermediate-parsers '()) - (result (make-failure :place input - :message "Exhausted options."))) +(defun select-parser (input parsers) + (let ((result (make-failure :place input))) (dolist (p parsers) - (let ((r (funcall p - input - :lazy (> (length parsers) 1)))) - (cond ((functionp r) - (push r intermediate-parsers)) - ((parsing-p r) + (let ((r (funcall p input))) + (cond ((parsing-p r) (when (or (not (parsing-p result)) (> (input-cursor (parsing-left r)) (input-cursor (parsing-left result)))) (setf result r))) ((failure-p r) (when (failure-p result) - (setf result r))) - (t (error (format nil "Invalid return value: ~a" r)))))) - (if intermediate-parsers - (lazily-select-parser input intermediate-parsers) - result))) + (let ((priority-cmp (- (failure-priority r) + (failure-priority result)))) + (when (or (> priority-cmp 0) + (and (= priority-cmp 0) + (>= (input-cursor (failure-place r)) + (input-cursor (failure-place result))))) + (setf result r))))) + (t (error (format nil "Invalid return value: ~a." r)))))) + result)) (defmacro one-of (first-parser second-parser &rest other-parsers) - `(lambda (input &key lazy) - (declare (ignore lazy)) - (lazily-select-parser input (list ,first-parser ,second-parser ,@other-parsers)))) + `(lambda (input) + (select-parser input + (list ,first-parser ,second-parser ,@other-parsers)))) ;;; TODO: Find a way to be able to use the input without needing to define a name for it. (defmacro comp (bindings &body body) |