Merge branch 'master' of git://factorcode.org/git/factor into experimental

db4
Alex Chapman 2008-05-02 17:58:13 +10:00
commit 6ba999933e
33 changed files with 295 additions and 171 deletions

View File

@ -1,7 +1,7 @@
! Copyright (C) 2007 Daniel Ehrenberg and Slava Pestov ! Copyright (C) 2007 Daniel Ehrenberg and Slava Pestov
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: help.markup help.syntax kernel sequences USING: help.markup help.syntax kernel sequences
sequences.private namespaces classes math ; sequences.private namespaces math ;
IN: assocs IN: assocs
ARTICLE: "alists" "Association lists" ARTICLE: "alists" "Association lists"

View File

@ -404,8 +404,8 @@ M: quotation '
[ [
{ {
dictionary source-files builtins dictionary source-files builtins
update-map class<-cache class-not-cache update-map class<=-cache class<=>-cache
classes-intersect-cache class-and-cache class-not-cache classes-intersect-cache class-and-cache
class-or-cache class-or-cache
} [ dup get swap bootstrap-word set ] each } [ dup get swap bootstrap-word set ] each
] H{ } make-assoc ] H{ } make-assoc

View File

@ -44,10 +44,6 @@ SYMBOL: bootstrap-time
"Now, you can run Factor:" print "Now, you can run Factor:" print
vm write " -i=" write "output-image" get print flush ; vm write " -i=" write "output-image" get print flush ;
! Wrap everything in a catch which starts a listener so
! you can see what went wrong, instead of dealing with a
! fep
! We time bootstrap ! We time bootstrap
millis >r millis >r

View File

@ -1,14 +1,14 @@
USING: help.markup help.syntax kernel classes ; USING: help.markup help.syntax kernel classes words
checksums checksums.crc32 sequences math ;
IN: classes.algebra IN: classes.algebra
ARTICLE: "class-operations" "Class operations" ARTICLE: "class-operations" "Class operations"
"Set-theoretic operations on classes:" "Set-theoretic operations on classes:"
{ $subsection class< } { $subsection class< }
{ $subsection class<= }
{ $subsection class-and } { $subsection class-and }
{ $subsection class-or } { $subsection class-or }
{ $subsection classes-intersect? } { $subsection classes-intersect? }
"Topological sort:"
{ $subsection sort-classes }
{ $subsection min-class } { $subsection min-class }
"Low-level implementation detail:" "Low-level implementation detail:"
{ $subsection class-types } { $subsection class-types }
@ -17,6 +17,40 @@ ARTICLE: "class-operations" "Class operations"
{ $subsection class-types } { $subsection class-types }
{ $subsection class-tags } ; { $subsection class-tags } ;
ARTICLE: "class-linearization" "Class linearization"
"Classes have an intrinsic partial order; given two classes A and B, we either have that A is a subset of B, B is a subset of A, A and B are equal as sets, or they are incomparable. The last two situations present difficulties for method dispatch:"
{ $list
"If a generic word defines a method on a mixin class A and another class B, and B is the only instance of A, there is an ambiguity because A and B are equal as sets; any object that is an instance of one is an instance of both."
{ "If a generic word defines methods on two union classes which are incomparable but not disjoint, for example " { $link sequence } " and " { $link number } ", there is an ambiguity because the generic word may be called on an object that is an instance of both unions." }
}
"These difficulties are resolved by imposing a linear order on classes, computed as follows for two classes A and B:"
{ $list
"If A and B are the same class (not just equal as sets), then comparison stops."
"If A is a proper subset of B, or B is a proper subset of A, then comparison stops."
{ "Next, the metaclasses of A and B are compared, with intrinsic meta-class order, from most-specific to least-specific:"
{ $list
"Built-in classes and tuple classes"
"Predicate classes"
"Union classes"
"Mixin classes"
}
"If this yields an unambiguous answer, comparison stops."
}
"If the metaclasses of A and B occupy the same position in the order, then the vocabularies of A and B are compared lexicographically. If this yields an unambiguous answer, comparison stops."
"If A and B belong to the same vocabulary, their names are compared lexicographically. This must yield an unambiguous result, since if the names equal they must be the same class and this case was already handled in the first step."
}
"Some examples:"
{ $list
{ { $link integer } " precedes " { $link number } " because it is a strict subset" }
{ { $link number } " precedes " { $link sequence } " because the " { $vocab-link "math" } " vocabulary precedes the " { $vocab-link "sequences" } " vocabulary" }
{ { $link crc32 } " precedes " { $link checksum } ", even if it were the only instance, because " { $link crc32 } " is a singleton class which is more specific than a mixin class" }
}
"Operations:"
{ $subsection class<=> }
{ $subsection sort-classes }
"Metaclass order:"
{ $subsection rank-class } ;
HELP: flatten-builtin-class HELP: flatten-builtin-class
{ $values { "class" class } { "assoc" "an assoc whose keys are classes" } } { $values { "class" class } { "assoc" "an assoc whose keys are classes" } }
{ $description "Outputs a set of tuple classes whose union is the smallest cover of " { $snippet "class" } " intersected with " { $link tuple } "." } ; { $description "Outputs a set of tuple classes whose union is the smallest cover of " { $snippet "class" } " intersected with " { $link tuple } "." } ;
@ -29,14 +63,16 @@ HELP: class-types
{ $values { "class" class } { "seq" "an increasing sequence of integers" } } { $values { "class" class } { "seq" "an increasing sequence of integers" } }
{ $description "Outputs a sequence of builtin type numbers whose instances can possibly be instances of the given class." } ; { $description "Outputs a sequence of builtin type numbers whose instances can possibly be instances of the given class." } ;
HELP: class< HELP: class<=
{ $values { "first" "a class" } { "second" "a class" } { "?" "a boolean" } } { $values { "first" "a class" } { "second" "a class" } { "?" "a boolean" } }
{ $description "Tests if all instances of " { $snippet "class1" } " are also instances of " { $snippet "class2" } "." } { $description "Tests if all instances of " { $snippet "class1" } " are also instances of " { $snippet "class2" } "." }
{ $notes "Classes are partially ordered. This means that if " { $snippet "class1 <= class2" } " and " { $snippet "class2 <= class1" } ", then " { $snippet "class1 = class2" } ". Also, if " { $snippet "class1 <= class2" } " and " { $snippet "class2 <= class3" } ", then " { $snippet "class1 <= class3" } "." } ; { $notes "Classes are partially ordered. This means that if " { $snippet "class1 <= class2" } " and " { $snippet "class2 <= class1" } ", then " { $snippet "class1 = class2" } ". Also, if " { $snippet "class1 <= class2" } " and " { $snippet "class2 <= class3" } ", then " { $snippet "class1 <= class3" } "." } ;
HELP: sort-classes HELP: sort-classes
{ $values { "seq" "a sequence of class" } { "newseq" "a new seqence of classes" } } { $values { "seq" "a sequence of class" } { "newseq" "a new seqence of classes" } }
{ $description "Outputs a topological sort of a sequence of classes. Larger classes come before their subclasses." } ; { $description "Outputs a linear sort of a sequence of classes. Larger classes come before their subclasses." } ;
{ sort-classes class<=> } related-words
HELP: class-or HELP: class-or
{ $values { "first" class } { "second" class } { "class" class } } { $values { "first" class } { "second" class } { "class" class } }
@ -53,3 +89,7 @@ HELP: classes-intersect?
HELP: min-class HELP: min-class
{ $values { "class" class } { "seq" "a sequence of class words" } { "class/f" "a class word or " { $link f } } } { $values { "class" class } { "seq" "a sequence of class words" } { "class/f" "a class word or " { $link f } } }
{ $description "If all classes in " { $snippet "seq" } " that intersect " { $snippet "class" } " are subtypes of " { $snippet "class" } ", outputs the last such element of " { $snippet "seq" } ". If any conditions fail to hold, outputs " { $link f } "." } ; { $description "If all classes in " { $snippet "seq" } " that intersect " { $snippet "class" } " are subtypes of " { $snippet "class" } ", outputs the last such element of " { $snippet "seq" } ". If any conditions fail to hold, outputs " { $link f } "." } ;
HELP: class<=>
{ $values { "first" class } { "second" class } { "n" symbol } }
{ $description "Compares two classes with the class linearization order." } ;

