Minor changes (added COPYING information and other minutiae).
Annotate for file /templates-hierarchy.lisp
2009-04-15 mantoniotti 1 ;;;; -*- Mode: Lisp -*-
10:18:59 ' 2
' 3 ;;;; templates-hierarchy.lisp --
2004-11-17 mantoniotti 4
2011-04-02 mantoniotti 5 ;;;; See file COPYING for copyright licensing information.
04:05:18 ' 6
2004-11-17 mantoniotti 7 (in-package "CL.EXT.DACF.UNIFICATION") ; DACF = Data And Control Flow.
22:19:54 ' 8
' 9 ;;; Templates.
' 10 ;;; Essentially we extend the type specifier language.
' 11 ;;; The interesting thing is that we need to specify how a "match"
' 12 ;;; between a template and a CL object is performed.
' 13
' 14 ;;; A template is one of the following
' 15 ;;;
' 16 ;;; <template> ::= <logical variable>
' 17 ;;; | <structure template>
' 18 ;;; | <instance template>
' 19 ;;; | <destructuring template>
' 20 ;;; | <vector template>
' 21 ;;; | <sequence template>
' 22 ;;; | <array template>
' 23 ;;; | <type template>
' 24 ;;; | <lisp object>
' 25 ;;;
' 26
' 27 ;;; Destructuring Template Lambda List (as per standard CL terminology)
' 28 ;;;
' 29 ;;; <destructuring template lambda list> ::= <a "destructuring LL" with <template> in lieu of <var>>
' 30
' 31 ;;; Templates for Structures and Instances
' 32 ;;;
' 33 ;;; <structure template> ::= (<class designator> <structure-slot-spec>*)
' 34 ;;;
' 35 ;;; <instance template> ::= (<class designator> <slot-spec>*)
' 36 ;;;
' 37 ;;; where
' 38 ;;;
' 39 ;;; <structure-slot-spec> ::= <reader-name> <template>
' 40 ;;; <instance-slot-spec> ::= <accessor-name> <template>
' 41 ;;; | (slot-value <slot-name>) <template>
' 42
' 43 ;;; Template for Sequences
' 44 ;;;
' 45 ;;; <sequence template> ::= (<container type> . <destructuring template lambda list>)
' 46 ;;; | (subseq <from> <to> . <destructuring template lambda list>)
' 47 ;;; <container type> ::= list | cons | vector | array
' 48
' 49 ;;; Templates for Vectors and Arrays.
' 50 ;;;
' 51 ;;; <vector template> ::= (vector . <destructuring template lambda list>)
' 52 ;;;
' 53 ;;; <array template> ::= (array <shape template>)
' 54 ;;; | (<array CL type specifier> <shape template>)
' 55 ;;; | (array (['*' | <element type>] [<dimension spec>]]) <shape template>)
' 56 ;;; | (aref <index template> <template>)
' 57 ;;; <shape template> ::= <destructuring template lambda list>
' 58 ;;; | <sequence template>
' 59 ;;; | (<shape template>)
' 60
' 61 ;;; Templates for LIST and CONS
' 62 ;;; <list template> ::= (list . <destructuring template lambda list>)
' 63 ;;; <cons template> ::= (cons <template> <template>)
' 64
' 65 ;;; A regular list or cons acts as a list (hence as a sequence) template, or a cons template.
' 66
' 67 (define-condition unification-template-error (simple-error)
' 68 ())
' 69
' 70 ;;; Templates are introduced by the reader macro #T(...)
' 71
' 72 (defclass template ()
' 73 ((spec :accessor template-spec :type (or symbol cons) :initarg :spec))
' 74 (:default-initargs :spec nil))
' 75
' 76 (defgeneric template-p (x)
' 77 (:method ((x template)) t)
' 78 (:method ((x t)) nil))
' 79
' 80
' 81 (defclass type-template (template) ())
' 82
' 83 (defgeneric type-template-p (x)
' 84 (:method ((x type-template)) t)
' 85 (:method ((x t)) nil))
' 86
' 87
' 88 (defgeneric type-template-type-spec (x)
' 89 (:method ((x type-template))
' 90 (let ((spec (template-spec x)))
' 91 (if spec
' 92 (first spec)
' 93 'null))))
' 94
' 95
' 96
' 97 (defclass nil-template (type-template) ()) ; This is the point where we break the type hierarchy.
' 98
' 99 (defgeneric nil-template-p (x)
' 100 (:method ((x nil-template)) t)
' 101 (:method ((x t)) nil))
' 102
' 103
' 104 (defclass expression-template (template) ())
' 105
' 106 (defgeneric expression-template-p (x)
' 107 (:method ((x expression-template)) t)
' 108 (:method ((x t)) nil))
' 109
' 110
2010-02-07 pix 111 (defmethod print-object ((template template) stream)
2004-11-17 mantoniotti 112 (format stream "#T~S" (template-spec template)))
22:19:54 ' 113
' 114
' 115 (defclass sequence-template (type-template) ())
' 116
' 117 (defgeneric sequence-template-p (x)
' 118 (:method ((x sequence-template)) t)
' 119 (:method ((x t)) nil))
' 120
' 121
' 122 (defclass list-template (sequence-template) ())
' 123
' 124 (defgeneric list-template-p (x)
' 125 (:method ((x list-template)) t)
' 126 (:method ((x t)) nil))
' 127
2009-04-15 mantoniotti 128
10:18:59 ' 129 (defclass lambda-template (list-template expression-template) ())
' 130
' 131 (defgeneric lambda-template-p (x)
' 132 (:method ((x lambda-template)) t)
' 133 (:method ((x t)) nil))
' 134
' 135
' 136
2004-11-17 mantoniotti 137 (defclass array-template (type-template) ())
22:19:54 ' 138
' 139 (defgeneric array-template-p (x)
' 140 (:method ((x array-template)) t)
' 141 (:method ((x t)) nil))
' 142
' 143
' 144 (defclass vector-template (sequence-template array-template) ())
' 145
' 146 (defgeneric vector-template-p (x)
' 147 (:method ((x vector-template)) t)
' 148 (:method ((x t)) nil))
' 149
' 150
' 151 (defclass string-template (vector-template) ())
' 152
' 153 (defgeneric string-template-p (x)
' 154 (:method ((x string-template)) t)
' 155 (:method ((x t)) nil))
' 156
' 157
' 158
' 159
' 160 (defclass symbol-template (type-template) ())
' 161
' 162 (defgeneric symbol-template-p (x)
' 163 (:method ((x symbol-template)) t)
' 164 (:method ((x t)) nil))
' 165
' 166
' 167 (defclass number-template (type-template) ())
' 168
' 169 (defgeneric number-template-p (x)
' 170 (:method ((x number-template)) t)
' 171 (:method ((x t)) nil))
' 172
' 173
' 174 (defclass structure-object-template (type-template) ())
' 175
' 176 (defgeneric structure-object-template-p (x)
' 177 (:method ((x structure-object-template)) t)
' 178 (:method ((x t)) nil))
' 179
' 180
' 181 (defclass standard-object-template (type-template) ())
' 182
' 183 (defgeneric standard-object-template-p (x)
' 184 (:method ((x standard-object-template)) t)
' 185 (:method ((x t)) nil))
' 186
' 187
' 188 ;;; Expression Templates.
' 189
' 190 (defclass subseq-template (expression-template) ())
' 191
' 192 (defgeneric subseq-template-p (x)
' 193 (:method ((x subseq-template)) t)
' 194 (:method ((x t)) nil))
' 195
' 196
' 197
' 198 (defclass element-template (expression-template) ())
' 199
' 200 (defgeneric element-template-p (x)
' 201 (:method ((x element-template)) t)
' 202 (:method ((x t)) nil))
' 203
' 204
' 205 (defclass elt-template (element-template) ())
' 206
' 207 (defgeneric elt-template-p (x)
' 208 (:method ((x elt-template)) t)
' 209 (:method ((x t)) nil))
' 210
' 211
' 212 (defclass aref-template (element-template) ())
' 213
' 214 (defgeneric aref-template-p (x)
' 215 (:method ((x aref-template)) t)
' 216 (:method ((x t)) nil))
' 217
' 218
' 219 (defclass nth-template (element-template) ())
' 220
' 221 (defgeneric nth-template-p (x)
' 222 (:method ((x nth-template)) t)
' 223 (:method ((x t)) nil))
' 224
' 225
' 226 (defclass nthcdr-template (element-template) ())
' 227
' 228 (defgeneric nthcdr-template-p (x)
' 229 (:method ((x nthcdr-template)) t)
' 230 (:method ((x t)) nil))
' 231
' 232
' 233 (defgeneric make-template (kind spec))
' 234
2008-07-13 mantoniotti 235
2004-11-17 mantoniotti 236 (defmethod make-template ((kind null) (spec symbol))
22:19:54 ' 237 (assert (null spec) (spec) "MAKE-TEMPLATE called erroneously with ~S and ~S." kind spec)
' 238 (make-instance 'nil-template :spec spec))
' 239
' 240 (defmethod make-template ((kind symbol) (spec symbol))
' 241 (make-instance 'symbol-template :spec spec))
' 242
' 243 (defmethod make-template ((kind (eql 'symbol)) (spec cons))
' 244 (make-instance 'symbol-template :spec spec))
' 245
' 246 (defmethod make-template ((kind symbol) (spec cons))
' 247 (cond ((subtypep kind 'number)
' 248 (make-instance 'number-template :spec spec))
' 249 ((subtypep kind 'structure-object)
' 250 (make-instance 'structure-object-template :spec spec))
' 251 ((subtypep kind 'standard-object)
' 252 (make-instance 'standard-object-template :spec spec))
' 253 (t
' 254 (error 'unification-template-error
' 255 :format-control "Unknown template specifier ~S."
' 256 :format-arguments (list kind)))
' 257 ))
' 258
' 259 (defmethod make-template ((kind cons) (spec cons))
' 260 (cond ((subtypep kind 'number)
' 261 (make-instance 'number-template :spec spec))
' 262 ((subtypep kind 'string)
' 263 (make-instance 'string-template :spec spec))
' 264 ((subtypep kind 'vector)
' 265 (make-instance 'vector-template :spec spec))
' 266 ((subtypep kind 'array)
' 267 (make-instance 'array-template :spec spec))
' 268 (t
' 269 (error 'unification-template-error
' 270 :format-control "Unknown template specifier ~S."
' 271 :format-arguments (list kind)))
' 272 ))
' 273
' 274 (defmethod make-template ((kind number) (spec number))
' 275 (assert (= kind spec))
' 276 (make-instance 'number-template :spec spec))
' 277
' 278 (defmethod make-template ((kind (eql 'sequence)) (spec cons))
' 279 (make-instance 'sequence-template :spec spec))
' 280
' 281 (defmethod make-template ((kind (eql 'list)) (spec cons))
' 282 (make-instance 'list-template :spec spec))
' 283
2009-04-15 mantoniotti 284 (defmethod make-template ((kind (eql 'lambda)) (spec cons))
10:18:59 ' 285 (make-instance 'lambda-template :spec spec))
' 286
2004-11-17 mantoniotti 287 (defmethod make-template ((kind (eql 'vector)) (spec cons))
22:19:54 ' 288 (make-instance 'vector-template :spec spec))
' 289
' 290 (defmethod make-template ((kind (eql 'string)) (spec cons))
' 291 (make-instance 'string-template :spec spec))
' 292
' 293 (defmethod make-template ((kind (eql 'array)) (spec cons))
' 294 (make-instance 'array-template :spec spec))
' 295
' 296
' 297 (defmethod make-template ((kind (eql 'subseq)) (spec cons))
' 298 (make-instance 'subseq-template :spec spec))
' 299
' 300 (defmethod make-template ((kind (eql 'elt)) (spec cons))
' 301 (make-instance 'elt-template :spec spec))
' 302
' 303 (defmethod make-template ((kind (eql 'aref)) (spec cons))
' 304 (make-instance 'aref-template :spec spec))
' 305
' 306 (defmethod make-template ((kind (eql 'nth)) (spec cons))
' 307 (make-instance 'nth-template :spec spec))
' 308
' 309 (defmethod make-template ((kind (eql 'nthcdr)) (spec cons))
' 310 (make-instance 'nthcdr-template :spec spec))
' 311
' 312
' 313
2008-07-13 mantoniotti 314 ;;;;===========================================================================
13:10:48 ' 315 ;;;; Implementation.
2004-11-17 mantoniotti 316
22:19:54 ' 317 ;;; Symbol Templates.
' 318 ;;; Specification is
' 319 ;;;
' 320 ;;; (symbol <symbol>)
' 321
' 322 (defun symbol-template-symbol (x)
' 323 (declare (type symbol-template x))
' 324 (assert (symbol-template-p x) (x) "Non symbol template ~S." x)
' 325 (let ((spec (template-spec x)))
' 326 (cond ((symbolp spec) spec)
' 327 ((consp spec) (second spec)))))
' 328
' 329
' 330 ;;; Number template
' 331 ;;; Specification is
' 332 ;;;
' 333 ;;; (<number type> <number>)
' 334 ;;; or
' 335 ;;;
' 336 ;;; <number>
' 337
' 338 (defun number-template-number (x)
' 339 (declare (type number-template x))
' 340 (assert (number-template-p x) (x) "Non number template ~S." x)
' 341 (let ((spec (template-spec x)))
' 342 (etypecase spec
' 343 (symbol spec)
' 344 (number spec)
' 345 (cons (second spec)))))
' 346
' 347
2009-12-17 mantoniotti 348 (defun number-template-numeric-type (x)
16:43:12 ' 349 (declare (type number-template x))
' 350 (let ((n (number-template-number x)))
' 351 (if (numberp n)
' 352 (type-of n)
' 353 (first (template-spec x)))))
' 354
' 355 (defun number-template-numeric-class (x)
' 356 (declare (type number-template x))
' 357 (let ((n (number-template-number x)))
' 358 (if (numberp n)
' 359 (class-of n)
' 360 (find-class (first (template-spec x))))))
' 361
' 362
' 363
' 364
2004-11-17 mantoniotti 365 ;;; Sequence Templates.
22:19:54 ' 366 ;;; Specification is
' 367 ;;;
' 368 ;;; (<sequence subtype> . <destructuring template lambda list>)
' 369 ;;; or
' 370 ;;; (subseq <from> <to> . <destructuring template lambda list>)
' 371
' 372 (defun sequence-template-lambda-list (x)
' 373 (declare (type sequence-template x))
' 374 (assert (sequence-template-p x) (x) "Non sequence template ~S." x)
' 375 (rest (template-spec x)))
' 376
' 377
' 378 ;;; Vector Templates.
' 379 ;;; Specification is
' 380 ;;;
' 381 ;;; (<vector type specifier> . <destructuring template lambda list>)
' 382
' 383 (defun vector-template-element-type (x)
' 384 (declare (type vector-template x))
' 385 (assert (vector-template-p x) (x) "Non vector template ~S." x)
' 386 (let ((spec (type-template-type-spec x)))
' 387 (if (consp spec)
' 388 (destructuring-bind (vector-kwd &optional (element-type '*) size)
' 389 spec
' 390 (declare (ignore vector-kwd size))
' 391 element-type)
' 392 '*)))
' 393
' 394
' 395 (defun vector-template-size (x)
' 396 (declare (type vector-template x))
' 397 (assert (vector-template-p x) (x) "Non vector template ~S." x)
' 398 (let ((spec (type-template-type-spec x)))
' 399 (if (consp spec)
' 400 (destructuring-bind (vector-kwd &optional element-type (size '*))
' 401 spec
' 402 (declare (ignore vector-kwd element-type))
' 403 size)
' 404 '*)))
' 405
' 406
' 407 ;;; Array Templates.
' 408 ;;; Specification is
' 409 ;;;
' 410 ;;; (array (['*' | <element type>] [<dimension spec>]) <shape template>)
' 411 ;;; or
' 412 ;;; (<array type specifier> <shape template>)
' 413
' 414
' 415 (defun array-template-shape-template (x)
' 416 (declare (type array-template x))
' 417 (assert (array-template-p x) (x) "Non array template ~S." x)
' 418 (let ((t-spec (template-spec x)))
' 419 (if (= 2 (list-length t-spec))
' 420 (second t-spec)
' 421 (third t-spec))))
' 422
' 423
' 424 (defun array-template-element-type (x)
' 425 (declare (type array-template x))
' 426 (assert (array-template-p x) (x) "Non array template ~S." x)
' 427 (let ((type-spec (type-template-type-spec x)))
' 428 (if (consp type-spec)
' 429 (destructuring-bind (array-kwd &optional (element-type '*) dimension-spec)
' 430 type-spec
' 431 (declare (ignore array-kwd dimension-spec))
' 432 element-type)
' 433 '*)))
' 434
' 435
' 436 (defun array-template-dimensions (x)
' 437 (declare (type array-template x))
' 438 (assert (array-template-p x) (x) "Non array template ~S." x)
' 439 (let ((type-spec (type-template-type-spec x)))
' 440 (if (consp type-spec)
' 441 (destructuring-bind (array-kwd &optional element-type (dimension-spec '*))
' 442 type-spec
' 443 (declare (ignore array-kwd element-type))
' 444 dimension-spec)
' 445 '*)))
' 446
' 447
' 448
' 449 ;;; Structure and Standard Object Templates.
' 450
2009-12-17 mantoniotti 451 (defun structure-object-template-class (x)
16:43:12 ' 452 (and (structure-object-template-p x)
' 453 (first (template-spec x))))
' 454
2004-11-17 mantoniotti 455 (defun structure-object-template-slots (x)
22:19:54 ' 456 (and (structure-object-template-p x)
' 457 (rest (template-spec x))))
' 458
' 459
2009-12-17 mantoniotti 460 (defun standard-object-template-class (x)
16:43:12 ' 461 (and (standard-object-template-p x)
' 462 (first (template-spec x))))
' 463
2004-11-17 mantoniotti 464 (defun standard-object-template-slots (x)
22:19:54 ' 465 (and (standard-object-template-p x)
' 466 (rest (template-spec x))))
' 467
' 468
' 469 ;;;---------------------------------------------------------------------------
' 470 ;;; Expression Templates.
' 471
' 472
' 473 ;;; AREF Templates.
' 474
' 475 (defun aref-template-indexes (x)
' 476 (declare (type aref-template x))
' 477 (assert (aref-template-p x) (x) "Non aref template ~S." x)
' 478 (let ((spec (template-spec x)))
' 479 (second spec)))
' 480
' 481
' 482 (defun aref-template-element (x)
' 483 (declare (type aref-template x))
' 484 (assert (aref-template-p x) (x) "Non array template ~S." x)
' 485 (let ((spec (template-spec x)))
' 486 (third spec)))
' 487
' 488
' 489
' 490
' 491 ;;;===========================================================================
' 492 ;;; Template variables.
' 493 ;;; Let's walk down a template.
' 494 ;;; Note that there is an asymmetry here: I admit some containers to have
' 495 ;;; variables inside, but I do not search instances of a class for variables.
' 496 ;;; This is an asymmetry that would be way too hard to fix without more
' 497 ;;; introspective power (which is available in the MOP, but not standard.)
' 498
' 499 (defgeneric collect-template-vars (template))
' 500
' 501 (defmethod collect-template-vars ((template template))
' 502 (let ((spec (template-spec template)))
' 503 (nconc (collect-template-vars (car spec))
' 504 (collect-template-vars (cdr spec)))))
' 505
' 506 (defmethod collect-template-vars ((template symbol-template))
' 507 (let ((template (symbol-template-symbol template)))
' 508 (when (and (variablep template) (not (variable-any-p template)))
' 509 (list template))))
' 510
' 511
' 512 (defmethod collect-template-vars ((template number-template))
' 513 (let ((template (number-template-number template)))
' 514 (etypecase template
' 515 (number ())
2005-04-27 mantoniotti 516 (symbol (cond ((and (variablep template) (not (variable-any-p template)))
20:44:25 ' 517 (list template))
2004-11-17 mantoniotti 518 ((and (boundp template)
22:19:54 ' 519 (numberp (symbol-value template)))
2005-04-27 mantoniotti 520 ;; This handles cases like #T(number pi)
20:44:25 ' 521 ;; It may be too broad, but for the time being it seems ok.
' 522 nil)
2004-11-17 mantoniotti 523 (t
22:19:54 ' 524 (error "Invalid number template ~S." template)))))))
' 525
' 526
' 527 (defmethod collect-template-vars ((template symbol))
' 528 (when (and (variablep template) (not (variable-any-p template)))
' 529 (list template)))
' 530
' 531 (defmethod collect-template-vars ((template null))
' 532 ())
' 533
' 534 (defmethod collect-template-vars ((template cons))
' 535 (nconc (collect-template-vars (car template))
' 536 (collect-template-vars (cdr template))))
' 537
' 538 (defmethod collect-template-vars ((template string))
' 539 ())
' 540
' 541
' 542 (defmethod collect-template-vars ((template vector))
' 543 (loop for e across template
' 544 nconc (collect-template-vars e)))
' 545
' 546
' 547 (defmethod collect-template-vars ((template array))
' 548 (loop for i below (array-total-size template)
' 549 nconc (collect-template-vars (row-major-aref template i))))
' 550
' 551
' 552 (defmethod collect-template-vars ((template t))
' 553 ())
' 554
' 555 ;;; end of file -- templates.lisp --