Dynamic scope inference

slava 2006-11-13 03:14:04 +00:00
parent 28050349c5
commit fc8a1e5160
23 changed files with 597 additions and 399 deletions

View File

@ -1,6 +1,5 @@
+ 0.87:
- cocoa: move window while factor is busy: mouse gets messed up!
- live search: timer delay would be nice
- menu should stay up if mouse button released
- roundoff is still not quite right with tracks
@ -19,7 +18,6 @@
- intrinsic fixnum>float float>fixnum
- mac intel: struct returns from objc methods
- faster apropos
- infer which variables are read, written in a quotation
- compiled call traces
+ ui:

View File

@ -7,7 +7,6 @@ optimizer parser sequences sequences-internals words ;
[
print-warnings off
[
! Wrap everything in a catch which starts a listener so
! you can see what went wrong, instead of dealing with a
! fep
@ -72,7 +71,6 @@ optimizer parser sequences sequences-internals words ;
H{ } clone parent-graph set-global xref-help
H{ } clone term-index set-global index-help
] when
] no-parse-hook
run-bootstrap-init
@ -83,6 +81,10 @@ optimizer parser sequences sequences-internals words ;
0 exit
] set-boot
"compile" get [
[ recompile ] parse-hook set-global
] when
f error set-global
f error-continuation set-global

View File

@ -69,6 +69,7 @@ SYMBOL: architecture
: emit-object ( header tag quot -- addr )
swap here-as >r swap tag-header emit call align-here r> ;
inline
! Image header
@ -224,7 +225,7 @@ M: string '
: emit-array ( list type -- pointer )
>r [ ' ] map r> object-tag [
dup length emit-fixnum
( elements -- ) emit-seq
emit-seq
] emit-object ;
: transfer-tuple ( tuple -- tuple )

View File