View File

@ -4,9 +4,9 @@ kernel math namespaces parser prettyprint sequences strings
tools.test vectors words quotations classes classes.algebra tools.test vectors words quotations classes classes.algebra
classes.private classes.union classes.mixin classes.predicate classes.private classes.union classes.mixin classes.predicate
vectors definitions source-files compiler.units growable vectors definitions source-files compiler.units growable
random inference effects kernel.private sbufs ; random inference effects kernel.private sbufs math.order ;
: class= [ class< ] 2keep swap class< and ; : class= [ class<= ] [ swap class<= ] 2bi and ;
: class-and* >r class-and r> class= ; : class-and* >r class-and r> class= ;
@ -38,43 +38,43 @@ UNION: both first-one union-class ;
[ f ] [ number vector class-and sequence classes-intersect? ] unit-test [ f ] [ number vector class-and sequence classes-intersect? ] unit-test
[ t ] [ \ fixnum \ integer class< ] unit-test [ t ] [ \ fixnum \ integer class<= ] unit-test
[ t ] [ \ fixnum \ fixnum class< ] unit-test [ t ] [ \ fixnum \ fixnum class<= ] unit-test
[ f ] [ \ integer \ fixnum class< ] unit-test [ f ] [ \ integer \ fixnum class<= ] unit-test
[ t ] [ \ integer \ object class< ] unit-test [ t ] [ \ integer \ object class<= ] unit-test
[ f ] [ \ integer \ null class< ] unit-test [ f ] [ \ integer \ null class<= ] unit-test
[ t ] [ \ null \ object class< ] unit-test [ t ] [ \ null \ object class<= ] unit-test
[ t ] [ \ generic \ word class< ] unit-test [ t ] [ \ generic \ word class<= ] unit-test
[ f ] [ \ word \ generic class< ] unit-test [ f ] [ \ word \ generic class<= ] unit-test
[ f ] [ \ reversed \ slice class< ] unit-test [ f ] [ \ reversed \ slice class<= ] unit-test
[ f ] [ \ slice \ reversed class< ] unit-test [ f ] [ \ slice \ reversed class<= ] unit-test
PREDICATE: no-docs < word "documentation" word-prop not ; PREDICATE: no-docs < word "documentation" word-prop not ;
UNION: no-docs-union no-docs integer ; UNION: no-docs-union no-docs integer ;
[ t ] [ no-docs no-docs-union class< ] unit-test [ t ] [ no-docs no-docs-union class<= ] unit-test
[ f ] [ no-docs-union no-docs class< ] unit-test [ f ] [ no-docs-union no-docs class<= ] unit-test
TUPLE: a ; TUPLE: a ;
TUPLE: b ; TUPLE: b ;
UNION: c a b ; UNION: c a b ;
[ t ] [ \ c \ tuple class< ] unit-test [ t ] [ \ c \ tuple class<= ] unit-test
[ f ] [ \ tuple \ c class< ] unit-test [ f ] [ \ tuple \ c class<= ] unit-test
[ t ] [ \ tuple-class \ class class< ] unit-test [ t ] [ \ tuple-class \ class class<= ] unit-test
[ f ] [ \ class \ tuple-class class< ] unit-test [ f ] [ \ class \ tuple-class class<= ] unit-test
TUPLE: tuple-example ; TUPLE: tuple-example ;
[ t ] [ \ null \ tuple-example class< ] unit-test [ t ] [ \ null \ tuple-example class<= ] unit-test
[ f ] [ \ object \ tuple-example class< ] unit-test [ f ] [ \ object \ tuple-example class<= ] unit-test
[ f ] [ \ object \ tuple-example class< ] unit-test [ f ] [ \ object \ tuple-example class<= ] unit-test
[ t ] [ \ tuple-example \ tuple class< ] unit-test [ t ] [ \ tuple-example \ tuple class<= ] unit-test
[ f ] [ \ tuple \ tuple-example class< ] unit-test [ f ] [ \ tuple \ tuple-example class<= ] unit-test
TUPLE: a1 ; TUPLE: a1 ;
TUPLE: b1 ; TUPLE: b1 ;
@ -84,57 +84,57 @@ UNION: x1 a1 b1 ;
UNION: y1 a1 c1 ; UNION: y1 a1 c1 ;
UNION: z1 b1 c1 ; UNION: z1 b1 c1 ;
[ f ] [ z1 x1 y1 class-and class< ] unit-test [ f ] [ z1 x1 y1 class-and class<= ] unit-test
[ t ] [ x1 y1 class-and a1 class< ] unit-test [ t ] [ x1 y1 class-and a1 class<= ] unit-test
[ f ] [ y1 z1 class-and x1 classes-intersect? ] unit-test [ f ] [ y1 z1 class-and x1 classes-intersect? ] unit-test
[ f ] [ b1 c1 class-or a1 b1 class-or a1 c1 class-and class-and class< ] unit-test [ f ] [ b1 c1 class-or a1 b1 class-or a1 c1 class-and class-and class<= ] unit-test
[ t ] [ a1 b1 class-or a1 c1 class-or class-and a1 class< ] unit-test [ t ] [ a1 b1 class-or a1 c1 class-or class-and a1 class<= ] unit-test
[ f ] [ a1 c1 class-or b1 c1 class-or class-and a1 b1 class-or classes-intersect? ] unit-test [ f ] [ a1 c1 class-or b1 c1 class-or class-and a1 b1 class-or classes-intersect? ] unit-test
[ f ] [ growable \ hi-tag classes-intersect? ] unit-test [ f ] [ growable \ hi-tag classes-intersect? ] unit-test
[ t ] [ [ t ] [
growable tuple sequence class-and class< growable tuple sequence class-and class<=
] unit-test ] unit-test
[ t ] [ [ t ] [
growable assoc class-and tuple class< growable assoc class-and tuple class<=
] unit-test ] unit-test
[ t ] [ object \ f \ f class-not class-or class< ] unit-test [ t ] [ object \ f \ f class-not class-or class<= ] unit-test
[ t ] [ fixnum class-not integer class-and bignum class= ] unit-test [ t ] [ fixnum class-not integer class-and bignum class= ] unit-test
[ f ] [ integer integer class-not classes-intersect? ] unit-test [ f ] [ integer integer class-not classes-intersect? ] unit-test
[ t ] [ array number class-not class< ] unit-test [ t ] [ array number class-not class<= ] unit-test
[ f ] [ bignum number class-not class< ] unit-test [ f ] [ bignum number class-not class<= ] unit-test
[ vector ] [ vector class-not class-not ] unit-test [ vector ] [ vector class-not class-not ] unit-test
[ t ] [ fixnum fixnum bignum class-or class< ] unit-test [ t ] [ fixnum fixnum bignum class-or class<= ] unit-test
[ f ] [ fixnum class-not integer class-and array class< ] unit-test [ f ] [ fixnum class-not integer class-and array class<= ] unit-test
[ f ] [ fixnum class-not integer class< ] unit-test [ f ] [ fixnum class-not integer class<= ] unit-test
[ f ] [ number class-not array class< ] unit-test [ f ] [ number class-not array class<= ] unit-test
[ f ] [ fixnum class-not array class< ] unit-test [ f ] [ fixnum class-not array class<= ] unit-test
[ t ] [ number class-not integer class-not class< ] unit-test [ t ] [ number class-not integer class-not class<= ] unit-test
[ t ] [ vector array class-not class-and vector class= ] unit-test [ t ] [ vector array class-not class-and vector class= ] unit-test
[ f ] [ fixnum class-not number class-and array classes-intersect? ] unit-test [ f ] [ fixnum class-not number class-and array classes-intersect? ] unit-test
[ f ] [ fixnum class-not integer class< ] unit-test [ f ] [ fixnum class-not integer class<= ] unit-test
[ t ] [ null class-not object class= ] unit-test [ t ] [ null class-not object class= ] unit-test
@ -147,7 +147,7 @@ UNION: z1 b1 c1 ;
[ t ] [ [ t ] [
fixnum class-not fixnum class-not
fixnum fixnum class-not class-or fixnum fixnum class-not class-or
class< class<=
] unit-test ] unit-test
! Test method inlining ! Test method inlining
@ -241,3 +241,14 @@ UNION: z1 b1 c1 ;
= =
] unit-test ] unit-test
] times ] times
SINGLETON: xxx
UNION: yyy xxx ;
[ { yyy xxx } ] [ { xxx yyy } sort-classes ] unit-test
[ { yyy xxx } ] [ { yyy xxx } sort-classes ] unit-test
[ { number integer ratio } ] [ { ratio number integer } sort-classes ] unit-test
[ { sequence number ratio } ] [ { ratio number sequence } sort-classes ] unit-test
[ +lt+ ] [ \ real sequence class<=> ] unit-test

