(in-package #:monparser) (defclass input () ((cursor :initarg :cursor :accessor cursor :initform 0) (file :initarg :file :reader file :initform nil) (data :initarg :data :reader data :initform nil))) (defun has-data? (input) (< (cursor input) (length (data input)))) (defun prefix? (target input) (string= target (data input) :start2 (cursor input) :end2 (min (+ (cursor input) (length target)) (length (data input))))) (defun peek (input) (char (data input) (cursor input))) (defun advance (input &optional (amount 1)) (make-instance 'input :data (data input) :file (file input) :cursor (+ (cursor input) amount))) (defun input-sub (input1 input2) (- (cursor input1) (cursor input2))) (defun from-string (str) (make-instance 'input :data str)) (defun read-file (path) (with-open-file (file path) (let* ((size (file-length file)) (buf (make-string size))) (read-sequence buf file) buf))) (defun from-file (filename) (make-instance 'input :file filename :data (read-file filename))) (defun line-and-column (input) (let ((line 1) (column 1)) (dotimes (i (cursor input)) (let ((c (char (data input) i))) (case c (#\Newline (incf line) (setf column 1)) (t (incf column))))) (values line column)))