Hash :
6349554f
Author :
Thomas de Grivel
Date :
2018-06-29T12:05:03
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
(in-package :parser-stream)
(defvar *buffer-size* 64)
(deftype token-vector (&optional (size '*))
`(array token (,size)))
(defclass item ()
((tokens :initform #()
:accessor item-tokens
:type (simple-array token (*)))))
(defgeneric item-character (item))
(defgeneric item-line (item))
(defgeneric item-token (item n))
(defmethod item-token ((item item) (n integer))
(declare (type fixnum n))
(svref (item-tokens item) n))
(defmethod item-line ((item item))
(token-stream:token-line (item-token item 0)))
(defmethod item-character ((item item))
(token-stream:token-character (item-token item 0)))
(defun make-buffer ()
(make-array `(,*buffer-size*)
:adjustable t
:element-type '(or null item)
:fill-pointer 0
:initial-element nil))
(defclass parser (super-stream input-stream)
((buffer :initform (make-buffer)
:accessor parser-buffer
:type token-vector)
(eof-p :initform nil
:accessor parser-eof-p
:type boolean)
(input-ended :initform nil
:accessor parser-input-ended
:type boolean)
(match-start :initform 0
:accessor parser-match-start
:type fixnum)
(stack :initform ()
:accessor parser-stack
:type list)))
(defgeneric parser-parse (parser))
(declaim (ftype (function (parser) token-vector) parser-buffer))
(declaim (ftype (function (parser) fixnum) parser-match-start))
(defmethod stream-element-type ((stream parser))
'item)
;; Input
(defmethod parser-push-extend ((pr parser) item)
(vector-push-extend item (parser-buffer pr) 64))
(defmethod parser-token ((pr parser) (index integer))
(declare (type fixnum index))
(let ((buf (parser-buffer pr)))
(when (< index (fill-pointer buf))
(aref buf index))))
(defmethod parser-input ((pr parser))
(let ((in (stream-underlying-stream pr)))
(multiple-value-bind (token state) (stream-read in)
(ecase state
((nil) (parser-push-extend pr token)
(values token nil))
((:eof) (setf (parser-input-ended pr) t)
(values nil :eof))
((:non-blocking)
(signal (make-condition 'non-blocking :stream pr)))))))
(defmethod parser-input-n ((pr parser) (n integer))
(declare (type fixnum n))
(loop
(let ((length (- (the fixnum (fill-pointer (parser-buffer pr)))
(parser-match-start pr))))
(declare (type fixnum length))
(unless (< length n)
(return t))
(when (parser-input-ended pr)
(return))
(parser-input pr))))
(defmethod parser-match-token ((pr parser) (index integer))
(declare (type fixnum index))
(when (parser-input-n pr (the fixnum (1+ index)))
(let ((buf (parser-buffer pr))
(match-index (+ (parser-match-start pr)
index)))
(declare (type fixnum match-index))
(aref buf match-index))))
;; Matcher
(defmethod match ((pr parser) (type symbol))
(let ((item (parser-match-token pr 0)))
(when (and item (subtypep (type-of item) (find-class type)))
(incf (parser-match-start pr))
item)))
(defmethod match-or ((pr parser) (types cons))
(loop
(when (endp types)
(return))
(let* ((type (pop types))
(token (match pr type)))
(when token
(return token)))))
(defmethod match-option ((pr parser) (f function))
(or (funcall f pr)
(parser-match-start pr)))
(defmethod match-not ((pr parser) (f function))
(let ((match-start (parser-match-start pr)))
(cond ((or (funcall f pr)
(parser-input-ended pr))
(setf (parser-match-start pr) match-start)
nil)
(t
(let ((token (parser-match-token pr 0)))
(when token
(incf (the fixnum (parser-match-start pr)))
token))))))
(defmacro match-sequence (parser &body body)
(let ((pr (gensym "PR-"))
(match-start (gensym "MATCH-START-"))
(result (gensym "RESULT-")))
`(let* ((,pr ,parser)
(,match-start (parser-match-start ,pr))
(,result (progn ,@body)))
(cond (,result
,result)
(t
(setf (parser-match-start ,pr) ,match-start)
nil)))))
(defmethod match-times ((pr parser) (f function) (min integer) (max integer))
(declare (type fixnum min max))
(match-sequence pr
(let ((n 0))
(loop
(unless (< n max)
(return (parser-match-start pr)))
(unless (funcall f pr)
(if (< n min)
(return nil)
(return (parser-match-start pr))))
(incf n)))))
(defmethod match-times ((pr parser) (f function) (min integer) (max null))
(declare (type fixnum min))
(match-sequence pr
(let ((n 0))
(declare (type fixnum n))
(loop
(unless (funcall f pr)
(if (< n min)
(return nil)
(return (parser-match-start pr))))
(incf n)))))
(defmethod stream-read ((pr parser))
(if (parser-eof-p pr)
(values nil :eof)
(handler-case (values (parser-parse pr) nil)
(end-of-file () (values nil :eof))
(non-blocking () (values nil :non-blocking)))))
;; Item stack
(defmethod parser-push ((pr parser))
(push (parser-match-start pr) (parser-stack pr)))
(defmethod parser-pop ((pr parser))
(assert (parser-stack pr))
(let* ((buffer (parser-buffer pr))
(fp (fill-pointer buffer))
(start (pop (parser-stack pr)))
(match-start (parser-match-start pr))
(tokens (subseq buffer start match-start))
(item (make-instance 'item :tokens tokens)))
(when (endp (parser-stack pr))
(replace buffer buffer :start2 match-start :end2 fp)
(setf (parser-match-start pr) 0
(fill-pointer (parser-buffer pr)) (- fp match-start)))
item))
(defmethod parser-discard ((pr parser))
(assert (parser-stack pr))
(let* ((buffer (parser-buffer pr))
(fp (fill-pointer buffer))
(match-start (parser-match-start pr)))
(pop (parser-stack pr))
(when (endp (parser-stack pr))
(replace buffer buffer :start2 match-start :end2 fp)
(setf (parser-match-start pr) 0
(fill-pointer buffer) (- fp match-start)))
nil))