View File

@ -2,16 +2,16 @@
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: kernel classes classes.builtin combinators accessors USING: kernel classes classes.builtin combinators accessors
sequences arrays vectors assocs namespaces words sorting layouts sequences arrays vectors assocs namespaces words sorting layouts
math hashtables kernel.private sets ; math hashtables kernel.private sets math.order ;
IN: classes.algebra IN: classes.algebra
: 2cache ( key1 key2 assoc quot -- value ) : 2cache ( key1 key2 assoc quot -- value )
>r >r 2array r> [ first2 ] r> compose cache ; inline >r >r 2array r> [ first2 ] r> compose cache ; inline
DEFER: (class<) DEFER: (class<=)
: class< ( first second -- ? ) : class<= ( first second -- ? )
class<-cache get [ (class<) ] 2cache ; class<=-cache get [ (class<=) ] 2cache ;
DEFER: (class-not) DEFER: (class-not)
@ -45,31 +45,31 @@ TUPLE: anonymous-complement class ;
C: <anonymous-complement> anonymous-complement C: <anonymous-complement> anonymous-complement
: superclass< ( first second -- ? ) : superclass<= ( first second -- ? )
>r superclass r> class< ; >r superclass r> class<= ;
: left-union-class< ( first second -- ? ) : left-union-class<= ( first second -- ? )
>r members r> [ class< ] curry all? ; >r members r> [ class<= ] curry all? ;
: right-union-class< ( first second -- ? ) : right-union-class<= ( first second -- ? )
members [ class< ] with contains? ; members [ class<= ] with contains? ;
: left-anonymous-union< ( first second -- ? ) : left-anonymous-union< ( first second -- ? )
>r members>> r> [ class< ] curry all? ; >r members>> r> [ class<= ] curry all? ;
: right-anonymous-union< ( first second -- ? ) : right-anonymous-union< ( first second -- ? )
members>> [ class< ] with contains? ; members>> [ class<= ] with contains? ;
: left-anonymous-intersection< ( first second -- ? ) : left-anonymous-intersection< ( first second -- ? )
>r members>> r> [ class< ] curry contains? ; >r members>> r> [ class<= ] curry contains? ;
: right-anonymous-intersection< ( first second -- ? ) : right-anonymous-intersection< ( first second -- ? )
members>> [ class< ] with all? ; members>> [ class<= ] with all? ;
: anonymous-complement< ( first second -- ? ) : anonymous-complement< ( first second -- ? )
[ class>> ] bi@ swap class< ; [ class>> ] bi@ swap class<= ;
: (class<) ( first second -- -1/0/1 ) : (class<=) ( first second -- -1/0/1 )
{ {
{ [ 2dup eq? ] [ 2drop t ] } { [ 2dup eq? ] [ 2drop t ] }
{ [ dup object eq? ] [ 2drop t ] } { [ dup object eq? ] [ 2drop t ] }
@ -77,13 +77,13 @@ C: <anonymous-complement> anonymous-complement
{ [ 2dup [ anonymous-complement? ] both? ] [ anonymous-complement< ] } { [ 2dup [ anonymous-complement? ] both? ] [ anonymous-complement< ] }
{ [ over anonymous-union? ] [ left-anonymous-union< ] } { [ over anonymous-union? ] [ left-anonymous-union< ] }
{ [ over anonymous-intersection? ] [ left-anonymous-intersection< ] } { [ over anonymous-intersection? ] [ left-anonymous-intersection< ] }
{ [ over members ] [ left-union-class< ] } { [ over members ] [ left-union-class<= ] }
{ [ dup anonymous-union? ] [ right-anonymous-union< ] } { [ dup anonymous-union? ] [ right-anonymous-union< ] }
{ [ dup anonymous-intersection? ] [ right-anonymous-intersection< ] } { [ dup anonymous-intersection? ] [ right-anonymous-intersection< ] }
{ [ over anonymous-complement? ] [ 2drop f ] } { [ over anonymous-complement? ] [ 2drop f ] }
{ [ dup anonymous-complement? ] [ class>> classes-intersect? not ] } { [ dup anonymous-complement? ] [ class>> classes-intersect? not ] }
{ [ dup members ] [ right-union-class< ] } { [ dup members ] [ right-union-class<= ] }
{ [ over superclass ] [ superclass< ] } { [ over superclass ] [ superclass<= ] }
[ 2drop f ] [ 2drop f ]
} cond ; } cond ;
@ -94,7 +94,7 @@ C: <anonymous-complement> anonymous-complement
members>> [ classes-intersect? ] with all? ; members>> [ classes-intersect? ] with all? ;
: anonymous-complement-intersect? ( first second -- ? ) : anonymous-complement-intersect? ( first second -- ? )
class>> class< not ; class>> class<= not ;
: union-class-intersect? ( first second -- ? ) : union-class-intersect? ( first second -- ? )
members [ classes-intersect? ] with contains? ; members [ classes-intersect? ] with contains? ;
@ -103,7 +103,7 @@ C: <anonymous-complement> anonymous-complement
{ {
{ [ over tuple eq? ] [ 2drop t ] } { [ over tuple eq? ] [ 2drop t ] }
{ [ over builtin-class? ] [ 2drop f ] } { [ over builtin-class? ] [ 2drop f ] }
{ [ over tuple-class? ] [ [ class< ] [ swap class< ] 2bi or ] } { [ over tuple-class? ] [ [ class<= ] [ swap class<= ] 2bi or ] }
[ swap classes-intersect? ] [ swap classes-intersect? ]
} cond ; } cond ;
@ -145,8 +145,8 @@ C: <anonymous-complement> anonymous-complement
: (class-and) ( first second -- class ) : (class-and) ( first second -- class )
{ {
{ [ 2dup class< ] [ drop ] } { [ 2dup class<= ] [ drop ] }
{ [ 2dup swap class< ] [ nip ] } { [ 2dup swap class<= ] [ nip ] }
{ [ 2dup classes-intersect? not ] [ 2drop null ] } { [ 2dup classes-intersect? not ] [ 2drop null ] }
{ [ dup members ] [ right-union-and ] } { [ dup members ] [ right-union-and ] }
{ [ dup anonymous-union? ] [ right-anonymous-union-and ] } { [ dup anonymous-union? ] [ right-anonymous-union-and ] }
@ -165,8 +165,8 @@ C: <anonymous-complement> anonymous-complement
: (class-or) ( first second -- class ) : (class-or) ( first second -- class )
{ {
{ [ 2dup class< ] [ nip ] } { [ 2dup class<= ] [ nip ] }
{ [ 2dup swap class< ] [ drop ] } { [ 2dup swap class<= ] [ drop ] }
{ [ dup anonymous-union? ] [ right-anonymous-union-or ] } { [ dup anonymous-union? ] [ right-anonymous-union-or ] }
{ [ over anonymous-union? ] [ left-anonymous-union-or ] } { [ over anonymous-union? ] [ left-anonymous-union-or ] }
[ 2array <anonymous-union> ] [ 2array <anonymous-union> ]
@ -180,22 +180,43 @@ C: <anonymous-complement> anonymous-complement
[ <anonymous-complement> ] [ <anonymous-complement> ]
} cond ; } cond ;
: largest-class ( seq -- n elt ) : class< ( first second -- ? )
dup [ {
[ 2dup class< >r swap class< not r> and ] { [ 2dup class<= not ] [ 2drop f ] }
with filter empty? { [ 2dup swap class<= not ] [ 2drop t ] }
] curry find [ "Topological sort failed" throw ] unless* ; [ [ rank-class ] bi@ < ]
} cond ;
: class-tie-breaker ( first second -- n )
2dup [ rank-class ] compare {
{ +lt+ [ 2drop +lt+ ] }
{ +gt+ [ 2drop +gt+ ] }
{ +eq+ [ <=> ] }
} case ;
: (class<=>) ( first second -- n )
{
{ [ 2dup class<= ] [
2dup swap class<=
[ class-tie-breaker ] [ 2drop +lt+ ] if
] }
{ [ 2dup swap class<= ] [
2dup class<=
[ class-tie-breaker ] [ 2drop +gt+ ] if
] }
[ class-tie-breaker ]
} cond ;
: class<=> ( first second -- n )
class<=>-cache get [ (class<=>) ] 2cache ;
: sort-classes ( seq -- newseq ) : sort-classes ( seq -- newseq )
>vector [ class<=> invert-comparison ] sort ;
[ dup empty? not ]
[ dup largest-class >r over delete-nth r> ]
[ ] unfold nip ;
: min-class ( class seq -- class/f ) : min-class ( class seq -- class/f )
over [ classes-intersect? ] curry filter over [ classes-intersect? ] curry filter
dup empty? [ 2drop f ] [ dup empty? [ 2drop f ] [
tuck [ class< ] with all? [ peek ] [ drop f ] if tuck [ class<= ] with all? [ peek ] [ drop f ] if
] if ; ] if ;
: (flatten-class) ( class -- ) : (flatten-class) ( class -- )
@ -212,7 +233,7 @@ C: <anonymous-complement> anonymous-complement
: flatten-builtin-class ( class -- assoc ) : flatten-builtin-class ( class -- assoc )
flatten-class [ flatten-class [
dup tuple class< [ 2drop tuple tuple ] when dup tuple class<= [ 2drop tuple tuple ] when
] assoc-map ; ] assoc-map ;
: class-types ( class -- seq ) : class-types ( class -- seq )

View File

@ -16,3 +16,5 @@ PREDICATE: builtin-class < class
M: hi-tag class hi-tag type>class ; M: hi-tag class hi-tag type>class ;
M: object class tag type>class ; M: object class tag type>class ;
M: builtin-class rank-class drop 0 ;

View File

@ -47,6 +47,7 @@ $nl
$nl $nl
"Classes can be inspected and operated upon:" "Classes can be inspected and operated upon:"
{ $subsection "class-operations" } { $subsection "class-operations" }
{ $subsection "class-linearization" }
{ $see-also "class-index" } ; { $see-also "class-index" } ;
ABOUT: "classes" ABOUT: "classes"

View File

@ -18,14 +18,14 @@ GENERIC: generic-update-test ( x -- y )
M: union-1 generic-update-test drop "union-1" ; M: union-1 generic-update-test drop "union-1" ;
[ f ] [ bignum union-1 class< ] unit-test [ f ] [ bignum union-1 class<= ] unit-test
[ t ] [ union-1 number class< ] unit-test [ t ] [ union-1 number class<= ] unit-test
[ "union-1" ] [ 1.0 generic-update-test ] unit-test [ "union-1" ] [ 1.0 generic-update-test ] unit-test
"IN: classes.tests USE: math USE: arrays UNION: union-1 rational array ;" eval "IN: classes.tests USE: math USE: arrays UNION: union-1 rational array ;" eval
[ t ] [ bignum union-1 class< ] unit-test [ t ] [ bignum union-1 class<= ] unit-test
[ f ] [ union-1 number class< ] unit-test [ f ] [ union-1 number class<= ] unit-test
[ "union-1" ] [ { 1.0 } generic-update-test ] unit-test [ "union-1" ] [ { 1.0 } generic-update-test ] unit-test
"IN: classes.tests USE: math PREDICATE: union-1 < integer even? ;" eval "IN: classes.tests USE: math PREDICATE: union-1 < integer even? ;" eval
@ -52,7 +52,7 @@ M: sequence-mixin collection-size length ;
M: assoc-mixin collection-size assoc-size ; M: assoc-mixin collection-size assoc-size ;
[ t ] [ array sequence-mixin class< ] unit-test [ t ] [ array sequence-mixin class<= ] unit-test
[ t ] [ { 1 2 3 } sequence-mixin? ] unit-test [ t ] [ { 1 2 3 } sequence-mixin? ] unit-test
[ 3 ] [ { 1 2 3 } collection-size ] unit-test [ 3 ] [ { 1 2 3 } collection-size ] unit-test
[ f ] [ H{ { 1 2 } { 2 3 } } sequence-mixin? ] unit-test [ f ] [ H{ { 1 2 } { 2 3 } } sequence-mixin? ] unit-test
@ -67,14 +67,14 @@ MIXIN: mx1
INSTANCE: integer mx1 INSTANCE: integer mx1
[ t ] [ integer mx1 class< ] unit-test [ t ] [ integer mx1 class<= ] unit-test
[ t ] [ mx1 integer class< ] unit-test [ t ] [ mx1 integer class<= ] unit-test
[ t ] [ mx1 number class< ] unit-test [ t ] [ mx1 number class<= ] unit-test
"IN: classes.tests USE: arrays INSTANCE: array mx1" eval "IN: classes.tests USE: arrays INSTANCE: array mx1" eval
[ t ] [ array mx1 class< ] unit-test [ t ] [ array mx1 class<= ] unit-test
[ f ] [ mx1 number class< ] unit-test [ f ] [ mx1 number class<= ] unit-test
[ \ mx1 forget ] with-compilation-unit [ \ mx1 forget ] with-compilation-unit
@ -94,14 +94,14 @@ UNION: redefine-bug-1 fixnum ;
UNION: redefine-bug-2 redefine-bug-1 quotation ; UNION: redefine-bug-2 redefine-bug-1 quotation ;
[ t ] [ fixnum redefine-bug-2 class< ] unit-test [ t ] [ fixnum redefine-bug-2 class<= ] unit-test
[ t ] [ quotation redefine-bug-2 class< ] unit-test [ t ] [ quotation redefine-bug-2 class<= ] unit-test
[ ] [ "IN: classes.tests USE: math UNION: redefine-bug-1 bignum ;" eval ] unit-test [ ] [ "IN: classes.tests USE: math UNION: redefine-bug-1 bignum ;" eval ] unit-test
[ t ] [ bignum redefine-bug-1 class< ] unit-test [ t ] [ bignum redefine-bug-1 class<= ] unit-test
[ f ] [ fixnum redefine-bug-2 class< ] unit-test [ f ] [ fixnum redefine-bug-2 class<= ] unit-test
[ t ] [ bignum redefine-bug-2 class< ] unit-test [ t ] [ bignum redefine-bug-2 class<= ] unit-test
USE: io.streams.string USE: io.streams.string

View File

@ -5,21 +5,24 @@ slots.private namespaces sequences strings words vectors math
quotations combinators sorting effects graphs vocabs ; quotations combinators sorting effects graphs vocabs ;
IN: classes IN: classes
SYMBOL: class<-cache SYMBOL: class<=-cache
SYMBOL: class<=>-cache
SYMBOL: class-not-cache SYMBOL: class-not-cache
SYMBOL: classes-intersect-cache SYMBOL: classes-intersect-cache
SYMBOL: class-and-cache SYMBOL: class-and-cache
SYMBOL: class-or-cache SYMBOL: class-or-cache
: init-caches ( -- ) : init-caches ( -- )
H{ } clone class<-cache set H{ } clone class<=-cache set
H{ } clone class<=>-cache set
H{ } clone class-not-cache set H{ } clone class-not-cache set
H{ } clone classes-intersect-cache set H{ } clone classes-intersect-cache set
H{ } clone class-and-cache set H{ } clone class-and-cache set
H{ } clone class-or-cache set ; H{ } clone class-or-cache set ;
: reset-caches ( -- ) : reset-caches ( -- )
class<-cache get clear-assoc class<=-cache get clear-assoc
class<=>-cache get clear-assoc
class-not-cache get clear-assoc class-not-cache get clear-assoc
classes-intersect-cache get clear-assoc classes-intersect-cache get clear-assoc
class-and-cache get clear-assoc class-and-cache get clear-assoc
@ -57,6 +60,8 @@ PREDICATE: predicate < word "predicating" word-prop >boolean ;
#! Output f for non-classes to work with algebra code #! Output f for non-classes to work with algebra code
dup class? [ "members" word-prop ] [ drop f ] if ; dup class? [ "members" word-prop ] [ drop f ] if ;
GENERIC: rank-class ( class -- n )
GENERIC: reset-class ( class -- ) GENERIC: reset-class ( class -- )
M: word reset-class drop ; M: word reset-class drop ;

View File

@ -9,6 +9,8 @@ PREDICATE: mixin-class < union-class "mixin" word-prop ;
M: mixin-class reset-class M: mixin-class reset-class
{ "class" "metaclass" "members" "mixin" } reset-props ; { "class" "metaclass" "members" "mixin" } reset-props ;
M: mixin-class rank-class drop 3 ;
: redefine-mixin-class ( class members -- ) : redefine-mixin-class ( class members -- )
dupd define-union-class dupd define-union-class
t "mixin" set-word-prop ; t "mixin" set-word-prop ;

View File

@ -30,3 +30,5 @@ M: predicate-class reset-class
"predicate-definition" "predicate-definition"
"superclass" "superclass"
} reset-props ; } reset-props ;
M: predicate-class rank-class drop 1 ;