@ -27,7 +27,7 @@ M: alien-callback-error summary
alien-callback-xt [ word-xt <alien> ] curry infer-quot ;
\ alien-callback [ string object quotation ] [ alien ] <effect>
"infer-effect" set-word-prop
"inferred-effect" set-word-prop
\ alien-callback [
empty-node <alien-callback> dup node,

View File

@ -16,7 +16,7 @@ M: alien-indirect-error summary
drop "Words calling ``alien-indirect'' cannot run in the interpreter. Compile the caller word and try again." ;
\ alien-indirect [ string object string ] [ ] <effect>
"infer-effect" set-word-prop
"inferred-effect" set-word-prop
\ alien-indirect [
empty-node <alien-indirect>

View File

@ -9,7 +9,7 @@ TUPLE: alien-invoke library function return parameters ;
C: alien-invoke make-node ;
: alien-invoke-stack ( node -- )
dup alien-invoke-parameters length over consume-values
dup alien-invoke-parameters over consume-values
dup alien-invoke-return "void" = 0 1 ? swap produce-values ;
: alien-invoke-dlsym ( node -- symbol dll )
@ -29,7 +29,7 @@ M: alien-invoke-error summary
[ inference-warning ] recover ;
\ alien-invoke [ string object string object ] [ ] <effect>
"infer-effect" set-word-prop
"inferred-effect" set-word-prop
\ alien-invoke [
empty-node <alien-invoke>

View File

@ -121,7 +121,7 @@ H{ } clone objc-methods set-global
\ (send) [ pop-literal nip infer-send ] "infer" set-word-prop
\ (send) [ object object ] [ ] <effect>
"infer-effect" set-word-prop
"inferred-effect" set-word-prop
: send ( ... selector -- ... ) f (send) ; inline

View File

@ -32,10 +32,10 @@ M: f batch-ends drop ;
: word-dataflow ( word -- dataflow )
[
dup ?no-effect
dup "no-effect" word-prop [ no-effect ] when
dup dup add-recursive-state
dup specialized-def (dataflow)
swap current-effect check-effect
[ specialized-def (dataflow) ] keep
finish-word 2drop
] with-infer ;
: (compile) ( word -- )
@ -50,11 +50,8 @@ M: f batch-ends drop ;
[ (compile) ] with-compiler ;
: try-compile ( word -- )
[
compile
] [
batch-errors get compile-error update-xt
] recover ;
[ compile ]
[ batch-errors get compile-error update-xt ] recover ;
: compile-batch ( seq -- )
batch-errors get batch-begins
@ -78,5 +75,3 @@ M: f batch-ends drop ;
changed-words get [
dup hash-keys compile-batch clear-hash
] when* ;
[ recompile ] parse-hook set

View File

@ -55,16 +55,41 @@ TUPLE: unbalanced-branches-error in out ;
swap meta-r active-variable
unify-effect meta-r set drop ;
TUPLE: unbalanced-namestacks ;
: unify-namestacks ( seq -- )
flip
[ H{ } clone [ dupd hash-update ] reduce ] map
meta-n set ;
: namestack-effect ( seq -- )
#! If the namestack is unbalanced, we don't throw an error
meta-n active-variable
dup [ length ] map all-equal? [
<unbalanced-namestacks> inference-error
] unless
unify-namestacks ;
: unify-vars ( seq -- )
#! Don't use active-variable here, because we want to
#! consider variables set right before a throw too
[ inferred-vars swap hash ] map apply-var-seq ;
: unify-effects ( seq -- )
dup datastack-effect dup callstack-effect
dup datastack-effect
dup callstack-effect
dup namestack-effect
dup unify-vars
[ terminated? swap hash ] all? terminated? set ;
: unify-dataflow ( effects -- nodes )
[ dataflow-graph swap hash ] map ;
: copy-inference ( -- )
meta-r [ clone ] change
meta-d [ clone ] change
meta-r [ clone ] change
meta-n [ [ clone ] map ] change
inferred-vars [ clone ] change
d-in [ ] change
dataflow-graph off
current-node off ;

View File

@ -2,7 +2,7 @@
! See http://factorcode.org/license.txt for BSD license.
IN: inference
USING: arrays generic hashtables kernel math
namespaces parser sequences words ;
namespaces parser sequences words vectors ;
SYMBOL: d-in
SYMBOL: meta-d

View File

@ -28,6 +28,10 @@ M: too-many-r> summary
drop
"Quotation pops retain stack elements which it did not push" ;
M: too-many-n> summary
drop
"Quotation pops name stack elements which it did not push" ;
M: no-effect error.
"The word " write
no-effect-word pprint

View File

@ -3,7 +3,7 @@
IN: inference
USING: arrays errors generic io kernel
math namespaces parser prettyprint sequences strings
vectors words ;
vectors words tools ;
TUPLE: inference-error rstate major? ;
@ -29,17 +29,14 @@ M: object value-literal
: value-vector ( n -- vector ) [ drop <computed> ] map >vector ;
: add-inputs ( n stack -- n stack )
tuck length - dup 0 >
: add-inputs ( seq stack -- n stack )
tuck [ length ] 2apply - dup 0 >
[ dup value-vector [ rot nappend ] keep ]
[ drop 0 swap ] if ;
: ensure-values ( n -- )
: ensure-values ( seq -- )
meta-d [ add-inputs ] change d-in [ + ] change ;
: short-effect ( -- pair )
d-in get meta-d get length 2array ;
SYMBOL: terminated?
: current-effect ( -- effect )
@ -50,8 +47,10 @@ SYMBOL: recorded
: init-inference ( recursive-state -- )
terminated? off
V{ } clone meta-r set
V{ } clone meta-d set
V{ } clone meta-r set
V{ } clone meta-n set
empty-vars inferred-vars set
0 d-in set
recursive-state set
dataflow-graph off
@ -97,9 +96,11 @@ TUPLE: too-many-r> ;
] when ;
: undo-infer ( -- )
recorded get
[ "infer" word-prop not ] subset
[ f "infer-effect" set-word-prop ] each ;
recorded get [ "infer" word-prop not ] subset [
dup
f "inferred-vars" set-word-prop
f "inferred-effect" set-word-prop
] each ;
: with-infer ( quot -- )
[
@ -115,8 +116,19 @@ TUPLE: too-many-r> ;
] recover
] with-scope ;
: infer ( quot -- effect )
[ infer-quot short-effect ] with-infer ;
: infer ( quot -- effect infer-vars )
[ infer-quot inferred-vars get current-effect ] with-infer ;
: vars. ( seq str -- )
over empty? [ 2drop ] [ print [ . ] each ] if ;
: infer. ( quot -- )
infer
"* Stack effect:" print effect>string print
dup inferred-vars-reads "* Reads free variables:" vars.
dup inferred-vars-writes "* Writes free variables:" vars.
dup inferred-vars-reads-globals "* Reads global variables:" vars.
inferred-vars-writes-globals "* Writes global variables:" vars. ;
: (dataflow) ( quot -- dataflow )
infer-quot f #return node, dataflow-graph get ;

View File

@ -1,60 +1,62 @@
! Copyright (C) 2004, 2006 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
IN: inference
USING: arrays alien assembler errors generic hashtables
hashtables-internals io io-internals kernel
kernel-internals math math-internals memory parser
sequences strings vectors words prettyprint ;
sequences strings vectors words prettyprint namespaces ;
\ declare [
pop-literal nip
dup length ensure-values
dup ensure-values
dup length d-tail
swap #declare
[ 2dup set-node-in-d set-node-out-d ] keep
node,
] "infer" set-word-prop
\ declare { object } { } <effect> "infer-effect" set-word-prop
\ declare { object } { } <effect> "inferred-effect" set-word-prop
\ fixnum< { fixnum fixnum } { object } <effect> "infer-effect" set-word-prop
\ fixnum< { fixnum fixnum } { object } <effect> "inferred-effect" set-word-prop
\ fixnum< t "foldable" set-word-prop
\ fixnum<= { fixnum fixnum } { object } <effect> "infer-effect" set-word-prop
\ fixnum<= { fixnum fixnum } { object } <effect> "inferred-effect" set-word-prop
\ fixnum<= t "foldable" set-word-prop
\ fixnum> { fixnum fixnum } { object } <effect> "infer-effect" set-word-prop
\ fixnum> { fixnum fixnum } { object } <effect> "inferred-effect" set-word-prop
\ fixnum> t "foldable" set-word-prop
\ fixnum>= { fixnum fixnum } { object } <effect> "infer-effect" set-word-prop
\ fixnum>= { fixnum fixnum } { object } <effect> "inferred-effect" set-word-prop
\ fixnum>= t "foldable" set-word-prop
\ eq? { object object } { object } <effect> "infer-effect" set-word-prop
\ eq? { object object } { object } <effect> "inferred-effect" set-word-prop
\ eq? t "foldable" set-word-prop
! Primitive combinators
\ call { object } { } <effect> "infer-effect" set-word-prop
\ call { object } { } <effect> "inferred-effect" set-word-prop
\ call [ pop-literal infer-quot-value ] "infer" set-word-prop
\ execute { word } { } <effect> "infer-effect" set-word-prop
\ execute { word } { } <effect> "inferred-effect" set-word-prop
\ execute [
pop-literal unit infer-quot-value
] "infer" set-word-prop
\ if { object object object } { } <effect> "infer-effect" set-word-prop
\ if { object object object } { } <effect> "inferred-effect" set-word-prop
\ if [
2 #drop node, pop-d pop-d swap 2array
#if pop-d drop infer-branches
] "infer" set-word-prop
\ cond { object } { } <effect> "infer-effect" set-word-prop
\ cond { object } { } <effect> "inferred-effect" set-word-prop
\ cond [
pop-literal <reversed>
[ no-cond ] swap alist>quot infer-quot-value
] "infer" set-word-prop
\ dispatch { fixnum array } { } <effect> "infer-effect" set-word-prop
\ dispatch { fixnum array } { } <effect> "inferred-effect" set-word-prop
\ dispatch [
pop-literal nip [ <value> ] map
@ -64,300 +66,352 @@ sequences strings vectors words prettyprint ;
! Non-standard control flow
\ throw { object } { } <effect>
t over set-effect-terminated?
"infer-effect" set-word-prop
"inferred-effect" set-word-prop
! Stack effects for all primitives
\ rehash-string { string } { } <effect> "infer-effect" set-word-prop
\ rehash-string { string } { } <effect> "inferred-effect" set-word-prop
\ string>sbuf { string } { sbuf } <effect> "infer-effect" set-word-prop
\ string>sbuf { string } { sbuf } <effect> "inferred-effect" set-word-prop
\ bignum>fixnum { bignum } { fixnum } <effect> "infer-effect" set-word-prop
\ bignum>fixnum { bignum } { fixnum } <effect> "inferred-effect" set-word-prop
\ bignum>fixnum t "foldable" set-word-prop
\ float>fixnum { float } { fixnum } <effect> "infer-effect" set-word-prop
\ float>fixnum { float } { fixnum } <effect> "inferred-effect" set-word-prop
\ bignum>fixnum t "foldable" set-word-prop
\ fixnum>bignum { fixnum } { bignum } <effect> "infer-effect" set-word-prop
\ fixnum>bignum { fixnum } { bignum } <effect> "inferred-effect" set-word-prop
\ fixnum>bignum t "foldable" set-word-prop
\ float>bignum { float } { bignum } <effect> "infer-effect" set-word-prop
\ float>bignum { float } { bignum } <effect> "inferred-effect" set-word-prop
\ float>bignum t "foldable" set-word-prop
\ fixnum>float { fixnum } { float } <effect> "infer-effect" set-word-prop
\ fixnum>float { fixnum } { float } <effect> "inferred-effect" set-word-prop
\ fixnum>float t "foldable" set-word-prop
\ bignum>float { bignum } { float } <effect> "infer-effect" set-word-prop
\ bignum>float { bignum } { float } <effect> "inferred-effect" set-word-prop
\ bignum>float t "foldable" set-word-prop
\ (fraction>) { integer integer } { rational } <effect> "infer-effect" set-word-prop
\ (fraction>) { integer integer } { rational } <effect> "inferred-effect" set-word-prop
\ (fraction>) t "foldable" set-word-prop
\ string>float { string } { float } <effect> "infer-effect" set-word-prop
\ string>float { string } { float } <effect> "inferred-effect" set-word-prop
\ string>float t "foldable" set-word-prop
\ float>string { float } { string } <effect> "infer-effect" set-word-prop
\ float>string { float } { string } <effect> "inferred-effect" set-word-prop
\ float>string t "foldable" set-word-prop
\ float>bits { real } { integer } <effect> "infer-effect" set-word-prop
\ float>bits { real } { integer } <effect> "inferred-effect" set-word-prop
\ float>bits t "foldable" set-word-prop
\ double>bits { real } { integer } <effect> "infer-effect" set-word-prop
\ double>bits { real } { integer } <effect> "inferred-effect" set-word-prop
\ double>bits t "foldable" set-word-prop
\ bits>float { integer } { float } <effect> "infer-effect" set-word-prop
\ bits>float { integer } { float } <effect> "inferred-effect" set-word-prop
\ bits>float t "foldable" set-word-prop
\ bits>double { integer } { float } <effect> "infer-effect" set-word-prop
\ bits>double { integer } { float } <effect> "inferred-effect" set-word-prop
\ bits>double t "foldable" set-word-prop
\ <complex> { real real } { number } <effect> "infer-effect" set-word-prop
\ <complex> { real real } { number } <effect> "inferred-effect" set-word-prop
\ <complex> t "foldable" set-word-prop
\ fixnum+ { fixnum fixnum } { integer } <effect> "infer-effect" set-word-prop
\ fixnum+ { fixnum fixnum } { integer } <effect> "inferred-effect" set-word-prop
\ fixnum+ t "foldable" set-word-prop
\ fixnum+fast { fixnum fixnum } { fixnum } <effect> "infer-effect" set-word-prop
\ fixnum+fast { fixnum fixnum } { fixnum } <effect> "inferred-effect" set-word-prop
\ fixnum+fast t "foldable" set-word-prop
\ fixnum- { fixnum fixnum } { integer } <effect> "infer-effect" set-word-prop
\ fixnum- { fixnum fixnum } { integer } <effect> "inferred-effect" set-word-prop
\ fixnum- t "foldable" set-word-prop
\ fixnum-fast { fixnum fixnum } { fixnum } <effect> "infer-effect" set-word-prop
\ fixnum-fast { fixnum fixnum } { fixnum } <effect> "inferred-effect" set-word-prop
\ fixnum-fast t "foldable" set-word-prop
\ fixnum* { fixnum fixnum } { integer } <effect> "infer-effect" set-word-prop
\ fixnum* { fixnum fixnum } { integer } <effect> "inferred-effect" set-word-prop
\ fixnum* t "foldable" set-word-prop
\ fixnum/i { fixnum fixnum } { integer } <effect> "infer-effect" set-word-prop
\ fixnum/i { fixnum fixnum } { integer } <effect> "inferred-effect" set-word-prop
\ fixnum/i t "foldable" set-word-prop
\ fixnum-mod { fixnum fixnum } { fixnum } <effect> "infer-effect" set-word-prop
\ fixnum-mod { fixnum fixnum } { fixnum } <effect> "inferred-effect" set-word-prop
\ fixnum-mod t "foldable" set-word-prop
\ fixnum/mod { fixnum fixnum } { integer fixnum } <effect> "infer-effect" set-word-prop
\ fixnum/mod { fixnum fixnum } { integer fixnum } <effect> "inferred-effect" set-word-prop
\ fixnum/mod t "foldable" set-word-prop
\ fixnum-bitand { fixnum fixnum } { fixnum } <effect> "infer-effect" set-word-prop
\ fixnum-bitand { fixnum fixnum } { fixnum } <effect> "inferred-effect" set-word-prop
\ fixnum-bitand t "foldable" set-word-prop
\ fixnum-bitor { fixnum fixnum } { fixnum } <effect> "infer-effect" set-word-prop
\ fixnum-bitor { fixnum fixnum } { fixnum } <effect> "inferred-effect" set-word-prop
\ fixnum-bitor t "foldable" set-word-prop
\ fixnum-bitxor { fixnum fixnum } { fixnum } <effect> "infer-effect" set-word-prop
\ fixnum-bitxor { fixnum fixnum } { fixnum } <effect> "inferred-effect" set-word-prop
\ fixnum-bitxor t "foldable" set-word-prop
\ fixnum-bitnot { fixnum } { fixnum } <effect> "infer-effect" set-word-prop
\ fixnum-bitnot { fixnum } { fixnum } <effect> "inferred-effect" set-word-prop
\ fixnum-bitnot t "foldable" set-word-prop
\ fixnum-shift { fixnum fixnum } { integer } <effect> "infer-effect" set-word-prop
\ fixnum-shift { fixnum fixnum } { integer } <effect> "inferred-effect" set-word-prop
\ fixnum-shift t "foldable" set-word-prop
\ bignum= { bignum bignum } { object } <effect> "infer-effect" set-word-prop
\ bignum= { bignum bignum } { object } <effect> "inferred-effect" set-word-prop
\ bignum= t "foldable" set-word-prop
\ bignum+ { bignum bignum } { bignum } <effect> "infer-effect" set-word-prop
\ bignum+ { bignum bignum } { bignum } <effect> "inferred-effect" set-word-prop
\ bignum+ t "foldable" set-word-prop
\ bignum- { bignum bignum } { bignum } <effect> "infer-effect" set-word-prop
\ bignum- { bignum bignum } { bignum } <effect> "inferred-effect" set-word-prop
\ bignum- t "foldable" set-word-prop
\ bignum* { bignum bignum } { bignum } <effect> "infer-effect" set-word-prop
\ bignum* { bignum bignum } { bignum } <effect> "inferred-effect" set-word-prop
\ bignum* t "foldable" set-word-prop
\ bignum/i { bignum bignum } { bignum } <effect> "infer-effect" set-word-prop
\ bignum/i { bignum bignum } { bignum } <effect> "inferred-effect" set-word-prop
\ bignum/i t "foldable" set-word-prop
\ bignum-mod { bignum bignum } { bignum } <effect> "infer-effect" set-word-prop
\ bignum-mod { bignum bignum } { bignum } <effect> "inferred-effect" set-word-prop
\ bignum-mod t "foldable" set-word-prop
\ bignum/mod { bignum bignum } { bignum bignum } <effect> "infer-effect" set-word-prop
\ bignum/mod { bignum bignum } { bignum bignum } <effect> "inferred-effect" set-word-prop
\ bignum/mod t "foldable" set-word-prop
\ bignum-bitand { bignum bignum } { bignum } <effect> "infer-effect" set-word-prop
\ bignum-bitand { bignum bignum } { bignum } <effect> "inferred-effect" set-word-prop
\ bignum-bitand t "foldable" set-word-prop
\ bignum-bitor { bignum bignum } { bignum } <effect> "infer-effect" set-word-prop
\ bignum-bitor { bignum bignum } { bignum } <effect> "inferred-effect" set-word-prop
\ bignum-bitor t "foldable" set-word-prop
\ bignum-bitxor { bignum bignum } { bignum } <effect> "infer-effect" set-word-prop
\ bignum-bitxor { bignum bignum } { bignum } <effect> "inferred-effect" set-word-prop
\ bignum-bitxor t "foldable" set-word-prop
\ bignum-bitnot { bignum } { bignum } <effect> "infer-effect" set-word-prop
\ bignum-bitnot { bignum } { bignum } <effect> "inferred-effect" set-word-prop
\ bignum-bitnot t "foldable" set-word-prop
\ bignum-shift { bignum bignum } { bignum } <effect> "infer-effect" set-word-prop
\ bignum-shift { bignum bignum } { bignum } <effect> "inferred-effect" set-word-prop
\ bignum-shift t "foldable" set-word-prop
\ bignum< { bignum bignum } { object } <effect> "infer-effect" set-word-prop
\ bignum< { bignum bignum } { object } <effect> "inferred-effect" set-word-prop
\ bignum< t "foldable" set-word-prop
\ bignum<= { bignum bignum } { object } <effect> "infer-effect" set-word-prop
\ bignum<= { bignum bignum } { object } <effect> "inferred-effect" set-word-prop
\ bignum<= t "foldable" set-word-prop
\ bignum> { bignum bignum } { object } <effect> "infer-effect" set-word-prop
\ bignum> { bignum bignum } { object } <effect> "inferred-effect" set-word-prop
\ bignum> t "foldable" set-word-prop
\ bignum>= { bignum bignum } { object } <effect> "infer-effect" set-word-prop
\ bignum>= { bignum bignum } { object } <effect> "inferred-effect" set-word-prop
\ bignum>= t "foldable" set-word-prop
\ float+ { float float } { float } <effect> "infer-effect" set-word-prop
\ float+ { float float } { float } <effect> "inferred-effect" set-word-prop
\ float+ t "foldable" set-word-prop
\ float- { float float } { float } <effect> "infer-effect" set-word-prop
\ float- { float float } { float } <effect> "inferred-effect" set-word-prop
\ float- t "foldable" set-word-prop
\ float* { float float } { float } <effect> "infer-effect" set-word-prop
\ float* { float float } { float } <effect> "inferred-effect" set-word-prop
\ float* t "foldable" set-word-prop
\ float/f { float float } { float } <effect> "infer-effect" set-word-prop
\ float/f { float float } { float } <effect> "inferred-effect" set-word-prop
\ float/f t "foldable" set-word-prop
\ float< { float float } { object } <effect> "infer-effect" set-word-prop
\ float< { float float } { object } <effect> "inferred-effect" set-word-prop
\ float< t "foldable" set-word-prop
\ float-mod { float float } { float } <effect> "infer-effect" set-word-prop
\ float-mod { float float } { float } <effect> "inferred-effect" set-word-prop
\ float-mod t "foldable" set-word-prop
\ float<= { float float } { object } <effect> "infer-effect" set-word-prop
\ float<= { float float } { object } <effect> "inferred-effect" set-word-prop
\ float<= t "foldable" set-word-prop
\ float> { float float } { object } <effect> "infer-effect" set-word-prop
\ float> { float float } { object } <effect> "inferred-effect" set-word-prop
\ float> t "foldable" set-word-prop
\ float>= { float float } { object } <effect> "infer-effect" set-word-prop
\ float>= { float float } { object } <effect> "inferred-effect" set-word-prop
\ float>= t "foldable" set-word-prop
\ (word) { object object } { word } <effect> "infer-effect" set-word-prop
\ (word) { object object } { word } <effect> "inferred-effect" set-word-prop
\ update-xt { word } { } <effect> "infer-effect" set-word-prop
\ update-xt { word } { } <effect> "inferred-effect" set-word-prop
\ word-xt { word } { integer } <effect> "infer-effect" set-word-prop
\ word-xt { word } { integer } <effect> "inferred-effect" set-word-prop
\ getenv { fixnum } { object } <effect> "infer-effect" set-word-prop
\ setenv { object fixnum } { } <effect> "infer-effect" set-word-prop
\ stat { string } { object object object object } <effect> "infer-effect" set-word-prop
\ (directory) { string } { array } <effect> "infer-effect" set-word-prop
\ data-gc { integer } { } <effect> "infer-effect" set-word-prop
\ getenv { fixnum } { object } <effect> "inferred-effect" set-word-prop
\ setenv { object fixnum } { } <effect> "inferred-effect" set-word-prop
\ stat { string } { object object object object } <effect> "inferred-effect" set-word-prop
\ (directory) { string } { array } <effect> "inferred-effect" set-word-prop
\ data-gc { integer } { } <effect> "inferred-effect" set-word-prop
! code-gc does not declare a stack effect since it might be
! called from a compiled word which becomes unreachable during
! the course of its execution, resulting in a crash
\ gc-time { } { integer } <effect> "infer-effect" set-word-prop
\ save-image { string } { } <effect> "infer-effect" set-word-prop
\ exit { integer } { } <effect> "infer-effect" set-word-prop
\ data-room { } { integer integer array } <effect> "infer-effect" set-word-prop
\ code-room { } { integer integer } <effect> "infer-effect" set-word-prop
\ os-env { string } { object } <effect> "infer-effect" set-word-prop
\ millis { } { integer } <effect> "infer-effect" set-word-prop
\ gc-time { } { integer } <effect> "inferred-effect" set-word-prop
\ save-image { string } { } <effect> "inferred-effect" set-word-prop
\ exit { integer } { } <effect> "inferred-effect" set-word-prop
\ data-room { } { integer integer array } <effect> "inferred-effect" set-word-prop
\ code-room { } { integer integer } <effect> "inferred-effect" set-word-prop
\ os-env { string } { object } <effect> "inferred-effect" set-word-prop
\ millis { } { integer } <effect> "inferred-effect" set-word-prop
\ type { object } { fixnum } <effect> "infer-effect" set-word-prop
\ type { object } { fixnum } <effect> "inferred-effect" set-word-prop
\ type t "foldable" set-word-prop
\ tag { object } { fixnum } <effect> "infer-effect" set-word-prop
\ tag { object } { fixnum } <effect> "inferred-effect" set-word-prop
\ tag t "foldable" set-word-prop
\ cwd { } { string } <effect> "infer-effect" set-word-prop
\ cd { string } { } <effect> "infer-effect" set-word-prop
\ cwd { } { string } <effect> "inferred-effect" set-word-prop
\ cd { string } { } <effect> "inferred-effect" set-word-prop
\ dlopen { string } { dll } <effect> "infer-effect" set-word-prop
\ dlsym { string object } { integer } <effect> "infer-effect" set-word-prop
\ dlclose { dll } { } <effect> "infer-effect" set-word-prop
\ dlopen { string } { dll } <effect> "inferred-effect" set-word-prop
\ dlsym { string object } { integer } <effect> "inferred-effect" set-word-prop
\ dlclose { dll } { } <effect> "inferred-effect" set-word-prop
\ <byte-array> { integer } { byte-array } <effect> "infer-effect" set-word-prop
\ <byte-array> { integer } { byte-array } <effect> "inferred-effect" set-word-prop
\ <displaced-alien> { integer c-ptr } { c-ptr } <effect> "infer-effect" set-word-prop
\ <displaced-alien> { integer c-ptr } { c-ptr } <effect> "inferred-effect" set-word-prop
\ alien-signed-cell { c-ptr integer } { integer } <effect> "infer-effect" set-word-prop
\ alien-signed-cell { c-ptr integer } { integer } <effect> "inferred-effect" set-word-prop
\ set-alien-signed-cell { integer c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-unsigned-cell { c-ptr integer } { integer } <effect> "infer-effect" set-word-prop
\ set-alien-signed-cell { integer c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-unsigned-cell { c-ptr integer } { integer } <effect> "inferred-effect" set-word-prop
\ set-alien-unsigned-cell { integer c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-signed-8 { c-ptr integer } { integer } <effect> "infer-effect" set-word-prop
\ set-alien-unsigned-cell { integer c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-signed-8 { c-ptr integer } { integer } <effect> "inferred-effect" set-word-prop
\ set-alien-signed-8 { integer c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-unsigned-8 { c-ptr integer } { integer } <effect> "infer-effect" set-word-prop
\ set-alien-signed-8 { integer c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-unsigned-8 { c-ptr integer } { integer } <effect> "inferred-effect" set-word-prop
\ set-alien-unsigned-8 { integer c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-signed-4 { c-ptr integer } { integer } <effect> "infer-effect" set-word-prop
\ set-alien-unsigned-8 { integer c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-signed-4 { c-ptr integer } { integer } <effect> "inferred-effect" set-word-prop
\ set-alien-signed-4 { integer c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-unsigned-4 { c-ptr integer } { integer } <effect> "infer-effect" set-word-prop
\ set-alien-signed-4 { integer c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-unsigned-4 { c-ptr integer } { integer } <effect> "inferred-effect" set-word-prop
\ set-alien-unsigned-4 { integer c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-signed-2 { c-ptr integer } { integer } <effect> "infer-effect" set-word-prop
\ set-alien-unsigned-4 { integer c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-signed-2 { c-ptr integer } { integer } <effect> "inferred-effect" set-word-prop
\ set-alien-signed-2 { integer c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-unsigned-2 { c-ptr integer } { integer } <effect> "infer-effect" set-word-prop
\ set-alien-signed-2 { integer c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-unsigned-2 { c-ptr integer } { integer } <effect> "inferred-effect" set-word-prop
\ set-alien-unsigned-2 { integer c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-signed-1 { c-ptr integer } { integer } <effect> "infer-effect" set-word-prop
\ set-alien-unsigned-2 { integer c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-signed-1 { c-ptr integer } { integer } <effect> "inferred-effect" set-word-prop
\ set-alien-signed-1 { integer c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-unsigned-1 { c-ptr integer } { integer } <effect> "infer-effect" set-word-prop
\ set-alien-signed-1 { integer c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-unsigned-1 { c-ptr integer } { integer } <effect> "inferred-effect" set-word-prop
\ set-alien-unsigned-1 { integer c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-float { c-ptr integer } { float } <effect> "infer-effect" set-word-prop
\ set-alien-unsigned-1 { integer c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-float { c-ptr integer } { float } <effect> "inferred-effect" set-word-prop
\ set-alien-float { float c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-float { c-ptr integer } { float } <effect> "infer-effect" set-word-prop
\ set-alien-float { float c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-float { c-ptr integer } { float } <effect> "inferred-effect" set-word-prop
\ set-alien-double { float c-ptr integer } { } <effect> "infer-effect" set-word-prop
\ alien-double { c-ptr integer } { float } <effect> "infer-effect" set-word-prop
\ set-alien-double { float c-ptr integer } { } <effect> "inferred-effect" set-word-prop
\ alien-double { c-ptr integer } { float } <effect> "inferred-effect" set-word-prop
\ alien>char-string { c-ptr } { string } <effect> "infer-effect" set-word-prop
\ alien>char-string { c-ptr } { string } <effect> "inferred-effect" set-word-prop
\ string>char-alien { string } { byte-array } <effect> "infer-effect" set-word-prop
\ string>char-alien { string } { byte-array } <effect> "inferred-effect" set-word-prop
\ alien>u16-string { c-ptr } { string } <effect> "infer-effect" set-word-prop
\ alien>u16-string { c-ptr } { string } <effect> "inferred-effect" set-word-prop
\ string>u16-alien { string } { byte-array } <effect> "infer-effect" set-word-prop
\ string>u16-alien { string } { byte-array } <effect> "inferred-effect" set-word-prop
\ string>memory { string integer } { } <effect> "infer-effect" set-word-prop
\ memory>string { integer integer } { string } <effect> "infer-effect" set-word-prop
\ string>memory { string integer } { } <effect> "inferred-effect" set-word-prop
\ memory>string { integer integer } { string } <effect> "inferred-effect" set-word-prop
\ alien-address { alien } { integer } <effect> "infer-effect" set-word-prop
\ alien-address { alien } { integer } <effect> "inferred-effect" set-word-prop
\ slot { object fixnum } { object } <effect> "infer-effect" set-word-prop
\ slot { object fixnum } { object } <effect> "inferred-effect" set-word-prop
\ set-slot { object object fixnum } { } <effect> "infer-effect" set-word-prop
\ set-slot { object object fixnum } { } <effect> "inferred-effect" set-word-prop
\ char-slot { fixnum object } { fixnum } <effect> "infer-effect" set-word-prop
\ char-slot { fixnum object } { fixnum } <effect> "inferred-effect" set-word-prop
\ set-char-slot { fixnum fixnum object } { } <effect> "infer-effect" set-word-prop
\ resize-array { integer array } { array } <effect> "infer-effect" set-word-prop
\ resize-string { integer string } { string } <effect> "infer-effect" set-word-prop
\ set-char-slot { fixnum fixnum object } { } <effect> "inferred-effect" set-word-prop
\ resize-array { integer array } { array } <effect> "inferred-effect" set-word-prop
\ resize-string { integer string } { string } <effect> "inferred-effect" set-word-prop
\ (hashtable) { } { hashtable } <effect> "infer-effect" set-word-prop
\ (hashtable) { } { hashtable } <effect> "inferred-effect" set-word-prop
\ <array> { integer object } { array } <effect> "infer-effect" set-word-prop
\ <array> { integer object } { array } <effect> "inferred-effect" set-word-prop
\ begin-scan { } { } <effect> "infer-effect" set-word-prop
\ next-object { } { object } <effect> "infer-effect" set-word-prop
\ end-scan { } { } <effect> "infer-effect" set-word-prop
\ begin-scan { } { } <effect> "inferred-effect" set-word-prop
\ next-object { } { object } <effect> "inferred-effect" set-word-prop
\ end-scan { } { } <effect> "inferred-effect" set-word-prop
\ size { object } { fixnum } <effect> "infer-effect" set-word-prop
\ size { object } { fixnum } <effect> "inferred-effect" set-word-prop
\ die { } { } <effect> "infer-effect" set-word-prop
\ fopen { string string } { alien } <effect> "infer-effect" set-word-prop
\ fgetc { alien } { object } <effect> "infer-effect" set-word-prop
\ fwrite { string alien } { } <effect> "infer-effect" set-word-prop
\ fflush { alien } { } <effect> "infer-effect" set-word-prop
\ fclose { alien } { } <effect> "infer-effect" set-word-prop
\ expired? { object } { object } <effect> "infer-effect" set-word-prop
\ die { } { } <effect> "inferred-effect" set-word-prop
\ fopen { string string } { alien } <effect> "inferred-effect" set-word-prop
\ fgetc { alien } { object } <effect> "inferred-effect" set-word-prop
\ fwrite { string alien } { } <effect> "inferred-effect" set-word-prop
\ fflush { alien } { } <effect> "inferred-effect" set-word-prop
\ fclose { alien } { } <effect> "inferred-effect" set-word-prop
\ expired? { object } { object } <effect> "inferred-effect" set-word-prop
\ <wrapper> { object } { wrapper } <effect> "infer-effect" set-word-prop
\ <wrapper> { object } { wrapper } <effect> "inferred-effect" set-word-prop
\ <wrapper> t "foldable" set-word-prop
\ (clone) { object } { object } <effect> "infer-effect" set-word-prop
\ (clone) { object } { object } <effect> "inferred-effect" set-word-prop
\ become { object fixnum } { object } <effect> "infer-effect" set-word-prop
\ become { object fixnum } { object } <effect> "inferred-effect" set-word-prop
\ array>vector { array } { vector } <effect> "infer-effect" set-word-prop
\ array>vector { array } { vector } <effect> "inferred-effect" set-word-prop
\ finalize-compile { array } { } <effect> "infer-effect" set-word-prop
\ finalize-compile { array } { } <effect> "inferred-effect" set-word-prop
\ <string> { integer integer } { string } <effect> "infer-effect" set-word-prop
\ <string> { integer integer } { string } <effect> "inferred-effect" set-word-prop
\ <quotation> { integer } { quotation } <effect> "infer-effect" set-word-prop
\ <quotation> { integer } { quotation } <effect> "inferred-effect" set-word-prop
! Dynamic scope inference
: if-tos-literal ( quot -- )
peek-d dup value? [ value-literal swap call ] [ 2drop ] if ;
inline
\ >n [ H{ } clone push-n ] "infer-vars" set-word-prop
\ >n { object } { } <effect> "inferred-effect" set-word-prop
TUPLE: too-many-n> ;
: apply-n> ( -- )
meta-n get empty? [
<too-many-n>> inference-error
] [
pop-n drop
] if ;
\ n> [ apply-n> ] "infer-vars" set-word-prop
\ n> { } { object } <effect> "inferred-effect" set-word-prop
\ ndrop [ apply-n> ] "infer-vars" set-word-prop
\ ndrop { } { } <effect> "inferred-effect" set-word-prop
\ get [
[ apply-var-read ] if-tos-literal
] "infer-vars" set-word-prop
\ get { object } { object } <effect> "inferred-effect" set-word-prop
\ set [
[ apply-var-write ] if-tos-literal
] "infer-vars" set-word-prop
\ set { object object } { } <effect> "inferred-effect" set-word-prop
\ get-global [
[ apply-global-read ]
if-tos-literal
] "infer-vars" set-word-prop
\ get-global { object } { object } <effect> "inferred-effect" set-word-prop
\ set-global [
[ apply-global-write ]
if-tos-literal
] "infer-vars" set-word-prop
\ set-global { object object } { } <effect> "inferred-effect" set-word-prop

View File

@ -18,7 +18,7 @@ sequences words parser words ;
infer-shuffle-outputs ;
: define-shuffle ( word shuffle -- )
[ "infer-effect" set-word-prop ] 2keep
[ "inferred-effect" set-word-prop ] 2keep
[ infer-shuffle ] curry "infer" set-word-prop ;
{
@ -47,7 +47,7 @@ sequences words parser words ;
0 1 rot node-outputs
] "infer" set-word-prop
\ >r { object } { } <effect> "infer-effect" set-word-prop
\ >r { object } { } <effect> "inferred-effect" set-word-prop
\ r> [
check-r>
@ -57,4 +57,4 @@ sequences words parser words ;
1 0 rot node-outputs
] "infer" set-word-prop
\ r> { } { object } <effect> "infer-effect" set-word-prop
\ r> { } { object } <effect> "inferred-effect" set-word-prop

View File

@ -0,0 +1,54 @@
! Copyright (C) 2004, 2006 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
IN: inference
USING: kernel sequences hashtables kernel-internals words
namespaces generic vectors namespaces ;
! Name stack and variable binding simulation
SYMBOL: meta-n
: push-n meta-n get push ;
: pop-n meta-n get pop ;
: peek-n meta-n get peek ;
TUPLE: inferred-vars reads writes reads-globals writes-globals ;
: vars-trivial? ( vars -- ? ) tuple-slots [ empty? ] all? ;
: empty-vars ( -- vars )
V{ } clone V{ } clone V{ } clone V{ } clone
<inferred-vars> ;
: apply-var-seq ( seq -- )
inferred-vars [
>r [ tuple-slots ] map r> tuple-slots add flip
[ concat prune >vector ] map first4 <inferred-vars>
] change ;
: apply-var-read ( symbol -- )
dup meta-n get [ hash-member? ] contains-with? [
drop
] [
inferred-vars get inferred-vars-reads push-new
] if ;
: apply-var-write ( symbol -- )
meta-n get empty? [
inferred-vars get inferred-vars-writes push-new
] [
dup peek-n set-hash
] if ;
: apply-global-read ( symbol -- )
inferred-vars get inferred-vars-reads-globals push-new ;
: apply-global-write ( symbol -- )
inferred-vars get inferred-vars-writes-globals push-new ;
: apply-vars ( vars -- )
[
dup inferred-vars-reads [ apply-var-read ] each
dup inferred-vars-writes [ apply-var-write ] each
dup inferred-vars-reads-globals [ apply-global-read ] each
inferred-vars-writes-globals [ apply-global-write ] each
] when* ;

View File

@ -5,29 +5,32 @@ math math-internals namespaces parser prettyprint sequences
strings vectors words ;
IN: inference
: consume-values ( n node -- )
: consume-values ( seq node -- )
>r length r>
over ensure-values
over 0 rot node-inputs
meta-d get [ length swap - ] keep set-length ;
: produce-values ( n node -- )
: produce-values ( seq node -- )
>r [ drop <computed> ] map dup r> set-node-out-d
meta-d get swap nappend ;
: recursing? ( word -- label/f )
recursive-state get <reversed> assoc ;
: if-inline ( word true false -- )
>r >r dup "inline" word-prop r> r> if ; inline
: make-call-node ( word -- node )
dup "inline" word-prop
[ dup recursing? [ #call-label ] [ #call ] ?if ]
[ #call ]
if ;
if-inline ;
: consume/produce ( word effect -- )
: consume/produce ( effect word -- )
meta-d get clone >r
swap make-call-node dup node,
over effect-in length over consume-values
over effect-out length over produce-values
over effect-in over consume-values
over effect-out over produce-values
r> over #call-label? [ swap set-node-in-d ] [ 2drop ] if
effect-terminated? [ terminate ] when ;
@ -45,7 +48,7 @@ TUPLE: no-effect word ;
: add-recursive-state ( word label -- )
2array recursive-state [ swap add ] change ;
: inline-block ( word -- node-block variables )
: inline-block ( word -- node-block data )
[
copy-inference nest-node
gensym 2dup add-recursive-state
@ -87,15 +90,14 @@ M: #call-label collect-recursion*
apply-infer node-child node-successor splice-node drop
] if ;
: infer-compound ( word -- effect )
: infer-compound ( word -- hash )
[
recursive-state get init-inference
[ inline-block nip [ current-effect ] bind ] keep
] with-scope over consume/produce ;
recursive-state get init-inference inline-block nip
] with-scope ;
GENERIC: apply-word
GENERIC: infer-word ( word -- effect data )
M: object apply-word no-effect ;
M: word infer-word no-effect ;
TUPLE: effect-error word effect ;
@ -104,57 +106,76 @@ TUPLE: effect-error word effect ;
: check-effect ( word effect -- )
over "infer" word-prop [
2drop
] [
over recorded get push
dup pick "declared-effect" word-prop dup
[ effect<= [ effect-error ] unless ] [ 2drop ] if
"infer-effect" set-word-prop
] if ;
over "declared-effect" word-prop 2dup
[ swap effect<= [ effect-error ] unless ] [ 2drop ] if
] unless 2drop ;
M: compound apply-word
[
dup infer-compound check-effect
] [
swap t "no-effect" set-word-prop rethrow
] recover ;
: save-inferred-data ( word effect vars -- )
>r over r>
dup vars-trivial? [ drop f ] when
"inferred-vars" set-word-prop
"inferred-effect" set-word-prop ;
: ?no-effect ( word -- )
dup "no-effect" word-prop [ no-effect ] [ drop ] if ;
: finish-word ( word -- effect vars )
current-effect 2dup check-effect
inferred-vars get
[ save-inferred-data ] 2keep ;
: apply-default ( word -- )
dup ?no-effect
dup "infer-effect" word-prop [
over "infer" word-prop [
swap effect-in length ensure-values call drop
] [
consume/produce
] if*
] [
apply-word
] if* ;
M: compound infer-word
[ dup infer-compound [ finish-word ] bind ]
[ swap t "no-effect" set-word-prop rethrow ] recover ;
M: word apply-object apply-default ;
: custom-infer ( word -- )
#! Customized inference behavior
dup "inferred-vars" word-prop apply-vars
dup "inferred-effect" word-prop effect-in ensure-values
"infer" word-prop call ;
: apply-effect/vars ( word effect vars -- )
apply-vars consume/produce ;
: cached-infer ( word -- )
dup "inferred-effect" word-prop
over "inferred-vars" word-prop
apply-effect/vars ;
: apply-word ( word -- )
{
{ [ dup "no-effect" word-prop ] [ no-effect ] }
{ [ dup "infer" word-prop ] [ custom-infer ] }
{ [ dup "inferred-effect" word-prop ] [ cached-infer ] }
{ [ t ] [ dup infer-word apply-effect/vars ] }
} cond ;
M: word apply-object apply-word ;
M: symbol apply-object apply-literal ;
TUPLE: recursive-declare-error word ;
: recursive-effect ( word -- effect )
dup stack-effect
[ ] [ <recursive-declare-error> inference-error ] ?if ;
: declared-infer ( word -- )
dup stack-effect [
consume/produce
] [
<recursive-declare-error> inference-error
] if* ;
: apply-inline ( word -- )
dup recursive-state get peek first eq?
[ declared-infer ] [ inline-closure ] if ;
: apply-compound ( word -- )
dup recursing? [ declared-infer ] [ apply-word ] if ;
: custom-infer-vars ( word -- )
dup "infer-vars" word-prop dup [
swap "inferred-effect" word-prop effect-in ensure-values
call
] [
2drop
] if ;
M: compound apply-object
dup "inline" word-prop [
dup recursive-state get peek first eq? [
dup recursive-effect consume/produce
] [
inline-closure
] if
] [
dup recursing? [
dup recursive-effect consume/produce
] [
apply-default
] if
] if ;
dup custom-infer-vars
[ apply-inline ] [ apply-compound ] if-inline ;

View File

@ -2,6 +2,7 @@ PROVIDE: library/compiler
{ +files+ {
"inference/shuffle.factor"
"inference/dataflow.factor"
"inference/variables.factor"
"inference/inference.factor"
"inference/branches.factor"
"inference/words.factor"

View File

@ -119,7 +119,7 @@ M: node child-ties
dup node-param "output-classes" word-prop [
call
] [
node-param "infer-effect" word-prop effect-out
node-param "inferred-effect" word-prop effect-out
dup [ word? ] all? [ drop f ] unless
] if* ;

View File

@ -3,6 +3,9 @@ math math-internals namespaces parser sequences strings test
vectors words ;
IN: temporary
: short-effect
dup effect-in length swap effect-out length 2array nip ;
[ f ] [ f [ [ ] map-nodes ] with-node-iterator ] unit-test
[ t ] [ [ ] dataflow dup [ [ ] map-nodes ] with-node-iterator = ] unit-test
@ -11,20 +14,20 @@ IN: temporary
[ t ] [ [ [ ] [ ] if ] dataflow dup [ [ ] map-nodes ] with-node-iterator = ] unit-test
[ { 0 0 } ] [ f infer ] unit-test
[ { 0 2 } ] [ [ 2 "Hello" ] infer ] unit-test
[ { 1 2 } ] [ [ dup ] infer ] unit-test
[ { 0 0 } ] [ f infer short-effect ] unit-test
[ { 0 2 } ] [ [ 2 "Hello" ] infer short-effect ] unit-test
[ { 1 2 } ] [ [ dup ] infer short-effect ] unit-test
[ { 1 2 } ] [ [ [ dup ] call ] infer ] unit-test
[ [ call ] infer ] unit-test-fails
[ { 1 2 } ] [ [ [ dup ] call ] infer short-effect ] unit-test
[ [ call ] infer short-effect ] unit-test-fails
[ { 2 4 } ] [ [ 2dup ] infer ] unit-test
[ { 2 4 } ] [ [ 2dup ] infer short-effect ] unit-test
[ { 1 0 } ] [ [ [ ] [ ] if ] infer ] unit-test
[ [ if ] infer ] unit-test-fails
[ [ [ ] if ] infer ] unit-test-fails
[ [ [ 2 ] [ ] if ] infer ] unit-test-fails
[ { 4 3 } ] [ [ [ rot ] [ -rot ] if ] infer ] unit-test
[ { 1 0 } ] [ [ [ ] [ ] if ] infer short-effect ] unit-test
[ [ if ] infer short-effect ] unit-test-fails
[ [ [ ] if ] infer short-effect ] unit-test-fails
[ [ [ 2 ] [ ] if ] infer short-effect ] unit-test-fails
[ { 4 3 } ] [ [ [ rot ] [ -rot ] if ] infer short-effect ] unit-test
[ { 4 3 } ] [
[
@ -33,18 +36,18 @@ IN: temporary
] [
-rot
] if
] infer
] infer short-effect
] unit-test
[ { 1 1 } ] [ [ dup [ ] when ] infer ] unit-test
[ { 1 1 } ] [ [ dup [ dup fixnum* ] when ] infer ] unit-test
[ { 2 1 } ] [ [ [ dup fixnum* ] when ] infer ] unit-test
[ { 1 1 } ] [ [ dup [ ] when ] infer short-effect ] unit-test
[ { 1 1 } ] [ [ dup [ dup fixnum* ] when ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ [ dup fixnum* ] when ] infer short-effect ] unit-test
[ { 1 0 } ] [ [ [ drop ] when* ] infer ] unit-test
[ { 1 1 } ] [ [ [ { { [ ] } } ] unless* ] infer ] unit-test
[ { 1 0 } ] [ [ [ drop ] when* ] infer short-effect ] unit-test
[ { 1 1 } ] [ [ [ { { [ ] } } ] unless* ] infer short-effect ] unit-test
[ { 0 1 } ] [
[ [ 2 2 fixnum+ ] dup [ ] when call ] infer
[ [ 2 2 fixnum+ ] dup [ ] when call ] infer short-effect
] unit-test
[
@ -57,37 +60,37 @@ IN: temporary
: termination-test-2 [ termination-test-1 ] [ 3 ] if ;
[ { 1 1 } ] [ [ termination-test-2 ] infer ] unit-test
[ { 1 1 } ] [ [ termination-test-2 ] infer short-effect ] unit-test
: infinite-loop infinite-loop ;
[ [ infinite-loop ] infer ] unit-test-fails
[ [ infinite-loop ] infer short-effect ] unit-test-fails
: no-base-case-1 dup [ no-base-case-1 ] [ no-base-case-1 ] if ;
[ [ no-base-case-1 ] infer ] unit-test-fails
[ [ no-base-case-1 ] infer short-effect ] unit-test-fails
: simple-recursion-1 ( obj -- obj )
dup [ simple-recursion-1 ] [ ] if ;
[ { 1 1 } ] [ [ simple-recursion-1 ] infer ] unit-test
[ { 1 1 } ] [ [ simple-recursion-1 ] infer short-effect ] unit-test
: simple-recursion-2 ( obj -- obj )
dup [ ] [ simple-recursion-2 ] if ;
[ { 1 1 } ] [ [ simple-recursion-2 ] infer ] unit-test
[ { 1 1 } ] [ [ simple-recursion-2 ] infer short-effect ] unit-test
: bad-recursion-2 ( obj -- obj )
dup [ dup first swap second bad-recursion-2 ] [ ] if ;
[ [ bad-recursion-2 ] infer ] unit-test-fails
[ [ bad-recursion-2 ] infer short-effect ] unit-test-fails
: funny-recursion ( obj -- obj )
dup [ funny-recursion 1 ] [ 2 ] if drop ;
[ { 1 1 } ] [ [ funny-recursion ] infer ] unit-test
[ { 1 1 } ] [ [ funny-recursion ] infer short-effect ] unit-test
! Simple combinators
[ { 1 2 } ] [ [ [ first ] keep second ] infer ] unit-test
[ { 1 2 } ] [ [ [ first ] keep second ] infer short-effect ] unit-test
! Mutual recursion
DEFER: foe
@ -110,8 +113,8 @@ DEFER: foe
2drop f
] if ;
[ { 2 1 } ] [ [ fie ] infer ] unit-test
[ { 2 1 } ] [ [ foe ] infer ] unit-test
[ { 2 1 } ] [ [ fie ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ foe ] infer short-effect ] unit-test
: nested-when ( -- )
t [
@ -120,7 +123,7 @@ DEFER: foe
] when
] when ;
[ { 0 0 } ] [ [ nested-when ] infer ] unit-test
[ { 0 0 } ] [ [ nested-when ] infer short-effect ] unit-test
: nested-when* ( obj -- )
[
@ -129,11 +132,11 @@ DEFER: foe
] when*
] when* ;
[ { 1 0 } ] [ [ nested-when* ] infer ] unit-test
[ { 1 0 } ] [ [ nested-when* ] infer short-effect ] unit-test
SYMBOL: sym-test
[ { 0 1 } ] [ [ sym-test ] infer ] unit-test
[ { 0 1 } ] [ [ sym-test ] infer short-effect ] unit-test
: terminator-branch
dup [
@ -142,7 +145,7 @@ SYMBOL: sym-test
"foo" throw
] if ;
[ { 1 1 } ] [ [ terminator-branch ] infer ] unit-test
[ { 1 1 } ] [ [ terminator-branch ] infer short-effect ] unit-test
: recursive-terminator ( obj -- )
dup [
@ -151,12 +154,12 @@ SYMBOL: sym-test
"Hi" throw
] if ;
[ { 1 0 } ] [ [ recursive-terminator ] infer ] unit-test
[ { 1 0 } ] [ [ recursive-terminator ] infer short-effect ] unit-test
GENERIC: potential-hang ( obj -- obj )
M: fixnum potential-hang dup [ potential-hang ] when ;
[ ] [ [ 5 potential-hang ] infer drop ] unit-test
[ ] [ [ 5 potential-hang ] infer short-effect drop ] unit-test
TUPLE: funny-cons car cdr ;
GENERIC: iterate ( obj -- )
@ -164,24 +167,24 @@ M: funny-cons iterate funny-cons-cdr iterate ;
M: f iterate drop ;
M: real iterate drop ;
[ { 1 0 } ] [ [ iterate ] infer ] unit-test
[ { 1 0 } ] [ [ iterate ] infer short-effect ] unit-test
! Regression
: cat ( obj -- * ) dup [ throw ] [ throw ] if ;
: dog ( a b c -- ) dup [ cat ] [ 3drop ] if ;
[ { 3 0 } ] [ [ dog ] infer ] unit-test
[ { 3 0 } ] [ [ dog ] infer short-effect ] unit-test
! Regression
DEFER: monkey
: friend ( a b c -- ) dup [ friend ] [ monkey ] if ;
: monkey ( a b c -- ) dup [ 3drop ] [ friend ] if ;
[ { 3 0 } ] [ [ friend ] infer ] unit-test
[ { 3 0 } ] [ [ friend ] infer short-effect ] unit-test
! Regression -- same as above but we infer the second word first
! Regression -- same as above but we infer short-effect the second word first
DEFER: blah2
: blah ( a b c -- ) dup [ blah ] [ blah2 ] if ;
: blah2 ( a b c -- ) dup [ blah ] [ 3drop ] if ;
[ { 3 0 } ] [ [ blah2 ] infer ] unit-test
[ { 3 0 } ] [ [ blah2 ] infer short-effect ] unit-test
! Regression
DEFER: blah4
@ -189,7 +192,7 @@ DEFER: blah4
dup [ blah3 ] [ dup [ blah4 ] [ blah3 ] if ] if ;
: blah4 ( a b c -- )
dup [ blah4 ] [ dup [ 3drop ] [ blah3 ] if ] if ;
[ { 3 0 } ] [ [ blah4 ] infer ] unit-test
[ { 3 0 } ] [ [ blah4 ] infer short-effect ] unit-test
! Regression
: bad-combinator ( obj quot -- )
@ -199,14 +202,14 @@ DEFER: blah4
[ swap slip ] keep swap bad-combinator
] if ; inline
[ [ [ 1 ] [ ] bad-combinator ] infer ] unit-test-fails
[ [ [ 1 ] [ ] bad-combinator ] infer short-effect ] unit-test-fails
! Regression
: bad-input#
dup string? [ 2array throw ] unless
over string? [ 2array throw ] unless ;
[ { 2 2 } ] [ [ bad-input# ] infer ] unit-test
[ { 2 2 } ] [ [ bad-input# ] infer short-effect ] unit-test
! Regression
@ -214,18 +217,18 @@ DEFER: blah4
DEFER: do-crap
: more-crap ( obj -- ) dup [ drop ] [ dup do-crap call ] if ;
: do-crap ( obj -- ) dup [ more-crap ] [ do-crap ] if ;
[ [ do-crap ] infer ] unit-test-fails
[ [ do-crap ] infer short-effect ] unit-test-fails
! This one does not
DEFER: do-crap*
: more-crap* ( obj -- ) dup [ drop ] [ dup do-crap* call ] if ;
: do-crap* ( obj -- ) dup [ do-crap* ] [ more-crap* ] if ;
[ [ do-crap* ] infer ] unit-test-fails
[ [ do-crap* ] infer short-effect ] unit-test-fails
! Regression
: too-deep ( a b -- c )
dup [ drop ] [ 2dup too-deep too-deep * ] if ; inline
[ { 2 1 } ] [ [ too-deep ] infer ] unit-test
[ { 2 1 } ] [ [ too-deep ] infer short-effect ] unit-test
! Error reporting is wrong
G: xyz math-combination ;
@ -233,7 +236,7 @@ M: fixnum xyz 2array ;
M: ratio xyz
[ >fraction ] 2apply swapd >r 2array swap r> 2array swap ;
[ t ] [ [ [ xyz ] infer ] catch inference-error? ] unit-test
[ t ] [ [ [ xyz ] infer short-effect ] catch inference-error? ] unit-test
! Doug Coleman discovered this one while working on the
! calendar library
@ -265,17 +268,17 @@ DEFER: C
[ dup B C ]
} dispatch ;
[ { 1 0 } ] [ [ A ] infer ] unit-test
[ { 1 0 } ] [ [ B ] infer ] unit-test
[ { 1 0 } ] [ [ C ] infer ] unit-test
[ { 1 0 } ] [ [ A ] infer short-effect ] unit-test
[ { 1 0 } ] [ [ B ] infer short-effect ] unit-test
[ { 1 0 } ] [ [ C ] infer short-effect ] unit-test
! I found this bug by thinking hard about the previous one
DEFER: Y
: X ( a b -- c d ) dup [ swap Y ] [ ] if ;
: Y ( a b -- c d ) X ;
[ { 2 2 } ] [ [ X ] infer ] unit-test
[ { 2 2 } ] [ [ Y ] infer ] unit-test
[ { 2 2 } ] [ [ X ] infer short-effect ] unit-test
[ { 2 2 } ] [ [ Y ] infer short-effect ] unit-test
! This one comes from UI code
DEFER: #1
@ -284,68 +287,92 @@ DEFER: #1
: #4 ( a -- ) dup [ drop ] [ dup #4 dup #3 call ] if ;
: #1 ( a -- ) dup [ dup #4 dup #3 ] [ ] if drop ;
[ \ #4 word-def infer ] unit-test-fails
[ [ #1 ] infer ] unit-test-fails
[ \ #4 word-def infer short-effect ] unit-test-fails
[ [ #1 ] infer short-effect ] unit-test-fails
! Similar
DEFER: bar
: foo ( a b -- c d ) dup [ 2drop f f bar ] [ ] if ;
: bar ( a b -- ) [ 2 2 + ] t foo drop call drop ;
[ [ foo ] infer ] unit-test-fails
[ [ foo ] infer short-effect ] unit-test-fails
[ 1234 infer ] unit-test-fails
[ 1234 infer short-effect ] unit-test-fails
! This used to hang
[ [ [ dup call ] dup call ] infer ] unit-test-fails
[ [ [ dup call ] dup call ] infer short-effect ] unit-test-fails
! This form should not have a stack effect
: bad-recursion-1 ( a -- b )
dup [ drop bad-recursion-1 5 ] [ ] if ;
[ [ bad-recursion-1 ] infer ] unit-test-fails
[ [ bad-recursion-1 ] infer short-effect ] unit-test-fails
: bad-bin ( a b -- ) 5 [ 5 bad-bin bad-bin 5 ] [ 2drop ] if ;
[ [ bad-bin ] infer ] unit-test-fails
[ [ bad-bin ] infer short-effect ] unit-test-fails
[ t ] [ [ [ r> ] infer ] catch inference-error? ] unit-test
[ t ] [ [ [ r> ] infer short-effect ] catch inference-error? ] unit-test
! Test some random library words
[ { 1 1 } ] [ [ unit ] infer ] unit-test
[ { 1 1 } ] [ [ unit ] infer short-effect ] unit-test
[ { 1 0 } ] [ [ >n ] infer ] unit-test
[ { 0 1 } ] [ [ n> ] infer ] unit-test
! Unbalanced >n/n> is an error now!
! [ { 1 0 } ] [ [ >n ] infer short-effect ] unit-test
! [ { 0 1 } ] [ [ n> ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ bitor ] infer ] unit-test
[ { 2 1 } ] [ [ bitand ] infer ] unit-test
[ { 2 1 } ] [ [ bitxor ] infer ] unit-test
[ { 2 1 } ] [ [ mod ] infer ] unit-test
[ { 2 1 } ] [ [ /i ] infer ] unit-test
[ { 2 1 } ] [ [ /f ] infer ] unit-test
[ { 2 2 } ] [ [ /mod ] infer ] unit-test
[ { 2 1 } ] [ [ + ] infer ] unit-test
[ { 2 1 } ] [ [ - ] infer ] unit-test
[ { 2 1 } ] [ [ * ] infer ] unit-test
[ { 2 1 } ] [ [ / ] infer ] unit-test
[ { 2 1 } ] [ [ < ] infer ] unit-test
[ { 2 1 } ] [ [ <= ] infer ] unit-test
[ { 2 1 } ] [ [ > ] infer ] unit-test
[ { 2 1 } ] [ [ >= ] infer ] unit-test
[ { 2 1 } ] [ [ number= ] infer ] unit-test
[ { 2 1 } ] [ [ bitor ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ bitand ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ bitxor ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ mod ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ /i ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ /f ] infer short-effect ] unit-test
[ { 2 2 } ] [ [ /mod ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ + ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ - ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ * ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ / ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ < ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ <= ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ > ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ >= ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ number= ] infer short-effect ] unit-test
[ { 1 1 } ] [ [ string>number ] infer ] unit-test
[ { 2 1 } ] [ [ = ] infer ] unit-test
[ { 1 1 } ] [ [ get ] infer ] unit-test
[ { 1 1 } ] [ [ string>number ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ = ] infer short-effect ] unit-test
[ { 1 1 } ] [ [ get ] infer short-effect ] unit-test
[ { 2 0 } ] [ [ push ] infer ] unit-test
[ { 2 0 } ] [ [ set-length ] infer ] unit-test
[ { 2 1 } ] [ [ append ] infer ] unit-test
[ { 1 1 } ] [ [ peek ] infer ] unit-test
[ { 2 0 } ] [ [ push ] infer short-effect ] unit-test
[ { 2 0 } ] [ [ set-length ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ append ] infer short-effect ] unit-test
[ { 1 1 } ] [ [ peek ] infer short-effect ] unit-test
[ { 1 1 } ] [ [ length ] infer ] unit-test
[ { 1 1 } ] [ [ reverse ] infer ] unit-test
[ { 2 1 } ] [ [ member? ] infer ] unit-test
[ { 2 1 } ] [ [ remove ] infer ] unit-test
[ { 1 1 } ] [ [ natural-sort ] infer ] unit-test
[ { 1 1 } ] [ [ length ] infer short-effect ] unit-test
[ { 1 1 } ] [ [ reverse ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ member? ] infer short-effect ] unit-test
[ { 2 1 } ] [ [ remove ] infer short-effect ] unit-test
[ { 1 1 } ] [ [ natural-sort ] infer short-effect ] unit-test
! Test scope inference
SYMBOL: x
[ [ n> ] infer ] unit-test-fails
[ [ ndrop ] infer ] unit-test-fails
[ V{ x } ] [ [ x get ] infer drop inferred-vars-reads ] unit-test
[ V{ x } ] [ [ x set ] infer drop inferred-vars-writes ] unit-test
[ V{ x } ] [ [ [ x get ] with-scope ] infer drop inferred-vars-reads ] unit-test
[ V{ } ] [ [ [ x set ] with-scope ] infer drop inferred-vars-writes ] unit-test
[ V{ x } ] [ [ [ x get ] bind ] infer drop inferred-vars-reads ] unit-test
[ V{ } ] [ [ [ x set ] bind ] infer drop inferred-vars-writes ] unit-test
[ V{ x } ] [ [ [ x get ] make-hash ] infer drop inferred-vars-reads ] unit-test
[ V{ } ] [ [ [ x set ] make-hash ] infer drop inferred-vars-writes ] unit-test
[ V{ building } ] [ [ , ] infer drop inferred-vars-reads ] unit-test
[ V{ } ] [ [ [ 3 , ] { } make ] infer drop inferred-vars-reads ] unit-test
[ V{ x } ] [ [ [ x get ] [ 5 ] if ] infer drop inferred-vars-reads ] unit-test
[ V{ x } ] [ [ >n [ x get ] [ 5 ] if n> ] infer drop inferred-vars-reads ] unit-test
[ V{ } ] [ [ >n [ x set ] [ drop ] if x get n> ] infer drop inferred-vars-reads ] unit-test
[ V{ x } ] [ [ >n x get ndrop ] infer drop inferred-vars-reads ] unit-test
[ V{ } ] [ [ >n x set ndrop ] infer drop inferred-vars-writes ] unit-test
[ [ >n ] [ ] if ] unit-test-fails

View File

@ -44,7 +44,7 @@ C: effect
: stack-effect ( word -- effect/f )
dup "declared-effect" word-prop [ ] [
dup "infer-effect" word-prop [ ] [ drop f ] ?if
dup "inferred-effect" word-prop [ ] [ drop f ] ?if
] ?if ;
M: effect clone

View File

@ -34,7 +34,9 @@ SYMBOL: restarts
error-continuation get continuation-name hash-stack ;
: :res ( n -- )
restarts get nth first3 continue-with ;
restarts get-global nth
f restarts set-global
first3 continue-with ;
: :edit ( -- )
error get

View File

@ -75,7 +75,7 @@ M: gadget ungraft* drop ;
: build-spec ( spec quot -- )
swap (build-spec) call ;
\ build-spec 2 0 <effect> "infer-effect" set-word-prop
\ build-spec 2 0 <effect> "inferred-effect" set-word-prop
\ build-spec [
pop-literal pop-literal nip (build-spec) infer-quot-value

View File

@ -85,8 +85,10 @@ SYMBOL: crossref
{ [ dup "infer" word-prop ] [ drop ] }
{ [ t ] [
dup changed-word
{ "infer-effect" "base-case" "no-effect" }
reset-props
{
"inferred-effect" "inferred-vars"
"base-case" "no-effect"
} reset-props
] }
} cond ;