(in-package #:monparser) (defclass parser-input () ((cursor :initarg :cursor :accessor input-cursor :initform 0) (data :initarg :data :reader input-data :initform nil))) (defun has-data? (input) (< (input-cursor input) (length (input-data input)))) (defun peek (input) (char (input-data input) (input-cursor input))) (defun advance (input) (make-instance 'parser-input :data (input-data input) :cursor (+ (input-cursor input) 1))) (defun line-and-column (input) (let ((line 1) (column 1)) (dotimes (i (input-cursor input)) (let ((c (char (input-data input) i))) (case c (#\Newline (incf line) (setf column 1)) (t (incf column))))) (values line column))) (defmethod print-object ((obj parser-input) stream) (let ((context-length 20)) (let ((begin (max (- (input-cursor obj) context-length) 0)) (end (min (+ (input-cursor obj) context-length) (length (input-data obj))))) (when (< 0 begin) (format stream "...")) (format stream "~a" (substitute #\↲ #\Newline (subseq (input-data obj) begin (input-cursor obj)))) (if (< (input-cursor obj) (length (input-data obj))) (format stream "~a~a" (substitute #\↲ #\Newline (subseq (input-data obj) (input-cursor obj) (1+ (input-cursor obj)))) (substitute #\↲ #\Newline (subseq (input-data obj) (1+ (input-cursor obj)) end))) (format stream "¬")) (when (< end (length (input-data obj))) (format stream "...")))))