View File

@ -233,8 +233,8 @@ TUPLE: laptop < computer battery ;
C: <laptop> laptop C: <laptop> laptop
[ t ] [ laptop tuple-class? ] unit-test [ t ] [ laptop tuple-class? ] unit-test
[ t ] [ laptop tuple class< ] unit-test [ t ] [ laptop tuple class<= ] unit-test
[ t ] [ laptop computer class< ] unit-test [ t ] [ laptop computer class<= ] unit-test
[ t ] [ laptop computer classes-intersect? ] unit-test [ t ] [ laptop computer classes-intersect? ] unit-test
[ ] [ "Pentium" 128 3 hours <laptop> "laptop" set ] unit-test [ ] [ "Pentium" 128 3 hours <laptop> "laptop" set ] unit-test
@ -266,8 +266,8 @@ TUPLE: server < computer rackmount ;
C: <server> server C: <server> server
[ t ] [ server tuple-class? ] unit-test [ t ] [ server tuple-class? ] unit-test
[ t ] [ server tuple class< ] unit-test [ t ] [ server tuple class<= ] unit-test
[ t ] [ server computer class< ] unit-test [ t ] [ server computer class<= ] unit-test
[ t ] [ server computer classes-intersect? ] unit-test [ t ] [ server computer classes-intersect? ] unit-test
[ ] [ "PowerPC" 64 "1U" <server> "server" set ] unit-test [ ] [ "PowerPC" 64 "1U" <server> "server" set ] unit-test
@ -286,8 +286,8 @@ test-server-slot-values
[ f ] [ "server" get laptop? ] unit-test [ f ] [ "server" get laptop? ] unit-test
[ f ] [ "laptop" get server? ] unit-test [ f ] [ "laptop" get server? ] unit-test
[ f ] [ server laptop class< ] unit-test [ f ] [ server laptop class<= ] unit-test
[ f ] [ laptop server class< ] unit-test [ f ] [ laptop server class<= ] unit-test
[ f ] [ laptop server classes-intersect? ] unit-test [ f ] [ laptop server classes-intersect? ] unit-test
[ f ] [ 1 2 <computer> laptop? ] unit-test [ f ] [ 1 2 <computer> laptop? ] unit-test
@ -306,9 +306,9 @@ TUPLE: electronic-device ;
[ ] [ "IN: classes.tuple.tests TUPLE: computer < electronic-device cpu ram ;" eval ] unit-test [ ] [ "IN: classes.tuple.tests TUPLE: computer < electronic-device cpu ram ;" eval ] unit-test
[ f ] [ electronic-device laptop class< ] unit-test [ f ] [ electronic-device laptop class<= ] unit-test
[ t ] [ server electronic-device class< ] unit-test [ t ] [ server electronic-device class<= ] unit-test
[ t ] [ laptop server class-or electronic-device class< ] unit-test [ t ] [ laptop server class-or electronic-device class<= ] unit-test
[ t ] [ "laptop" get electronic-device? ] unit-test [ t ] [ "laptop" get electronic-device? ] unit-test
[ t ] [ "laptop" get computer? ] unit-test [ t ] [ "laptop" get computer? ] unit-test

