factor/extra/multi-methods/multi-methods.factor

257 lines
6.8 KiB
Factor
Raw Normal View History

2008-01-06 10:22:26 -05:00
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math sequences vectors classes combinators
2008-01-06 10:22:26 -05:00
arrays words assocs parser namespaces definitions
2008-01-06 11:13:54 -05:00
prettyprint prettyprint.backend quotations arrays.lib
2008-02-08 02:08:23 -05:00
debugger io compiler.units kernel.private effects ;
IN: multi-methods
2008-02-08 02:08:23 -05:00
GENERIC: generic-prologue ( combination -- quot )
2008-01-06 10:22:26 -05:00
2008-02-08 02:08:23 -05:00
GENERIC: method-prologue ( combination -- quot )
2008-01-06 10:22:26 -05:00
: maximal-element ( seq quot -- n elt )
dupd [
swapd [ call 0 < ] 2curry subset empty?
] 2curry find [ "Topological sort failed" throw ] unless* ;
inline
: topological-sort ( seq quot -- newseq )
>r >vector [ dup empty? not ] r>
[ dupd maximal-element >r over delete-nth r> ] curry
[ ] unfold nip ; inline
: classes< ( seq1 seq2 -- -1/0/1 )
[
{
{ [ 2dup eq? ] [ 0 ] }
2008-02-08 02:08:23 -05:00
{ [ 2dup [ class< ] 2keep swap class< and ] [ 0 ] }
{ [ 2dup class< ] [ -1 ] }
{ [ 2dup swap class< ] [ 1 ] }
{ [ t ] [ 0 ] }
} cond 2nip
] 2map [ zero? not ] find nip 0 or ;
2008-01-06 10:22:26 -05:00
: picker ( n -- quot )
{
{ 0 [ [ dup ] ] }
{ 1 [ [ over ] ] }
{ 2 [ [ pick ] ] }
[ 1- picker [ >r ] swap [ r> swap ] 3append ]
} case ;
2008-01-06 11:13:54 -05:00
: (multi-predicate) ( class picker -- quot )
swap "predicate" word-prop append ;
: multi-predicate ( classes -- quot )
2008-01-06 11:13:54 -05:00
dup length <reversed>
[ picker 2array ] 2map
[ drop object eq? not ] assoc-subset
dup empty? [ drop [ t ] ] [
[ (multi-predicate) ] { } assoc>map
unclip [ swap [ f ] \ if 3array append [ ] like ] reduce
] if ;
: methods ( word -- alist )
"multi-methods" word-prop >alist ;
2008-01-06 10:22:26 -05:00
2008-02-08 02:08:23 -05:00
: make-method-def ( quot classes generic -- quot )
[
swap [ declare ] curry %
"multi-combination" word-prop method-prologue %
%
] [ ] make ;
TUPLE: method word def classes generic loc ;
PREDICATE: word method-body "multi-method" word-prop >boolean ;
M: method-body stack-effect
"multi-method" word-prop method-generic stack-effect ;
: method-word-name ( classes generic -- string )
[
word-name %
"-(" % [ "," % ] [ word-name % ] interleave ")" %
] "" make ;
: <method-word> ( quot classes generic -- word )
#! We xref here because the "multi-method" word-prop isn't
#! set yet so crossref? yields f.
[ make-method-def ] 2keep
method-word-name f <word>
dup rot define
dup xref ;
: <method> ( quot classes generic -- method )
[ <method-word> ] 3keep f \ method construct-boa
dup method-word over "multi-method" set-word-prop ;
2008-01-06 11:13:54 -05:00
TUPLE: no-method arguments generic ;
2008-01-06 11:13:54 -05:00
: no-method ( argument-count generic -- * )
>r narray r> \ no-method construct-boa throw ; inline
: argument-count ( methods -- n )
dup assoc-empty? [ drop 0 ] [
keys [ length ] map supremum
] if ;
: multi-dispatch-quot ( methods generic -- quot )
2008-02-08 02:08:23 -05:00
>r [
[
>r multi-predicate r> method-word 1quotation
] assoc-map
] keep argument-count
2008-01-06 11:13:54 -05:00
r> [ no-method ] 2curry
swap reverse alist>quot ;
2008-01-06 10:22:26 -05:00
: congruify-methods ( alist -- alist' )
2008-01-06 11:13:54 -05:00
dup argument-count [
swap >r object pad-left [ \ f or ] map r>
] curry assoc-map ;
2008-01-06 10:22:26 -05:00
: sorted-methods ( alist -- alist' )
[ [ first ] 2apply classes< ] topological-sort ;
2008-01-06 11:13:54 -05:00
: niceify-method [ dup \ f eq? [ drop f ] when ] map ;
M: no-method error.
"Type check error" print
nl
"Generic word " write dup no-method-generic pprint
" does not have a method applicable to inputs:" print
dup no-method-arguments short.
nl
"Inputs have signature:" print
dup no-method-arguments [ class ] map niceify-method .
nl
"Defined methods in topological order: " print
no-method-generic
methods congruify-methods sorted-methods keys
[ niceify-method ] map stack. ;
2008-01-06 10:22:26 -05:00
TUPLE: standard-combination ;
2008-02-08 02:08:23 -05:00
M: standard-combination method-prologue drop [ ] ;
M: standard-combination generic-prologue drop [ ] ;
2008-01-06 10:22:26 -05:00
2008-02-08 02:08:23 -05:00
: make-generic ( generic -- quot )
dup "multi-combination" word-prop generic-prologue swap
[ methods congruify-methods sorted-methods ] keep
multi-dispatch-quot append ;
2008-01-06 10:22:26 -05:00
TUPLE: hook-combination var ;
2008-02-08 02:08:23 -05:00
M: hook-combination method-prologue
drop [ drop ] ;
2008-01-06 10:22:26 -05:00
2008-02-08 02:08:23 -05:00
M: hook-combination generic-prologue
hook-combination-var [ get ] curry ;
2008-01-06 10:22:26 -05:00
2008-02-08 02:08:23 -05:00
: update-generic ( word -- )
dup make-generic define ;
2008-01-06 10:22:26 -05:00
: define-generic ( word combination -- )
2008-02-08 02:08:23 -05:00
over "multi-combination" word-prop over = [
2drop
] [
dupd "multi-combination" set-word-prop
dup H{ } clone "multi-methods" set-word-prop
update-generic
] if ;
2008-01-06 10:22:26 -05:00
: define-standard-generic ( word -- )
T{ standard-combination } define-generic ;
: GENERIC:
2008-01-06 10:22:26 -05:00
CREATE define-standard-generic ; parsing
: define-hook-generic ( word var -- )
hook-combination construct-boa define-generic ;
: HOOK:
CREATE scan-word define-hook-generic ; parsing
: method ( classes word -- method )
"multi-methods" word-prop at ;
: with-methods ( word quot -- )
over >r >r "multi-methods" word-prop
2008-02-08 02:08:23 -05:00
r> call r> update-generic ; inline
2008-02-08 02:08:23 -05:00
: define-method ( quot classes generic -- )
>r [ bootstrap-word ] map r>
[ <method> ] 2keep
2008-01-06 10:22:26 -05:00
[ set-at ] with-methods ;
2008-02-08 02:08:23 -05:00
: forget-method ( classes generic -- )
2008-01-06 10:22:26 -05:00
[ delete-at ] with-methods ;
2008-02-08 02:08:23 -05:00
: method>spec ( method -- spec )
dup method-classes swap method-generic add* ;
: parse-method ( -- quot classes generic )
parse-definition dup 2 tail over second rot first ;
: METHOD:
2008-01-06 10:22:26 -05:00
location
2008-02-08 02:08:23 -05:00
>r parse-method [ define-method ] 2keep add* r>
2008-01-06 10:22:26 -05:00
remember-definition ; parsing
! For compatibility
: M:
2008-02-08 02:08:23 -05:00
scan-word 1array scan-word parse-definition
-rot define-method ; parsing
2008-01-06 10:22:26 -05:00
! Definition protocol. We qualify core generics here
USE: qualified
QUALIFIED: syntax
PREDICATE: word generic
"multi-combination" word-prop >boolean ;
PREDICATE: word standard-generic
"multi-combination" word-prop standard-combination? ;
PREDICATE: word hook-generic
"multi-combination" word-prop hook-combination? ;
syntax:M: standard-generic definer drop \ GENERIC: f ;
syntax:M: standard-generic definition drop f ;
syntax:M: hook-generic definer drop \ HOOK: f ;
syntax:M: hook-generic definition drop f ;
syntax:M: hook-generic synopsis*
2008-01-06 11:13:54 -05:00
dup definer.
dup seeing-word
dup pprint-word
2008-01-06 10:22:26 -05:00
dup "multi-combination" word-prop
hook-combination-var pprint-word stack-effect. ;
PREDICATE: array method-spec
unclip generic? >r [ class? ] all? r> and ;
syntax:M: method-spec where
2008-02-08 02:08:23 -05:00
dup unclip method [ method-loc ] [ second where ] ?if ;
2008-01-06 10:22:26 -05:00
syntax:M: method-spec set-where
unclip method set-method-loc ;
syntax:M: method-spec definer
drop \ METHOD: \ ; ;
syntax:M: method-spec definition
2008-02-08 02:08:23 -05:00
unclip method dup [ method-def ] when ;
2008-01-06 10:22:26 -05:00
syntax:M: method-spec synopsis*
2008-01-06 11:13:54 -05:00
dup definer.
2008-01-06 10:22:26 -05:00
unclip pprint* pprint* ;
2008-01-14 19:11:32 -05:00
syntax:M: method-spec forget*
2008-02-08 02:08:23 -05:00
unclip forget-method ;