"lispier" regexps, l*last-child stuff
Annotate for file selectors.lisp
2009-11-18 pix 1 (in-package #:oh-ducks)
2009-11-15 pix 2
2009-12-05 pix 3 (defvar *implicit-element* nil
07:18:05 ' 4 "The element to be considered as an implicit element to be matched by combinators without a leading qualifier. E.g., \"> a\" will match <a> tags directly under *implicit-element*, and \"+ a\" will match <a> tags directly following *implicit-element*.")
2009-12-04 pix 5
2009-11-15 pix 6 #.(set-dispatch-macro-character #\# #\T 'unify::|sharp-T-reader|)
14:25:29 ' 7
' 8 (defclass selector (unify::string-template)
' 9 ((matcher :reader matcher :initarg :matcher)))
' 10
' 11 (defgeneric selector-p (object)
' 12 (:method ((ob selector)) t)
' 13 (:method ((ob t)) nil))
' 14
2009-11-16 pix 15 (defclass simple-selector (selector)
2009-11-15 pix 16 ((arg :reader selector-arg :initarg :arg)))
14:25:29 ' 17
' 18 (defmethod print-object ((selector simple-selector) stream)
' 19 (format stream "#<selector ~s>" (selector-arg selector)))
' 20
' 21 (defclass combinator (selector) ())
2009-11-16 pix 22
08:14:42 ' 23 (defgeneric combinator-p (object)
' 24 (:method ((ob combinator)) t)
' 25 (:method ((ob t)) nil))
' 26
' 27 (defmethod print-object ((selector combinator) stream)
2009-11-21 pix 28 (format stream "#<~s ~s>" (class-name (class-of selector)) (matcher selector)))
2009-11-16 pix 29
2009-11-15 pix 30 (defclass child-combinator (combinator) ())
14:25:29 ' 31 (defclass descendant-combinator (combinator) ())
' 32 (defclass adjacent-combinator (combinator) ())
' 33 (defclass sibling-combinator (combinator) ())
' 34
2009-11-16 pix 35 (defclass universal-selector (simple-selector) ())
2009-11-15 pix 36 (defclass type-selector (simple-selector) ())
14:25:29 ' 37 (defclass id-selector (simple-selector) ())
' 38 (defclass class-selector (simple-selector) ())
2009-11-23 pix 39 (defclass nth-child-selector (simple-selector) ())
2009-11-30 pix 40 (defclass nth-last-child-selector (nth-child-selector) ())
2009-11-23 pix 41
2010-01-04 pix 42 (defmethod initialize-instance :after ((selector nth-child-selector)
05:59:48 ' 43 &key (asign "+") a
' 44 (bsign "+") b
' 45 namedp)
' 46 (setf (slot-value selector 'arg)
' 47 (if namedp
' 48 (cons 2 (if (string-equal "odd" b) 1 0))
' 49 (cons (parse-integer (format nil "~a~a" asign (or a 1)))
' 50 (parse-integer (format nil "~a~a" bsign (or b 0)))))))
' 51
2009-11-23 pix 52 (defmethod print-object ((selector universal-selector) stream)
11:33:15 ' 53 (format stream "#<universal-selector>"))
2009-11-15 pix 54
2009-11-16 pix 55 (defmethod initialize-instance :after ((template combinator) &key)
2009-11-15 pix 56 (unless (slot-boundp template 'matcher)
14:25:29 ' 57 (let ((selector (template-spec template)))
' 58 (setf (slot-value template 'matcher) (parse-selector (string-trim " " selector))))))
' 59
2009-12-05 pix 60 (defclass %implicit-element-selector (selector) ())
07:18:05 ' 61 (defparameter %implicit-element-selector (make-instance '%implicit-element-selector))
2009-12-04 pix 62
2009-12-05 pix 63 (defmethod print-object ((selector %implicit-element-selector) stream)
2009-12-04 pix 64 (print-unreadable-object (selector stream :type t)))
04:47:58 ' 65
2010-01-04 pix 66 (cl-ppcre:define-parse-tree-synonym \s*
05:59:48 ' 67 (:non-greedy-repetition 0 nil :whitespace-char-class))
' 68 (cl-ppcre:define-parse-tree-synonym \s+
' 69 (:greedy-repetition 1 nil :whitespace-char-class))
' 70 (cl-ppcre:define-parse-tree-synonym sign
' 71 (:char-class #\+ #\-))
' 72 (cl-ppcre:define-parse-tree-synonym sign?
' 73 (:greedy-repetition 0 1 sign))
' 74 (cl-ppcre:define-parse-tree-synonym integer
' 75 (:greedy-repetition 1 nil :digit-class))
' 76 (cl-ppcre:define-parse-tree-synonym name
' 77 (:greedy-repetition 1 nil (:char-class :word-char-class #\-)))
' 78 (cl-ppcre:define-parse-tree-synonym $name
' 79 (:register name))
' 80 (cl-ppcre:define-parse-tree-synonym an+b
' 81 (:sequence
' 82 (:register sign?) (:greedy-repetition 0 1 (:register integer))
' 83 #\n \s*
' 84 (:register sign?) \s* (:greedy-repetition 0 1 (:register integer))))
' 85 (cl-ppcre:define-parse-tree-synonym b
' 86 (:register (:sequence sign? integer)))
' 87 (cl-ppcre:define-parse-tree-synonym odd/even
' 88 (:register (:alternation "odd" "even")))
' 89
2010-01-02 pix 90 ;; FIXME: proper parsing (e.g., by using the W3C's provided FLEX and YACC bits).
2009-11-15 pix 91 (defun parse-selector (selector)
14:25:29 ' 92 (match-case (selector)
' 93 ;; combinators
2010-01-04 pix 94 (#T(regexp$ (\s* #\~ \s*) ())
2009-12-05 pix 95 (list (make-instance 'sibling-combinator :matcher (or (parse-selector &rest) %implicit-element-selector))))
2010-01-04 pix 96 (#T(regexp$ (\s* #\+ \s*) ())
2009-12-05 pix 97 (list (make-instance 'adjacent-combinator :matcher (or (parse-selector &rest) %implicit-element-selector))))
2010-01-04 pix 98 (#T(regexp$ (\s* #\> \s*) ())
2009-12-05 pix 99 (list (make-instance 'child-combinator :matcher (or (parse-selector &rest) %implicit-element-selector))))
2010-01-04 pix 100 (#T(regexp$ (\s+) ())
2009-12-05 pix 101 (list (make-instance 'descendant-combinator :matcher (or (parse-selector &rest) %implicit-element-selector))))
2009-11-23 pix 102 ;; simple selectors
2009-11-30 pix 103 ;; cyclic (An+B, n+B)
2010-01-04 pix 104 (#T(regexp$ (":nth-child(" \s* an+b \s* ")")
05:59:48 ' 105 (?asign ?a ?bsign ?b))
2009-11-30 pix 106 (cons (make-instance 'nth-child-selector
2010-01-04 pix 107 :asign asign :a a
05:59:48 ' 108 :bsign bsign :b b)
' 109 (parse-selector &rest)))
' 110 (#T(regexp$ (":nth-last-child(" \s* an+b \s* ")")
' 111 (?asign ?a ?bsign ?b))
' 112 (cons (make-instance 'nth-last-child-selector
' 113 :asign asign :a a
' 114 :bsign bsign :b b)
2009-11-30 pix 115 (parse-selector &rest)))
04:48:22 ' 116 ;; absolute (B)
2010-01-04 pix 117 (#T(regexp$ (":nth-child(" \s* b \s* ")")
05:59:48 ' 118 (?b))
' 119 (cons (make-instance 'nth-child-selector :a 0 :b b)
' 120 (parse-selector &rest)))
' 121 (#T(regexp$ (":nth-last-child(" \s* b \s* ")")
' 122 (?b))
' 123 (cons (make-instance 'nth-last-child-selector :a 0 :b b)
' 124 (parse-selector &rest)))
2009-11-30 pix 125 ;; named (odd, even)
2010-01-04 pix 126 (#T(regexp$ (":nth-child(" \s* odd/even \s* ")")
05:59:48 ' 127 (?which))
' 128 (cons (make-instance 'nth-child-selector :namedp t :b which)
' 129 (parse-selector &rest)))
' 130 (#T(regexp$ (":nth-last-child(" \s* odd/even \s* ")")
' 131 (?which))
' 132 (cons (make-instance 'nth-last-child-selector :namedp t :b which)
2009-11-30 pix 133 (parse-selector &rest)))
2010-01-04 pix 134 ;; Everybody else
05:59:48 ' 135 (#T(regexp$ (":first-child") ())
' 136 (cons (make-instance 'nth-child-selector :a 0 :b 1)
' 137 (parse-selector &rest)))
' 138 (#T(regexp$ (":last-child") ())
' 139 (cons (make-instance 'nth-last-child-selector :a 0 :b 1)
' 140 (parse-selector &rest)))
' 141 (#T(regexp$ (":only-child") ())
' 142 (list* (make-instance 'nth-child-selector :a 0 :b 1)
' 143 (make-instance 'nth-last-child-selector :a 0 :b 1)
' 144 (parse-selector &rest)))
' 145 (#T(regexp$ (#\# $name) (?id))
2009-11-23 pix 146 (cons (make-instance 'id-selector :arg id) (parse-selector &rest)))
2010-01-04 pix 147 (#T(regexp$ (#\. $name) (?class))
2009-11-23 pix 148 (cons (make-instance 'class-selector :arg class) (parse-selector &rest)))
2010-01-04 pix 149 (#T(regexp$ ($name) (?type))
2009-11-23 pix 150 (cons (make-instance 'type-selector :arg type) (parse-selector &rest)))
2010-01-04 pix 151 (#T(regexp$ (#\*) ())
2009-11-23 pix 152 (cons (make-instance 'universal-selector) (parse-selector &rest)))
13:14:00 ' 153 (t (unless (string= selector "")
' 154 (error "Unable to to parse selector: ~s" selector)))))
2009-11-15 pix 155
2010-01-04 pix 156 (defun subjects-in-list (selector element-list)
2009-12-05 pix 157 (reduce #'nconc
2010-01-04 pix 158 (mapcar (curry #'subjects-of selector)
2009-12-05 pix 159 element-list)))
07:18:05 ' 160
2010-01-04 pix 161 (defun subjects-of (selector element)
01:03:10 ' 162 (nconc
2010-01-04 pix 163 (when (subject-p selector element) (list element))
2010-01-04 pix 164 (subjects-in-list selector (element-children element))))
2009-11-15 pix 165
2010-01-04 pix 166 (defgeneric subject-p (selector element))
2009-11-15 pix 167
2010-01-04 pix 168 (defmethod subject-p ((selector type-selector) element)
2009-11-15 pix 169 (element-type-equal element (selector-arg selector)))
14:25:29 ' 170
2010-01-04 pix 171 (defmethod subject-p ((selector id-selector) element)
2009-11-15 pix 172 (string= (element-id element) (selector-arg selector)))
14:25:29 ' 173
2010-01-04 pix 174 (defun an+b? (a b element siblings)
05:59:48 ' 175 (when-let* ((pos (1+ (position element siblings :test #'eq))))
' 176 ;; pos = An + B
' 177 (cond
' 178 ;; pos = 0n + B
' 179 ((= 0 a) (= b pos))
' 180 ;; (pos - B)/A = n
' 181 (t (and (zerop (mod (- pos b) a))
' 182 (not (minusp (/ (- pos b) a))))))))
' 183
2010-01-04 pix 184 (defmethod subject-p ((selector nth-child-selector) element)
2010-01-04 pix 185 (when-let* ((arg (selector-arg selector))
05:59:48 ' 186 (parent (element-parent element)))
' 187 (an+b? (car arg) (cdr arg) element (element-children parent))))
' 188
' 189 (defmethod subject-p ((selector nth-last-child-selector) element)
' 190 (when-let* ((arg (selector-arg selector))
' 191 (parent (element-parent element)))
' 192 (an+b? (car arg) (cdr arg) element (reverse (element-children parent)))))
2009-11-23 pix 193
2010-01-04 pix 194 (defmethod subject-p ((selector class-selector) element)
2009-11-15 pix 195 (member (selector-arg selector)
2010-01-04 pix 196 (element-classes element)
05:59:48 ' 197 :test #'string=))
2009-11-15 pix 198
2010-01-04 pix 199 (defmethod subject-p ((selector universal-selector) element)
2009-12-03 pix 200 (declare (ignore element selector))
2009-11-19 pix 201 t)
06:25:36 ' 202
2010-01-04 pix 203 (defmethod subject-p ((selector %implicit-element-selector) element)
2009-12-05 pix 204 (eq element *implicit-element*))
2009-12-04 pix 205
2010-01-04 pix 206 (defmethod subject-p ((selector list) element)
01:07:02 ' 207 (every (rcurry #'subject-p element) selector))
2009-11-16 pix 208
2010-01-04 pix 209 (defmethod subject-p ((selector child-combinator) element)
01:07:02 ' 210 (subject-p (matcher selector) (element-parent element)))
2009-11-16 pix 211
2010-01-04 pix 212 (defmethod subject-p ((selector descendant-combinator) element)
01:07:02 ' 213 (some (curry #'subject-p (matcher selector)) (element-ancestors element)))
2009-11-19 pix 214
2010-01-04 pix 215 (defmethod subject-p ((selector adjacent-combinator) element)
2009-12-03 pix 216 (let* ((parent (element-parent element))
00:12:02 ' 217 (siblings (element-children parent))
' 218 (ourpos (position element siblings :test #'eq)))
' 219 (and ourpos
' 220 (> ourpos 0)
2010-01-04 pix 221 (subject-p (matcher selector) (elt siblings (1- ourpos))))))
2009-11-19 pix 222
2010-01-04 pix 223 (defmethod subject-p ((selector sibling-combinator) element)
2009-12-03 pix 224 (let* ((parent (element-parent element))
00:12:02 ' 225 (siblings (element-children parent))
' 226 (ourpos (position element siblings :test #'eq)))
' 227 (and ourpos
' 228 (> ourpos 0)
2010-01-04 pix 229 (find-if (curry #'subject-p (matcher selector)) siblings :end ourpos))))
2009-12-05 pix 230
07:18:05 ' 231 ;; Hello excessively long name
' 232 (defun terminating-implicit-sibling-combinator-p (selector)
' 233 (typecase selector
' 234 ((or sibling-combinator adjacent-combinator)
' 235 (typecase (matcher selector)
' 236 (%implicit-element-selector t)
' 237 (list (terminating-implicit-sibling-combinator-p (car (last (matcher selector)))))))
' 238 (combinator (terminating-implicit-sibling-combinator-p (matcher selector)))
' 239 (selector nil)
' 240 (null nil)
' 241 (list (terminating-implicit-sibling-combinator-p (car (last selector))))
' 242 (t nil)))