Module: internal Author: Jonathan Bachrach Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND //// //// ANCIENT HISTORY //// define method concatenate-2 (list-1 :: , list-2 :: ) => (result :: ) if (list-1.empty?) list-2 else let rest :: = list-1.tail; pair(list-1.head, concatenate-2(rest, list-2)) end if end method concatenate-2; define method concatenate-2 (v1 :: , v2 :: ) => (result :: ) let size-1 :: = v1.size; let size-2 :: = v2.size; if (size-1 == 0) v2 elseif (size-2 == 0) v1 else let new-vector :: = make(, size: size-1 + size-2); for (index :: from 0 below size-1) vector-element(new-vector, index) := vector-element(v1, index); end for; for (index-2 :: from 0 below size-2, index :: from size-1) vector-element(new-vector, index) := vector-element(v2, index-2); end for; new-vector end if; end method concatenate-2; // define function precedes? (object1, object2, objects :: ) // iterate walk (cursor :: = objects) // let object = cursor.head; // case // object == object1 => // #t; // object == object2 => // #f; // otherwise => // walk(cursor.tail) // end case; // end iterate // end function; // bubble sort -- yuck! // define method bubble-sort! (items :: , #key test = \<, stable) // => (result :: ) // let tmp = #f; // until (tmp == items.head) // tmp := items.head; // for (prev :: = items then prev.tail, // next :: = items.tail then next.tail, // until: next.empty?) // // (unless (test (head prev) (head next)) // // Only rearrange on a definite positive outcome; // if (test(next.head, prev.head)) // tmp := prev.head; // prev.head := next.head; // next.head := tmp // end if; // end for // end until; // items // end method bubble-sort!; ///// ///// GROUNDING METHODS ///// /// We ground the potential infinite recursion on method look up by /// constraining instance? and subtype? to allow only class and /// singleton specializers. These are handled specially in the /// dispatch without calling either generic function through use /// of the following grounded versions: //define function class? (type :: ) // let class :: = type.object-class; // class == // | subclass?(class, ) //end function; //define function singleton? (object) // object.object-class == //end function; define inline function class? (type :: ) instance?(type, ) end function; define inline function singleton? (object) instance?(object, ) end function; define inline function grounded-instance? (o, type :: ) primitive-instance?(o, type) end function; define function grounded-subtype? (type1 :: , type2 :: ) case type1.class? & type2.class? => let type1 :: = type1; let type2 :: = type2; subclass?(type1, type2); type1.class? & type2.singleton? => #f; type1.singleton? & type2.class? => let type1 :: = type1; let type2 :: = type2; grounded-instance?(type1.singleton-object, type2); type1.singleton? & type2.singleton? => let type1 :: = type1; let type2 :: = type2; type1.singleton-object == type2.singleton-object; otherwise => subtype?(type1, type2) end case end function; // concrete-subtype?(, ) => #t // // For classes C1 and C2, // C1 is a concrete subtype of C2 if all concrete subclasses of C1 are // subclasses of C2. So if is the only subclass , // and is abstract and concrete, // is a concrete subtype of . // Consider also the lattice, with A, B, and C abstract: // A // / \ // B C // \ / // D // We can similarly deduce that A, B, and C are all concrete subtypes // of D. Even more unusual is deducing that B and C are mutually // concrete subtypes. define function concrete-subtype? (type1 :: , type2 :: , dep :: false-or()) => (well? :: ) grounded-subtype?(type1, type2) | (type1 ~== & class?(type1) & class?(type2) & (begin let c1 :: = type1; let c2 :: = type2; let ic1 :: = class-implementation-class(c1); let ic2 :: = class-implementation-class(c2); // Only do this if the classes are joint. Otherwise, we get frequent // quasi-false positives where unrelated classes with no concrete subclasses // are noted - correctly - as being subtypes. (subiclass?(ic2, c2, ic1, c1) | member?(c1, class-known-joint(ic2)) | member?(c2, class-known-joint(ic1))) & (~*conservative-concrete-subtype? | (iclass-subclasses-fixed?(ic1) & iclass-subclasses-fixed?(ic2))) & begin let st? = concrete-subtype?-internal(c1, c2); when (st? & dep) %register-subclass-dependent-generic(dep, c1) end when; st? end end)) end function; define variable *conservative-concrete-subtype? = #f; define function concrete-subtype?-internal (c1 :: , c2 :: ) => (well? :: ) let ic1 :: = class-implementation-class(c1); let ic2 :: = class-implementation-class(c2); (class-abstract?(ic1) | subiclass?(ic1, c1, ic2, c2)) & every?(rcurry(concrete-subtype?-internal, c2), direct-subclasses(ic1)) end function; define function grounded-has-instances? (class :: , type :: ) select (type by instance?) => let type :: = type; if (subclass?(class, type)) values(#t, #t) else values(#f, #f) end if; => let type :: = type; values(class == object-class(type.singleton-object), #f); => let type :: = type; has-instances?(class, type, $empty-subjunctive-class-universe); => let type :: = type; has-instances?(class, type, $empty-subjunctive-class-universe); => let type :: = type; has-instances?(class, type, $empty-subjunctive-class-universe); otherwise => has-instances?(class, type, $empty-subjunctive-class-universe); end select end function; ///// ///// CORE DISPATCHING BUILDING BLOCKS ///// //// //// PREDICATE USED TO ORDER SPECIALIZERS WRT ARGUMENT //// define function every-2? (function :: , argument-1 :: , argument-2 :: ) let size-1 :: = argument-1.size; let size-2 :: = argument-2.size; let min-size :: = if (size-1 < size-2) size-1 else size-2 end if; // MIN iterate search (index :: = 0) if (index = min-size) #t else function(vector-element(argument-1, index), vector-element(argument-2, index)) & search(index + 1) end if end iterate end function; //// //// IS ARGUMENT CONSISTENT WITH SPECIALIZER? //// define function applicable-argument? (argument, specializer) => (result :: ) grounded-instance?(argument, specializer) end function; //// //// IS METHOD CONSISTENT WITH GIVEN ARGUMENTS? //// ASSUMING THAT THE NUMBER OF ARGUMENTS IS NOT IN QUESTION //// define function applicable-method-assuming-number-required? (function :: , arguments :: ) => (result :: ) every-2?(applicable-argument?, arguments, function.function-specializers) end function; define function unbound-instance-slot (object, offset :: ) => (will-never-return :: ) let sd :: = vector-element(instance-slot-descriptors(object-class(object)), offset); error(make(, format-string: "The %s slot is unbound in %s.", format-arguments: list(slot-getter(sd) | sd, object))) end function; define function unbound-repeated-slot (object, idx :: ) => (will-never-return :: ) let sd :: = repeated-slot-descriptor(object-class(object)); error(make(, format-string: "%s at index %s is unbound in %s.", format-arguments: list(slot-getter(sd) | sd, idx, object))) end function; define function unbound-class-slot (inst, offset :: ) => (will-never-return :: ) let cls :: = if (instance?(inst, )) inst else object-class(inst) end if; let sd :: = vector-element(class-slot-descriptors(cls), offset); error(make(, format-string: "The %s slot is unbound in %s.", format-arguments: list(slot-getter(sd) | sd, inst))) end function; // eof;