2008-01-06 10:22:26 -05:00
|
|
|
! Copyright (C) 2008 Slava Pestov.
|
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2008-01-05 23:07:12 -05:00
|
|
|
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 ;
|
2008-01-05 23:07:12 -05:00
|
|
|
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
|
|
|
|
2008-01-05 23:07:12 -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 ] }
|
2008-01-05 23:07:12 -05:00
|
|
|
{ [ 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 ;
|
|
|
|
|
2008-01-05 23:07:12 -05:00
|
|
|
: 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-05 23:07:12 -05:00
|
|
|
|
2008-01-06 11:13:54 -05:00
|
|
|
TUPLE: no-method arguments generic ;
|
2008-01-05 23:07:12 -05:00
|
|
|
|
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' )
|
2008-01-05 23:07:12 -05:00
|
|
|
[ [ 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 ;
|
2008-01-05 23:07:12 -05:00
|
|
|
|
|
|
|
: 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-01-05 23:07:12 -05:00
|
|
|
|
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 ;
|
2008-01-05 23:07:12 -05:00
|
|
|
|
|
|
|
: 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 ;
|