View File

@ -226,6 +226,8 @@ M: tuple-class reset-class
} reset-props } reset-props
] bi ; ] bi ;
M: tuple-class rank-class drop 0 ;
M: tuple clone M: tuple clone
(clone) dup delegate clone over set-delegate ; (clone) dup delegate clone over set-delegate ;

View File

@ -30,3 +30,5 @@ M: union-class update-class define-union-predicate ;
M: union-class reset-class M: union-class reset-class
{ "class" "metaclass" "members" } reset-props ; { "class" "metaclass" "members" } reset-props ;
M: union-class rank-class drop 2 ;

View File

@ -181,11 +181,11 @@ INSTANCE: constant value
: %unbox-c-ptr ( dst src -- ) : %unbox-c-ptr ( dst src -- )
dup operand-class { dup operand-class {
{ [ dup \ f class< ] [ drop %unbox-f ] } { [ dup \ f class<= ] [ drop %unbox-f ] }
{ [ dup simple-alien class< ] [ drop %unbox-alien ] } { [ dup simple-alien class<= ] [ drop %unbox-alien ] }
{ [ dup byte-array class< ] [ drop %unbox-byte-array ] } { [ dup byte-array class<= ] [ drop %unbox-byte-array ] }
{ [ dup bit-array class< ] [ drop %unbox-byte-array ] } { [ dup bit-array class<= ] [ drop %unbox-byte-array ] }
{ [ dup float-array class< ] [ drop %unbox-byte-array ] } { [ dup float-array class<= ] [ drop %unbox-byte-array ] }
[ drop %unbox-any-c-ptr ] [ drop %unbox-any-c-ptr ]
} cond ; inline } cond ; inline
@ -569,7 +569,7 @@ M: loc lazy-store
{ {
{ f [ drop t ] } { f [ drop t ] }
{ known-tag [ class-tag >boolean ] } { known-tag [ class-tag >boolean ] }
[ class< ] [ class<= ]
} case ; } case ;
: spec-matches? ( value spec -- ? ) : spec-matches? ( value spec -- ? )
@ -644,7 +644,7 @@ PRIVATE>
UNION: immediate fixnum POSTPONE: f ; UNION: immediate fixnum POSTPONE: f ;
: operand-immediate? ( operand -- ? ) : operand-immediate? ( operand -- ? )
operand-class immediate class< ; operand-class immediate class<= ;
: phantom-push ( obj -- ) : phantom-push ( obj -- )
1 phantom-datastack get adjust-phantom 1 phantom-datastack get adjust-phantom

