;;;----- Licensing notice ---------------------------------------------------
;;;
-;;; This file is part of the Sensble Object Design, an object system for C.
+;;; This file is part of the Sensible Object Design, an object system for C.
;;;
;;; SOD is free software; you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
(defun find-instance-slot-by-name (class super-nick slot-name)
(let ((super (find-superclass-by-nick class super-nick)))
- (find-thing-by-name "slot" super (sod-class-slots super)
+ (find-thing-by-name "instance slot" super (sod-class-slots super)
slot-name #'sod-slot-name)))
(defun find-class-slot-by-name (class super-nick slot-name)
(let* ((meta (sod-class-metaclass class))
(super (find-superclass-by-nick meta super-nick)))
- (find-thing-by-name "slot" super (sod-class-slots super)
+ (find-thing-by-name "class slot" super (sod-class-slots super)
slot-name #'sod-slot-name)))
(defun find-message-by-name (class super-nick message-name)
(find-thing-by-name "message" super (sod-class-messages super)
message-name #'sod-message-name))))
+;;;--------------------------------------------------------------------------
+;;; Describing class inheritance paths in diagnostics.
+
+(export 'inheritance-path-reporter-state)
+(defclass inheritance-path-reporter-state ()
+ ((%class :type sod-class :initarg :class)
+ (paths :type list :initarg :paths)
+ (seen :type hash-table :initform (make-hash-table))))
+
+(export 'make-inheritance-path-reporter-state)
+(defun make-inheritance-path-reporter-state (class)
+ (make-instance 'inheritance-path-reporter-state :class class))
+
+(export 'report-inheritance-path)
+(defun report-inheritance-path (state super)
+ "Issue informational messages showing how CLASS inherits from SUPER."
+ (with-slots (paths (class %class) include-boundary seen) state
+ (unless (slot-boundp state 'paths)
+ (setf paths (distinguished-point-shortest-paths
+ class
+ (lambda (c)
+ (mapcar (lambda (super) (cons super 1))
+ (sod-class-direct-superclasses c))))))
+ (dolist (hop (mapcon (lambda (subpath)
+ (let ((super (car subpath))
+ (sub (and (cdr subpath)
+ (cadr subpath))))
+ (if (or (not sub) (gethash super seen))
+ nil
+ (progn
+ (setf (gethash super seen) t)
+ (list (cons super sub))))))
+ (cdr (find super paths :key #'cadr))))
+ (let ((super (car hop))
+ (sub (cdr hop)))
+ (info-with-location sub
+ "Class `~A' is a direct superclass ~
+ of `~A', defined here"
+ super sub)))))
+
+;;;--------------------------------------------------------------------------
+;;; Metaclass inference.
+
+(export 'select-minimal-class-property)
+(defun select-minimal-class-property (supers key order default what
+ &key (present (lambda (x)
+ (format nil "`~A'" x)))
+ allow-empty)
+ "Return the minimal partially-ordered key from the SUPERS.
+
+ KEY is a function of one argument which returns some interesting property
+ of a class. The keys are assumed to be partially ordered by ORDER, a
+ function of two arguments which returns non-nil if its first argument
+ precedes its second. If there is a unique minimal key then return it;
+ otherwise report a useful error and pick some candidate in an arbitrary
+ way; the DEFAULT may be chosen if no better choices are available. If
+ ALLOW-EMPTY is non-nil, then no error is reported if there are no SUPERS,
+ and the DEFAULT choice is returned immediately.
+
+ In an error message, the keys are described as WHAT, which should be a
+ noun phrase; keys are filtered through PRESENT, a function of one
+ argument, before presentation.
+
+ The function returns two values: the chosen value, and a flag which is
+ non-nil if it was chosen without errors."
+
+ (let ((candidates (partial-order-minima (mapcar key supers) order)))
+ (cond ((and (null candidates) allow-empty)
+ (values default t))
+ ((and candidates (null (cdr candidates)))
+ (values (car candidates) t))
+ (t
+ (cerror* "No obvious choice for implicit ~A: ~
+ ~{~#[root classes must specify explicitly~:;~
+ candidates are ~
+ ~#[~;~A~;~A and ~A~:;~@{~A, ~#[~;and ~A~]~}~]~]~:}"
+ what (mapcar present candidates))
+ (dolist (candidate candidates)
+ (let ((super (find candidate supers :key key)))
+ (info-with-location super
+ "Direct superclass `~A' defined here ~
+ has ~A ~A"
+ super what (funcall present candidate))))
+ (values (if candidates (car candidates) default) nil)))))
+
;;;--------------------------------------------------------------------------
;;; Miscellaneous useful functions.
* all of whose characters are alphanumeric or underscores
* and which doesn't contain two consecutive underscores."
- (and (stringp name)
- (plusp (length name))
- (alpha-char-p (char name 0))
- (every (lambda (ch) (or (alphanumericp ch) (char= ch #\_))) name)
- (not (search "__" name))))
+ (or (typep name 'temporary-variable)
+ (and (stringp name)
+ (plusp (length name))
+ (alpha-char-p (char name 0))
+ (every (lambda (ch) (or (alphanumericp ch) (char= ch #\_))) name)
+ (not (search "__" name)))))
(export 'find-root-superclass)
(defun find-root-superclass (class)
The root superclass is the superclass which itself has no direct
superclasses. In universes not based on the provided builtin module, the
- root class may not be our beloved SodObject; however, there must be one
+ root class may not be our beloved `SodObject'; however, there must be one
(otherwise the class graph is cyclic, which should be forbidden), and we
insist that it be unique."
;;
;; Note! This function gets called from `check-sod-class' before the
;; class's chains have been computed. Therefore we iterate over the direct
- ;; superclass's chains rather than the class's own. This misses a chain
+ ;; superclasses' chains rather than the class's own. This misses a chain
;; only in the case where the class is its own chain head. There are two
;; subcases: if there are no direct superclasses at all, then the class is
;; its own root; otherwise, it clearly can't be the root and the omission
(sod-class-chains super)))
supers)))
(list class))))
- (cond ((null roots) (error "Class ~A has no root class!" class))
- ((cdr roots) (error "Class ~A has multiple root classes ~
- ~{~A~#[~; and ~;, ~]~}"
- class roots))
+ (cond ((null roots)
+ (error "Class ~A has no root class!" class))
+ ((cdr roots)
+ (cerror* "Class ~A has multiple root classes ~
+ ~{~#[~;~A~;~A and ~A~:; ~@{~A, ~#[~;and ~A~]~}~]~}"
+ class roots)
+ (let ((state (make-inheritance-path-reporter-state class)))
+ (dolist (root roots)
+ (report-inheritance-path state root))))
(t (car roots)))))
(export 'find-root-metaclass)
(and (= (length message-args) (length method-args))
(every (lambda (message-arg method-arg)
(if (eq message-arg :ellipsis)
- (eq method-arg (c-type va-list))
+ (c-type-equal-p (argument-type method-arg)
+ c-type-va-list)
(c-type-equal-p (argument-type message-arg)
(argument-type method-arg))))
message-args method-args)))
(defun vtmsgs-struct-tag (class super)
(format nil "~A__vtmsgs_~A" class (sod-class-nickname super)))
+(export 'vtable-union-tag)
+(defun vtable-union-tag (class chain-head)
+ (format nil "~A__vtu_~A" class (sod-class-nickname chain-head)))
+
(export 'vtable-struct-tag)
(defun vtable-struct-tag (class chain-head)
(format nil "~A__vt_~A" class (sod-class-nickname chain-head)))
(defun vtable-name (class chain-head)
(format nil "~A__vtable_~A" class (sod-class-nickname chain-head)))
+(export 'message-macro-name)
+(defun message-macro-name (class entry)
+ (format nil "~A_~A" class (method-entry-slot-name entry)))
+
;;;----- That's all, folks --------------------------------------------------