(in-package #:input) (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 (1+ (cursor input)))) (defun from-string (str) (make-instance 'input :data str)) (defun from-file (filename) (make-instance 'input :file filename :data (str: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)))