View File

@ -4,22 +4,22 @@ generic.standard generic.math combinators ;
IN: generic IN: generic
ARTICLE: "method-order" "Method precedence" ARTICLE: "method-order" "Method precedence"
"Consider the case where a generic word has methods on two classes, say A and B, which share a non-empty intersection. If the generic word is called on an object which is an instance of both A and B, a choice of method must be made. If A is a subclass of B, the method for A to be called; this makes sense, because we're defining general behavior for instances of B, and refining it for instances of A. Conversely, if B is a subclass of A, then we expect B's method to be called. However, if neither is a subclass of the other, we have an ambiguous situation and undefined behavior will result. Either the method for A or B will be called, and there is no way to predict ahead of time." "Conceptually, method dispatch is implemented by testing the object against the predicate word for every class, in linear order (" { $link "class-linearization" } ")."
$nl
"The generic word system linearly orders all the methods on a generic word by their class. Conceptually, method dispatch is implemented by testing the object against the predicate word for every class, in order. If methods are defined on overlapping classes, this order will fail to be unique and the problem described above can occur."
$nl $nl
"Here is an example:" "Here is an example:"
{ $code { $code
"GENERIC: explain" "GENERIC: explain"
"M: number explain drop \"an integer\" print ;"
"M: sequence explain drop \"a sequence\" print ;"
"M: object explain drop \"an object\" print ;" "M: object explain drop \"an object\" print ;"
"M: number explain drop \"a number\" print ;"
"M: sequence explain drop \"a sequence\" print ;"
} }
"Neither " { $link number } " nor " { $link sequence } " are subclasses of each other, yet their intersection is the non-empty " { $link integer } " class. As a result, the outcome of calling " { $snippet "bar" } " with an " { $link integer } " on the stack is undefined - either one of the two methods may be called. This situation can lead to subtle bugs. To avoid it, explicitly disambiguate the method order by defining a method on the intersection. If in this case we want integers to behave like numbers, we would also define:" "The linear order is the following, from least-specific to most-specific:"
{ $code "M: integer explain drop \"an integer\" print ;" } { $code "{ object sequence number }" }
"On the other hand, if we want integers to behave like sequences here, we could define:" "Neither " { $link number } " nor " { $link sequence } " are subclasses of each other, yet their intersection is the non-empty " { $link integer } " class. Calling " { $snippet "explain" } " with an integer on the stack will print " { $snippet "a number" } " because " { $link number } " precedes " { $link sequence } " in the class linearization order. If this was not the desired outcome, define a method on the intersection:"
{ $code "M: integer explain drop \"a sequence\" print ;" } { $code "M: integer explain drop \"a sequence\" print ;" }
"The " { $link order } " word can be useful to clarify method dispatch order." "Now, the linear order is the following, from least-specific to most-specific:"
{ $code "{ object sequence number integer }" }
"The " { $link order } " word can be useful to clarify method dispatch order:"
{ $subsection order } ; { $subsection order } ;
ARTICLE: "generic-introspection" "Generic word introspection" ARTICLE: "generic-introspection" "Generic word introspection"

