2019-10-18 09:05:06 -04:00
|
|
|
! Copyright (C) 2004, 2007 Slava Pestov.
|
2006-05-10 18:51:18 -04:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2019-10-18 09:05:08 -04:00
|
|
|
USING: arrays generic assocs hashtables inference kernel
|
|
|
|
|
math namespaces sequences words parser intervals ;
|
2019-10-18 09:05:06 -04:00
|
|
|
IN: class-inference
|
|
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
! Variables used by the class inferencer
|
2005-07-28 15:17:31 -04:00
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
! Current value --> literal mapping
|
|
|
|
|
SYMBOL: value-literals
|
2006-05-02 14:16:59 -04:00
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
! Current value --> interval mapping
|
|
|
|
|
SYMBOL: value-intervals
|
2005-07-28 15:17:31 -04:00
|
|
|
|
|
|
|
|
! Current value --> class mapping
|
|
|
|
|
SYMBOL: value-classes
|
|
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
: set-value-interval* ( interval value -- )
|
|
|
|
|
value-intervals get set-at ;
|
|
|
|
|
|
|
|
|
|
M: interval-constraint apply-constraint
|
|
|
|
|
dup interval-constraint-interval
|
|
|
|
|
swap interval-constraint-value set-value-interval* ;
|
|
|
|
|
|
|
|
|
|
: set-class-interval ( class value -- )
|
|
|
|
|
>r "interval" word-prop dup
|
|
|
|
|
[ r> set-value-interval* ] [ r> 2drop ] if ;
|
2005-07-28 15:17:31 -04:00
|
|
|
|
2006-01-22 16:56:27 -05:00
|
|
|
: set-value-class* ( class value -- )
|
2019-10-18 09:05:08 -04:00
|
|
|
over [
|
|
|
|
|
2dup set-class-interval
|
|
|
|
|
2dup <class-constraint> assume
|
|
|
|
|
] when
|
|
|
|
|
value-classes get set-at ;
|
2005-07-28 18:20:31 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
M: class-constraint apply-constraint
|
|
|
|
|
dup class-constraint-class
|
|
|
|
|
swap class-constraint-value set-value-class* ;
|
2005-07-28 18:20:31 -04:00
|
|
|
|
2006-01-22 16:56:27 -05:00
|
|
|
: set-value-literal* ( literal value -- )
|
|
|
|
|
over class over set-value-class*
|
2019-10-18 09:05:08 -04:00
|
|
|
over real? [ over [a,a] over set-value-interval* ] when
|
|
|
|
|
2dup <literal-constraint> assume
|
|
|
|
|
value-literals get set-at ;
|
2005-07-28 18:20:31 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
M: literal-constraint apply-constraint
|
|
|
|
|
dup literal-constraint-literal
|
|
|
|
|
swap literal-constraint-value set-value-literal* ;
|
|
|
|
|
|
|
|
|
|
! For conditionals, an assoc of child node # --> constraint
|
|
|
|
|
GENERIC: child-constraints ( node -- seq )
|
2005-07-28 18:20:31 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
GENERIC: infer-classes-before ( node -- )
|
2005-07-28 15:17:31 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
GENERIC: infer-classes-around ( node -- )
|
2005-07-28 18:20:31 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
M: node infer-classes-before drop ;
|
2005-07-28 18:20:31 -04:00
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
M: node child-constraints
|
|
|
|
|
node-children length dup zero? [ drop f ] [ f <array> ] if ;
|
|
|
|
|
|
|
|
|
|
: value-literal* ( value -- obj ? )
|
|
|
|
|
value-literals get at* ;
|
|
|
|
|
|
|
|
|
|
M: literal-constraint constraint-satisfied?
|
|
|
|
|
dup literal-constraint-value value-literal*
|
|
|
|
|
[ swap literal-constraint-literal eql? ] [ 2drop f ] if ;
|
2005-07-28 18:20:31 -04:00
|
|
|
|
2006-01-22 16:56:27 -05:00
|
|
|
: value-class* ( value -- class )
|
2019-10-18 09:05:08 -04:00
|
|
|
value-classes get at [ object ] unless* ;
|
2005-07-28 15:17:31 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
M: class-constraint constraint-satisfied?
|
|
|
|
|
dup class-constraint-value value-class*
|
|
|
|
|
swap class-constraint-class class< ;
|
|
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
: value-interval* ( value -- interval/f )
|
|
|
|
|
value-intervals get at ;
|
2019-10-18 09:05:06 -04:00
|
|
|
|
|
|
|
|
M: pair apply-constraint
|
2019-10-18 09:05:08 -04:00
|
|
|
first2 2dup constraints get set-at
|
2019-10-18 09:05:06 -04:00
|
|
|
constraint-satisfied? [ apply-constraint ] [ drop ] if ;
|
|
|
|
|
|
|
|
|
|
M: pair constraint-satisfied?
|
|
|
|
|
first constraint-satisfied? ;
|
2005-07-28 18:20:31 -04:00
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
: extract-keys ( seq assoc -- newassoc )
|
|
|
|
|
[ drop swap memq? ] assoc-subset-with f assoc-like ;
|
|
|
|
|
|
2005-07-28 15:17:31 -04:00
|
|
|
: annotate-node ( node -- )
|
|
|
|
|
#! Annotate the node with the currently-inferred set of
|
|
|
|
|
#! value classes.
|
2005-09-09 22:34:24 -04:00
|
|
|
dup node-values
|
2019-10-18 09:05:08 -04:00
|
|
|
dup value-intervals get extract-keys pick set-node-intervals
|
|
|
|
|
dup value-classes get extract-keys pick set-node-classes
|
|
|
|
|
dup value-literals get extract-keys pick set-node-literals
|
|
|
|
|
2drop ;
|
2005-07-28 15:17:31 -04:00
|
|
|
|
|
|
|
|
: intersect-classes ( classes values -- )
|
2019-10-18 09:05:08 -04:00
|
|
|
[ [ value-class* class-and ] keep set-value-class* ] 2each ;
|
|
|
|
|
|
|
|
|
|
: intersect-intervals ( intervals values -- )
|
2006-01-22 16:40:18 -05:00
|
|
|
[
|
2019-10-18 09:05:08 -04:00
|
|
|
[ value-interval* interval-intersect ] keep
|
|
|
|
|
set-value-interval*
|
2006-01-22 16:40:18 -05:00
|
|
|
] 2each ;
|
2005-07-28 15:17:31 -04:00
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
: predicate-constraints ( class #call -- )
|
2019-10-18 09:05:06 -04:00
|
|
|
[
|
|
|
|
|
0 `input class,
|
|
|
|
|
general-t 0 `output class,
|
|
|
|
|
] set-constraints ;
|
2005-09-09 22:34:24 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
: compute-constraints ( #call -- )
|
2019-10-18 09:05:08 -04:00
|
|
|
dup node-param "constraints" word-prop [
|
2005-08-02 01:28:38 -04:00
|
|
|
call
|
|
|
|
|
] [
|
2019-10-18 09:05:08 -04:00
|
|
|
dup node-param "predicating" word-prop dup
|
|
|
|
|
[ swap predicate-constraints ] [ 2drop ] if
|
2006-05-02 06:13:43 -04:00
|
|
|
] if* ;
|
2005-08-02 01:28:38 -04:00
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
: default-output-classes ( word -- classes )
|
|
|
|
|
"inferred-effect" word-prop effect-out
|
|
|
|
|
dup [ class? ] all? [ drop f ] unless ;
|
|
|
|
|
|
|
|
|
|
: compute-output-classes ( node word -- classes intervals )
|
|
|
|
|
dup node-param "output-classes" word-prop dup
|
|
|
|
|
[ call ] [ 2drop f f ] if ;
|
|
|
|
|
|
|
|
|
|
: output-classes ( node -- classes intervals )
|
|
|
|
|
dup compute-output-classes
|
|
|
|
|
>r [ ] [ node-param default-output-classes ] ?if r> ;
|
|
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
M: #call infer-classes-before
|
|
|
|
|
dup compute-constraints
|
2019-10-18 09:05:08 -04:00
|
|
|
dup node-out-d swap output-classes
|
|
|
|
|
>r over intersect-classes
|
|
|
|
|
r> swap intersect-intervals ;
|
2005-07-28 15:17:31 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
M: #push infer-classes-before
|
2006-04-17 17:17:34 -04:00
|
|
|
node-out-d
|
2006-01-22 18:07:05 -05:00
|
|
|
[ [ value-literal ] keep set-value-literal* ] each ;
|
2005-07-28 18:20:31 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
M: #if child-constraints
|
|
|
|
|
[
|
|
|
|
|
general-t 0 `input class,
|
|
|
|
|
f 0 `input literal,
|
|
|
|
|
] make-constraints ;
|
2005-07-28 18:20:31 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
M: #dispatch child-constraints
|
2019-10-18 09:05:08 -04:00
|
|
|
dup [
|
|
|
|
|
node-children length [
|
2019-10-18 09:05:06 -04:00
|
|
|
0 `input literal,
|
|
|
|
|
] each
|
|
|
|
|
] make-constraints ;
|
2005-07-28 18:20:31 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
M: #declare infer-classes-before
|
2006-05-02 01:49:52 -04:00
|
|
|
dup node-param swap node-in-d [ set-value-class* ] 2each ;
|
|
|
|
|
|
2005-07-28 18:20:31 -04:00
|
|
|
DEFER: (infer-classes)
|
|
|
|
|
|
|
|
|
|
: infer-children ( node -- )
|
2019-10-18 09:05:06 -04:00
|
|
|
dup node-children swap child-constraints [
|
2005-07-28 18:20:31 -04:00
|
|
|
[
|
|
|
|
|
value-classes [ clone ] change
|
2019-10-18 09:05:06 -04:00
|
|
|
value-literals [ clone ] change
|
2019-10-18 09:05:08 -04:00
|
|
|
value-intervals [ clone ] change
|
2019-10-18 09:05:06 -04:00
|
|
|
constraints [ clone ] change
|
|
|
|
|
apply-constraint
|
2005-07-28 18:20:31 -04:00
|
|
|
(infer-classes)
|
|
|
|
|
] with-scope
|
|
|
|
|
] 2each ;
|
2005-07-28 15:17:31 -04:00
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
: pad-all ( seqs elt -- seq )
|
|
|
|
|
>r dup [ length ] map supremum r> rot
|
|
|
|
|
[ pick pick pad-left ] map 2nip ;
|
|
|
|
|
|
|
|
|
|
: merge-classes ( nodes -- seq )
|
|
|
|
|
[ dup node-in-d [ node-class ] map-with ] map
|
|
|
|
|
null pad-all flip [ null [ class-or ] reduce ] map ;
|
|
|
|
|
|
|
|
|
|
: merge-intervals ( nodes -- seq )
|
|
|
|
|
[ dup node-in-d
|
|
|
|
|
[ node-interval ] map-with ] map
|
|
|
|
|
f pad-all flip [ dup first [ interval-union ] reduce ] map ;
|
2006-08-06 22:30:52 -04:00
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
: annotate-merge ( nodes #merge/#entry -- )
|
2019-10-18 09:05:08 -04:00
|
|
|
node-out-d
|
|
|
|
|
over merge-classes over [ set-value-class* ] 2reverse-each
|
|
|
|
|
swap merge-intervals swap [ set-value-interval* ] 2reverse-each ;
|
2006-08-06 22:30:52 -04:00
|
|
|
|
2006-11-10 03:21:03 -05:00
|
|
|
: active-children ( node -- seq )
|
|
|
|
|
node-children
|
|
|
|
|
[ last-node ] map
|
|
|
|
|
[ #terminate? not ] subset ;
|
|
|
|
|
|
2006-08-06 22:30:52 -04:00
|
|
|
: merge-children ( node -- )
|
|
|
|
|
dup node-successor dup #merge? [
|
2019-10-18 09:05:06 -04:00
|
|
|
swap active-children dup empty?
|
|
|
|
|
[ 2drop ] [ swap annotate-merge ] if
|
2006-08-06 22:30:52 -04:00
|
|
|
] [
|
|
|
|
|
2drop
|
|
|
|
|
] if ;
|
|
|
|
|
|
2019-10-18 09:05:06 -04:00
|
|
|
: annotate-entry ( nodes #label -- )
|
2019-10-18 09:05:08 -04:00
|
|
|
>r merge-classes r> node-child node-out-d
|
|
|
|
|
[ set-value-class* ] 2reverse-each ;
|
2019-10-18 09:05:06 -04:00
|
|
|
|
|
|
|
|
M: #label infer-classes-before ( #label -- )
|
|
|
|
|
#! First, infer types under the hypothesis which hold on
|
|
|
|
|
#! entry to the recursive label.
|
|
|
|
|
dup 1array swap annotate-entry ;
|
|
|
|
|
|
|
|
|
|
M: #label infer-classes-around ( #label -- )
|
|
|
|
|
#! Now merge the types at every recursion point with the
|
|
|
|
|
#! entry types.
|
|
|
|
|
dup annotate-node
|
|
|
|
|
dup infer-classes-before
|
|
|
|
|
dup infer-children
|
|
|
|
|
dup collect-recursion over add
|
|
|
|
|
pick annotate-entry
|
|
|
|
|
dup infer-children
|
|
|
|
|
merge-children ;
|
|
|
|
|
|
|
|
|
|
M: object infer-classes-around
|
|
|
|
|
dup infer-classes-before
|
|
|
|
|
dup annotate-node
|
|
|
|
|
dup infer-children
|
|
|
|
|
merge-children ;
|
|
|
|
|
|
2005-07-28 15:17:31 -04:00
|
|
|
: (infer-classes) ( node -- )
|
2005-08-01 16:22:53 -04:00
|
|
|
[
|
2019-10-18 09:05:06 -04:00
|
|
|
dup infer-classes-around
|
2005-08-01 16:22:53 -04:00
|
|
|
node-successor (infer-classes)
|
|
|
|
|
] when* ;
|
2005-07-28 15:17:31 -04:00
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
: infer-classes-with ( node classes literals intervals -- )
|
2005-07-28 15:17:31 -04:00
|
|
|
[
|
2019-10-18 09:05:08 -04:00
|
|
|
?<hashtable> value-intervals set
|
2006-05-10 18:51:18 -04:00
|
|
|
?<hashtable> value-literals set
|
|
|
|
|
?<hashtable> value-classes set
|
2019-10-18 09:05:06 -04:00
|
|
|
H{ } clone constraints set
|
2005-07-28 15:17:31 -04:00
|
|
|
(infer-classes)
|
|
|
|
|
] with-scope ;
|
2006-05-10 18:51:18 -04:00
|
|
|
|
|
|
|
|
: infer-classes ( node -- )
|
2019-10-18 09:05:08 -04:00
|
|
|
f f f infer-classes-with ;
|
2006-05-10 18:51:18 -04:00
|
|
|
|
2019-10-18 09:05:08 -04:00
|
|
|
: infer-classes/node ( node existing -- )
|
2006-05-10 18:51:18 -04:00
|
|
|
#! Infer classes, using the existing node's class info as a
|
|
|
|
|
#! starting point.
|
2019-10-18 09:05:08 -04:00
|
|
|
dup node-classes
|
|
|
|
|
over node-literals
|
|
|
|
|
rot node-intervals
|
|
|
|
|
infer-classes-with ;
|