1 ;;;; optima-extensions.lisp --- Necessary extensions of the optima library.
3 ;;;; Copyright (C) 2014 Jan Moringen
5 ;;;; Author: Jan Moringen <jmoringe@techfak.uni-bielefeld.de>
7 (cl:in-package #:pattern-specializer)
11 (defgeneric pattern-more-specific-p (pattern1 pattern2)
13 "Return true if PATTERN1 is strictly more specific than
18 * Constant pattern are more specific than all other patterns
20 * Variable patterns are less specific than all other patterns
22 * For most complex patterns, subpatterns are compared
23 lexicographically. Exceptions:
25 * For `class-pattern' s, subclass relations have higher
26 precedence. The above rule applies only when the classes are
29 * `and-pattern's are comparable to all patterns by checking
30 whether some of their subpatterns are more specific than the
33 * `or-pattern's are similar."))
35 (defun subpatterns-unrestricted-p (pattern)
36 (every (of-type 'optima.core:variable-pattern)
37 (optima.core:complex-pattern-subpatterns pattern)))
41 (defmethod pattern-more-specific-p :around ((pattern1 optima::pattern)
42 (pattern2 optima::pattern))
43 (if (eq pattern1 pattern2)
47 (defmethod pattern-more-specific-p ((pattern1 optima::pattern)
48 (pattern2 optima::pattern))
53 (defmethod pattern-more-specific-p ((pattern1 optima.core:constant-pattern)
54 (pattern2 optima::pattern))
55 (if (typep pattern2 'optima.core:complex-pattern)
59 (defmethod pattern-more-specific-p ((pattern1 optima::pattern)
60 (pattern2 optima.core:constant-pattern))
61 (if (typep pattern1 'optima.core:complex-pattern)
65 (defmethod pattern-more-specific-p ((pattern1 optima.core:constant-pattern)
66 (pattern2 optima.core:constant-pattern))
67 (if (equal (optima.core:constant-pattern-value pattern1)
68 (optima.core:constant-pattern-value pattern2))
74 (defmethod pattern-more-specific-p ((pattern1 optima.core:variable-pattern)
75 (pattern2 optima::pattern))
76 (if (typep pattern2 '(or optima.core:or-pattern optima.core:and-pattern))
80 (defmethod pattern-more-specific-p ((pattern1 optima::pattern)
81 (pattern2 optima.core:variable-pattern))
82 (if (typep pattern1 '(or optima.core:or-pattern optima.core:and-pattern))
86 (defmethod pattern-more-specific-p ((pattern1 optima.core:variable-pattern)
87 (pattern2 optima.core:variable-pattern))
92 (defmethod pattern-more-specific-p ((pattern1 optima.core:guard-pattern)
93 (pattern2 optima::pattern))
94 (if (typep pattern2 '(or optima.core:or-pattern optima.core:and-pattern)) ; TODO not-pattern
98 (defmethod pattern-more-specific-p ((pattern1 optima::pattern)
99 (pattern2 optima.core:guard-pattern))
100 (if (typep pattern1 '(or optima.core:or-pattern optima.core:and-pattern))
104 (defmethod pattern-more-specific-p ((pattern1 optima.core:guard-pattern)
105 (pattern2 optima.core:guard-pattern))
106 (if (equal (optima.core:guard-pattern-test-form pattern1) ; TODO not enough because of variable names; encode variables with TODO numbers
107 (optima.core:guard-pattern-test-form pattern2))
108 (pattern-more-specific-p
109 (optima.core:guard-pattern-subpattern pattern1)
110 (optima.core:guard-pattern-subpattern pattern2))
115 (defmethod pattern-more-specific-p ((pattern1 optima.core:and-pattern)
116 (pattern2 optima::pattern))
117 (if (typep pattern2 'optima.core:and-pattern)
119 (let ((result (pattern-more-specific-p pattern2 pattern1)))
125 (defmethod pattern-more-specific-p ((pattern1 optima::pattern)
126 (pattern2 optima.core:and-pattern))
127 (reduce (lambda (result subpattern)
128 (case (pattern-more-specific-p pattern1 subpattern)
141 (optima.core:complex-pattern-subpatterns pattern2)
146 (defmethod pattern-more-specific-p ((pattern1 optima.core:or-pattern)
147 (pattern2 optima::pattern))
148 (if (typep pattern2 'optima.core:or-pattern)
150 (let ((result (pattern-more-specific-p pattern2 pattern1)))
156 (defmethod pattern-more-specific-p ((pattern1 optima::pattern)
157 (pattern2 optima.core:or-pattern))
158 (reduce (lambda (result subpattern)
159 (case (pattern-more-specific-p pattern1 subpattern)
171 (optima.core:complex-pattern-subpatterns pattern2)
176 ; TODO do this in a generic way via optima.core:complex-pattern-subpatterns
177 (defmethod pattern-more-specific-p ((pattern1 optima.core:cons-pattern)
178 (pattern2 optima.core:cons-pattern))
179 (let* ((car1 (optima.core:cons-pattern-car-pattern pattern1))
180 (cdr1 (optima.core:cons-pattern-cdr-pattern pattern1))
181 (car2 (optima.core:cons-pattern-car-pattern pattern2))
182 (cdr2 (optima.core:cons-pattern-cdr-pattern pattern2))
183 (result/car (pattern-more-specific-p car1 car2))
184 (result/cdr (pattern-more-specific-p cdr1 cdr2)))
186 ((and (eq result/cdr '=) (eq result/car '=))
188 ((and (eq result/car '<) (member result/cdr '(< =)))
190 ((and (eq result/cdr '<) (member result/car '(< =)))
192 ((and (eq result/car '>) (member result/cdr '(> =)))
194 ((and (eq result/cdr '>) (member result/car '(> =)))
201 (defmethod pattern-more-specific-p ((pattern1 optima.core:class-pattern)
202 (pattern2 optima.core:class-pattern))
203 (let* ((class1 (optima.core:class-pattern-class-name pattern1))
204 (slots1 (optima.core:class-pattern-slot-names pattern1))
205 (subpatterns1 (optima.core:class-pattern-subpatterns pattern1))
206 (class2 (optima.core:class-pattern-class-name pattern2))
207 (slots2 (optima.core:class-pattern-slot-names pattern2))
208 (subpatterns2 (optima.core:class-pattern-subpatterns pattern2))
209 (fewer-slots1-p (set-difference slots2 slots1))
210 (fewer-slots2-p (set-difference slots1 slots2)))
211 (labels ((lookup (slot)
212 (when-let ((position (position slot slots2)))
213 (nth position subpatterns2)))
214 (compare-slots (initial)
215 ;; TODO alternate idea: iterate over (union slots1 slots2); use lookup1 and lookup2 leading to :missing1 and :missing2
216 (reduce (lambda (result slot1-and-subpattern1)
217 (destructuring-bind (slot1 . subpattern1) slot1-and-subpattern1
218 (case (if-let ((subpattern2 (lookup slot1)))
219 (pattern-more-specific-p subpattern1 subpattern2)
221 ((< :missing) (case result
229 (mapcar #'cons slots1 subpatterns1)
230 :initial-value initial)))
231 (multiple-value-bind (result1 certain1-p) (subtypep class1 class2)
232 (multiple-value-bind (result2 certain2-p) (subtypep class2 class1)
233 (assert (and certain1-p certain2-p))
235 ((and result1 result2)
236 (compare-slots (if fewer-slots1-p '> '=)))
240 (fewer-slots2-p (compare-slots '<))
241 (t (compare-slots '<))))
245 (fewer-slots1-p (compare-slots '>))
246 (t (compare-slots '>))))
250 ;; `structure-pattern'
252 (defmethod pattern-more-specific-p ((pattern1 optima.core:structure-pattern)
253 (pattern2 optima.core:structure-pattern))
254 (error "not implemented"))