View File

@ -35,7 +35,7 @@ PREDICATE: method-spec < pair
GENERIC: effective-method ( ... generic -- method ) GENERIC: effective-method ( ... generic -- method )
: next-method-class ( class generic -- class/f ) : next-method-class ( class generic -- class/f )
order [ class< ] with filter reverse dup length 1 = order [ class<= ] with filter reverse dup length 1 =
[ drop f ] [ second ] if ; [ drop f ] [ second ] if ;
: next-method ( class generic -- class/f ) : next-method ( class generic -- class/f )

View File

@ -10,14 +10,14 @@ PREDICATE: math-class < class
dup null bootstrap-word eq? [ dup null bootstrap-word eq? [
drop f drop f
] [ ] [
number bootstrap-word class< number bootstrap-word class<=
] if ; ] if ;
: last/first ( seq -- pair ) [ peek ] [ first ] bi 2array ; : last/first ( seq -- pair ) [ peek ] [ first ] bi 2array ;
: math-precedence ( class -- pair ) : math-precedence ( class -- pair )
{ {
{ [ dup null class< ] [ drop { -1 -1 } ] } { [ dup null class<= ] [ drop { -1 -1 } ] }
{ [ dup math-class? ] [ class-types last/first ] } { [ dup math-class? ] [ class-types last/first ] }
[ drop { 100 100 } ] [ drop { 100 100 } ]
} cond ; } cond ;

View File

@ -26,8 +26,8 @@ M: method-body engine>quot 1quotation ;
alist>quot ; alist>quot ;
: split-methods ( assoc class -- first second ) : split-methods ( assoc class -- first second )
[ [ nip class< not ] curry assoc-filter ] [ [ nip class<= not ] curry assoc-filter ]
[ [ nip class< ] curry assoc-filter ] 2bi ; [ [ nip class<= ] curry assoc-filter ] 2bi ;
: convert-methods ( assoc class word -- assoc' ) : convert-methods ( assoc class word -- assoc' )
over >r >r split-methods dup assoc-empty? [ over >r >r split-methods dup assoc-empty? [

View File

@ -11,7 +11,7 @@ C: <predicate-dispatch-engine> predicate-dispatch-engine
[ >r "predicate" word-prop picker prepend r> ] assoc-map ; [ >r "predicate" word-prop picker prepend r> ] assoc-map ;
: keep-going? ( assoc -- ? ) : keep-going? ( assoc -- ? )
assumed get swap second first class< ; assumed get swap second first class<= ;
: prune-redundant-predicates ( assoc -- default assoc' ) : prune-redundant-predicates ( assoc -- default assoc' )
{ {

View File

@ -143,7 +143,7 @@ M: literal-constraint constraint-satisfied?
[ swap literal>> eql? ] [ 2drop f ] if ; [ swap literal>> eql? ] [ 2drop f ] if ;
M: class-constraint constraint-satisfied? M: class-constraint constraint-satisfied?
[ value>> value-class* ] [ class>> ] bi class< ; [ value>> value-class* ] [ class>> ] bi class<= ;
M: pair apply-constraint M: pair apply-constraint
first2 2dup constraints get set-at first2 2dup constraints get set-at

View File

@ -80,9 +80,6 @@ M: number equal? number= ;
M: real hashcode* nip >fixnum ; M: real hashcode* nip >fixnum ;
! real and sequence overlap. we disambiguate:
M: integer hashcode* nip >fixnum ;
GENERIC: fp-nan? ( x -- ? ) GENERIC: fp-nan? ( x -- ? )
M: object fp-nan? M: object fp-nan?

View File

@ -7,17 +7,13 @@ SYMBOL: +lt+
SYMBOL: +eq+ SYMBOL: +eq+
SYMBOL: +gt+ SYMBOL: +gt+
GENERIC: <=> ( obj1 obj2 -- symbol )
: (<=>) ( a b -- symbol )
2dup < [ 2drop +lt+ ] [ number= +eq+ +gt+ ? ] if ; inline
: invert-comparison ( symbol -- new-symbol ) : invert-comparison ( symbol -- new-symbol )
#! Can't use case, index or nth here #! Can't use case, index or nth here
dup +lt+ eq? [ drop +gt+ ] [ +eq+ eq? +eq+ +lt+ ? ] if ; dup +lt+ eq? [ drop +gt+ ] [ +eq+ eq? +eq+ +lt+ ? ] if ;
M: real <=> (<=>) ; GENERIC: <=> ( obj1 obj2 -- symbol )
M: integer <=> (<=>) ;
M: real <=> 2dup < [ 2drop +lt+ ] [ number= +eq+ +gt+ ? ] if ;
GENERIC: before? ( obj1 obj2 -- ? ) GENERIC: before? ( obj1 obj2 -- ? )
GENERIC: after? ( obj1 obj2 -- ? ) GENERIC: after? ( obj1 obj2 -- ? )

View File

@ -154,9 +154,9 @@ SYMBOL: potential-loops
node-literal t node-literal t
] [ ] [
node-class { node-class {
{ [ dup null class< ] [ drop f f ] } { [ dup null class<= ] [ drop f f ] }
{ [ dup \ f class-not class< ] [ drop t t ] } { [ dup \ f class-not class<= ] [ drop t t ] }
{ [ dup \ f class< ] [ drop f t ] } { [ dup \ f class<= ] [ drop f t ] }
[ drop f f ] [ drop f f ]
} cond } cond
] if ; ] if ;

View File

@ -77,7 +77,7 @@ DEFER: (flat-length)
float real float real
complex number complex number
object object
} [ class< ] with find nip ; } [ class<= ] with find nip ;
: inlining-math-method ( #call word -- quot/f ) : inlining-math-method ( #call word -- quot/f )
swap node-input-classes swap node-input-classes
@ -111,7 +111,7 @@ DEFER: (flat-length)
: comparable? ( actual testing -- ? ) : comparable? ( actual testing -- ? )
#! If actual is a subset of testing or if the two classes #! If actual is a subset of testing or if the two classes
#! are disjoint, return t. #! are disjoint, return t.
2dup class< >r classes-intersect? not r> or ; 2dup class<= >r classes-intersect? not r> or ;
: optimize-predicate? ( #call -- ? ) : optimize-predicate? ( #call -- ? )
dup node-param "predicating" word-prop dup [ dup node-param "predicating" word-prop dup [
@ -132,7 +132,7 @@ DEFER: (flat-length)
: evaluate-predicate ( #call -- ? ) : evaluate-predicate ( #call -- ? )
dup node-param "predicating" word-prop >r dup node-param "predicating" word-prop >r
node-class-first r> class< ; node-class-first r> class<= ;
: optimize-predicate ( #call -- node ) : optimize-predicate ( #call -- node )
#! If the predicate is followed by a branch we fold it #! If the predicate is followed by a branch we fold it

View File

@ -96,7 +96,7 @@ optimizer.math.partial generic.standard system accessors ;
: math-closure ( class -- newclass ) : math-closure ( class -- newclass )
{ null fixnum bignum integer rational float real number } { null fixnum bignum integer rational float real number }
[ class< ] with find nip number or ; [ class<= ] with find nip number or ;
: fits? ( interval class -- ? ) : fits? ( interval class -- ? )
"interval" word-prop dup "interval" word-prop dup
@ -108,7 +108,7 @@ optimizer.math.partial generic.standard system accessors ;
dup r> at swap or ; dup r> at swap or ;
: won't-overflow? ( interval node -- ? ) : won't-overflow? ( interval node -- ? )
node-in-d [ value-class* fixnum class< ] all? node-in-d [ value-class* fixnum class<= ] all?
swap fixnum fits? and ; swap fixnum fits? and ;
: post-process ( class interval node -- classes intervals ) : post-process ( class interval node -- classes intervals )
@ -214,7 +214,7 @@ optimizer.math.partial generic.standard system accessors ;
: twiddle-interval ( i1 -- i2 ) : twiddle-interval ( i1 -- i2 )
dup [ dup [
node get node-in-d node get node-in-d
[ value-class* integer class< ] all? [ value-class* integer class<= ] all?
[ integral-closure ] when [ integral-closure ] when
] when ; ] when ;
@ -293,7 +293,7 @@ most-negative-fixnum most-positive-fixnum [a,b]
! Removing overflow checks ! Removing overflow checks
: remove-overflow-check? ( #call -- ? ) : remove-overflow-check? ( #call -- ? )
dup out-d>> first node-class dup out-d>> first node-class
[ fixnum class< ] [ null eq? not ] bi and ; [ fixnum class<= ] [ null eq? not ] bi and ;
{ {
{ + [ fixnum+fast ] } { + [ fixnum+fast ] }
@ -356,7 +356,7 @@ most-negative-fixnum most-positive-fixnum [a,b]
dup #call? [ node-param eq? ] [ 2drop f ] if ; dup #call? [ node-param eq? ] [ 2drop f ] if ;
: coerced-to-fixnum? ( #call -- ? ) : coerced-to-fixnum? ( #call -- ? )
dup dup node-in-d [ node-class integer class< ] with all? dup dup node-in-d [ node-class integer class<= ] with all?
[ \ >fixnum consumed-by? ] [ drop f ] if ; [ \ >fixnum consumed-by? ] [ drop f ] if ;
{ {
@ -377,7 +377,7 @@ most-negative-fixnum most-positive-fixnum [a,b]
: convert-rem-to-and? ( #call -- ? ) : convert-rem-to-and? ( #call -- ? )
dup node-in-d { dup node-in-d {
{ [ 2dup first node-class integer class< not ] [ f ] } { [ 2dup first node-class integer class<= not ] [ f ] }
{ [ 2dup second node-literal integer? not ] [ f ] } { [ 2dup second node-literal integer? not ] [ f ] }
{ [ 2dup second node-literal power-of-2? not ] [ f ] } { [ 2dup second node-literal power-of-2? not ] [ f ] }
[ t ] [ t ]

View File

@ -12,7 +12,7 @@ SYMBOL: @
@ get [ eq? ] [ @ set t ] if* ; @ get [ eq? ] [ @ set t ] if* ;
: match-class ( value spec -- ? ) : match-class ( value spec -- ? )
>r node get swap node-class r> class< ; >r node get swap node-class r> class<= ;
: value-match? ( value spec -- ? ) : value-match? ( value spec -- ? )
{ {

View File

@ -0,0 +1,8 @@
IN: db.pooling.tests
USING: db.pooling tools.test ;
\ <pool> must-infer
{ 2 0 } [ [ ] with-db-pool ] must-infer-as
{ 1 0 } [ [ ] with-pooled-connection ] must-infer-as

View File

@ -0,0 +1,43 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel arrays namespaces sequences continuations
destructors db ;
IN: db.pooling
TUPLE: pool db params connections ;
: <pool> ( db params -- pool )
V{ } clone pool boa ;
M: pool dispose [ dispose-each f ] change-connections drop ;
: with-db-pool ( db params quot -- )
>r <pool> r> [ pool swap with-variable ] curry with-disposal ; inline
TUPLE: return-connection db pool ;
: return-connection ( db pool -- )
connections>> push ;
: new-connection ( pool -- )
[ [ db>> ] [ params>> ] bi make-db db-open ] keep
return-connection ;
: acquire-connection ( pool -- db )
[ dup connections>> empty? ] [ dup new-connection ] [ ] while
connections>> pop ;
: (with-pooled-connection) ( db pool quot -- )
[ >r drop db r> with-variable ]
[ drop return-connection ]
3bi ; inline
: with-pooled-connection ( pool quot -- )
>r [ acquire-connection ] keep r>
[ (with-pooled-connection) ] [ ] [ 2drop dispose ] cleanup ; inline
M: return-connection dispose
[ db>> ] [ pool>> ] bi return-connection ;
: return-connection-later ( db pool -- )
\ return-connection boa add-always-destructor ;

View File

@ -21,11 +21,6 @@ M: string json-print ( obj -- )
M: number json-print ( num -- ) M: number json-print ( num -- )
number>string write ; number>string write ;
! sequence and number overlap, we provide an explicit
! disambiguation method
M: integer json-print ( num -- )
number>string write ;
M: sequence json-print ( array -- ) M: sequence json-print ( array -- )
CHAR: [ write1 [ >json ] map "," join write CHAR: ] write1 ; CHAR: [ write1 [ >json ] map "," join write CHAR: ] write1 ;

View File

@ -86,12 +86,12 @@ SYMBOL: total
[ [
{ {
{ [ 2dup eq? ] [ +eq+ ] } { [ 2dup eq? ] [ +eq+ ] }
{ [ 2dup [ class< ] 2keep swap class< and ] [ +eq+ ] } { [ 2dup [ class<= ] [ swap class<= ] 2bi and ] [ +eq+ ] }
{ [ 2dup class< ] [ +lt+ ] } { [ 2dup class<= ] [ +lt+ ] }
{ [ 2dup swap class< ] [ +gt+ ] } { [ 2dup swap class<= ] [ +gt+ ] }
[ +eq+ ] [ +eq+ ]
} cond 2nip } cond 2nip
] 2map [ zero? not ] find nip +eq+ or ; ] 2map [ +eq+ eq? not ] find nip +eq+ or ;
: sort-methods ( alist -- alist' ) : sort-methods ( alist -- alist' )
[ [ first ] bi@ classes< ] topological-sort ; [ [ first ] bi@ classes< ] topological-sort ;

View File

@ -144,7 +144,8 @@ IN: tools.deploy.shaker
classes:class-and-cache classes:class-and-cache
classes:class-not-cache classes:class-not-cache
classes:class-or-cache classes:class-or-cache
classes:class<-cache classes:class<=-cache
classes:class<=>-cache
classes:classes-intersect-cache classes:classes-intersect-cache
classes:update-map classes:update-map
command-line:main-vocab-hook command-line:main-vocab-hook