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

db4
Doug Coleman 2008-02-14 14:15:00 -06:00
commit a89aea1a78
69 changed files with 1155 additions and 663 deletions

View File

@ -74,6 +74,12 @@ nl
malloc free memcpy malloc free memcpy
} compile } compile
[ compiled-usages recompile ] recompile-hook set-global : enable-compiler ( -- )
[ compiled-usages recompile ] recompile-hook set-global ;
: disable-compiler ( -- )
[ [ f ] { } map>assoc modify-code-heap ] recompile-hook set-global ;
enable-compiler
" done" print flush " done" print flush

View File

@ -7,11 +7,7 @@ ARTICLE: "combinators-quot" "Quotation construction utilities"
"Some words for creating quotations which can be useful for implementing method combinations and compiler transforms:" "Some words for creating quotations which can be useful for implementing method combinations and compiler transforms:"
{ $subsection cond>quot } { $subsection cond>quot }
{ $subsection case>quot } { $subsection case>quot }
{ $subsection alist>quot } { $subsection alist>quot } ;
"A powerful tool used to optimize code in several places is open-coded hashtable dispatch:"
{ $subsection hash-case>quot }
{ $subsection distribute-buckets }
{ $subsection hash-dispatch-quot } ;
ARTICLE: "combinators" "Additional combinators" ARTICLE: "combinators" "Additional combinators"
"The " { $vocab-link "combinators" } " vocabulary is usually used because it provides two combinators which abstract out nested chains of " { $link if } ":" "The " { $vocab-link "combinators" } " vocabulary is usually used because it provides two combinators which abstract out nested chains of " { $link if } ":"
@ -104,19 +100,17 @@ HELP: case>quot
{ $values { "assoc" "a sequence of pairs of quotations" } { "default" quotation } { "quot" quotation } } { $values { "assoc" "a sequence of pairs of quotations" } { "default" quotation } { "quot" quotation } }
{ $description "Creates a quotation that when called, has the same effect as applying " { $link case } " to " { $snippet "assoc" } "." { $description "Creates a quotation that when called, has the same effect as applying " { $link case } " to " { $snippet "assoc" } "."
$nl $nl
"The quotation actually tests each possible case in order;" { $link hash-case>quot } " produces more efficient code." } ; "This word uses three strategies:"
{ $list
"If the assoc only has a few keys, a linear search is generated."
{ "If the assoc has a large number of keys which form a contiguous range of integers, a direct dispatch is generated using the " { $link dispatch } " word together with a bounds check." }
"Otherwise, an open-coded hashtable dispatch is generated."
} } ;
HELP: distribute-buckets HELP: distribute-buckets
{ $values { "assoc" "an alist" } { "initial" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- assoc )" } } { "buckets" "a new array" } } { $values { "assoc" "an alist" } { "initial" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- assoc )" } } { "buckets" "a new array" } }
{ $description "Sorts the entries of " { $snippet "assoc" } " into buckets, using the quotation to yield a set of keys for each entry. The hashcode of each key is computed, and the entry is placed in all corresponding buckets. Each bucket is initially cloned from " { $snippet "initial" } "; this should either be an empty vector or a one-element vector containing a pair." } { $description "Sorts the entries of " { $snippet "assoc" } " into buckets, using the quotation to yield a set of keys for each entry. The hashcode of each key is computed, and the entry is placed in all corresponding buckets. Each bucket is initially cloned from " { $snippet "initial" } "; this should either be an empty vector or a one-element vector containing a pair." }
{ $notes "This word is used in the implemention of " { $link hash-case>quot } " and " { $link standard-combination } "." } ; { $notes "This word is used in the implemention of " { $link hash-case-quot } " and " { $link standard-combination } "." } ;
HELP: hash-case>quot
{ $values { "default" quotation } { "assoc" "an association list mapping quotations to quotations" } { "quot" quotation } }
{ $description "Creates a quotation that when called, has the same effect as applying " { $link case } " to " { $snippet "assoc" } "."
$nl
"The quotation uses an efficient hash-based search to avoid testing the object against all possible keys." }
{ $notes "This word is used behind the scenes to compile " { $link case } " forms efficiently; it can also be called directly, which is useful for meta-programming." } ;
HELP: dispatch ( n array -- ) HELP: dispatch ( n array -- )
{ $values { "n" "a fixnum" } { "array" "an array of quotations" } } { $values { "n" "a fixnum" } { "array" "an array of quotations" } }

7
core/combinators/combinators-tests.factor Normal file → Executable file
View File

@ -69,3 +69,10 @@ namespaces combinators words ;
! Interpreted ! Interpreted
[ "a hashtable" ] [ H{ } \ case-test-3 word-def call ] unit-test [ "a hashtable" ] [ H{ } \ case-test-3 word-def call ] unit-test
[ 1 3 t ] [ { 1 3 2 } contiguous-range? ] unit-test
[ f ] [ { 1 2 2 4 } contiguous-range? 2nip ] unit-test
[ f ] [ { + 3 2 } contiguous-range? 2nip ] unit-test
[ f ] [ { 1 0 7 } contiguous-range? 2nip ] unit-test
[ f ] [ { 1 1 3 7 } contiguous-range? 2nip ] unit-test
[ 4 8 t ] [ { 7 6 4 8 5 } contiguous-range? ] unit-test

View File

@ -1,8 +1,9 @@
! Copyright (C) 2006, 2007 Slava Pestov. ! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
IN: combinators IN: combinators
USING: arrays sequences sequences.private math.private USING: arrays sequences sequences.private math.private
kernel kernel.private math assocs quotations vectors ; kernel kernel.private math assocs quotations vectors
hashtables sorting ;
TUPLE: no-cond ; TUPLE: no-cond ;
@ -31,16 +32,24 @@ TUPLE: no-case ;
: recursive-hashcode ( n obj quot -- code ) : recursive-hashcode ( n obj quot -- code )
pick 0 <= [ 3drop 0 ] [ rot 1- -rot call ] if ; inline pick 0 <= [ 3drop 0 ] [ rot 1- -rot call ] if ; inline
! These go here, not in sequences and hashtables, since those
! two depend on combinators
M: sequence hashcode* M: sequence hashcode*
[ sequence-hashcode ] recursive-hashcode ; [ sequence-hashcode ] recursive-hashcode ;
M: hashtable hashcode*
[
dup assoc-size 1 number=
[ assoc-hashcode ] [ nip assoc-size ] if
] recursive-hashcode ;
: alist>quot ( default assoc -- quot ) : alist>quot ( default assoc -- quot )
[ rot \ if 3array append [ ] like ] assoc-each ; [ rot \ if 3array append [ ] like ] assoc-each ;
: cond>quot ( assoc -- quot ) : cond>quot ( assoc -- quot )
reverse [ no-cond ] swap alist>quot ; reverse [ no-cond ] swap alist>quot ;
: case>quot ( default assoc -- quot ) : linear-case-quot ( default assoc -- quot )
[ >r [ dupd = ] curry r> \ drop add* ] assoc-map [ >r [ dupd = ] curry r> \ drop add* ] assoc-map
alist>quot ; alist>quot ;
@ -63,20 +72,50 @@ M: sequence hashcode*
: hash-case-table ( default assoc -- array ) : hash-case-table ( default assoc -- array )
V{ } [ 1array ] distribute-buckets V{ } [ 1array ] distribute-buckets
[ case>quot ] with map ; [ linear-case-quot ] with map ;
: hash-dispatch-quot ( table -- quot ) : hash-dispatch-quot ( table -- quot )
[ length 1- [ fixnum-bitand ] curry ] keep [ length 1- [ fixnum-bitand ] curry ] keep
[ dispatch ] curry append ; [ dispatch ] curry append ;
: hash-case>quot ( default assoc -- quot ) : hash-case-quot ( default assoc -- quot )
hash-case-table hash-dispatch-quot
[ dup hashcode >fixnum ] swap append ;
: contiguous-range? ( keys -- from to ? )
dup [ fixnum? ] all? [
dup all-unique? [
dup infimum over supremum
[ - swap prune length + 1 = ] 2keep rot
] [
drop f f f
] if
] [
drop f f f
] if ;
: dispatch-case ( value from to default array -- )
>r >r 3dup between? [
drop - >fixnum r> drop r> dispatch
] [
2drop r> call r> drop
] if ; inline
: dispatch-case-quot ( default assoc from to -- quot )
-roll -roll sort-keys values [ >quotation ] map
[ dispatch-case ] 2curry 2curry ;
: case>quot ( default assoc -- quot )
dup empty? [ dup empty? [
drop drop
] [ ] [
dup length 4 <= [ dup length 4 <= [
case>quot linear-case-quot
] [ ] [
hash-case-table hash-dispatch-quot dup keys contiguous-range? [
[ dup hashcode >fixnum ] swap append dispatch-case-quot
] [
2drop hash-case-quot
] if
] if ] if
] if ; ] if ;

View File

@ -1,7 +1,7 @@
IN: temporary IN: temporary
USING: compiler tools.test namespaces sequences USING: compiler tools.test namespaces sequences
kernel.private kernel math continuations continuations.private kernel.private kernel math continuations continuations.private
words splitting ; words splitting sorting ;
: symbolic-stack-trace ( -- newseq ) : symbolic-stack-trace ( -- newseq )
error-continuation get continuation-call callstack>array error-continuation get continuation-call callstack>array
@ -31,9 +31,9 @@ words splitting ;
\ > stack-trace-contains? \ > stack-trace-contains?
] unit-test ] unit-test
: quux [ t [ "hi" throw ] when ] times ; : quux { 1 2 3 } [ "hi" throw ] sort ;
[ t ] [ [ t ] [
[ 10 quux ] ignore-errors [ 10 quux ] ignore-errors
\ (each-integer) stack-trace-contains? \ sort stack-trace-contains?
] unit-test ] unit-test

View File

@ -44,7 +44,9 @@ words kernel math effects definitions compiler.units ;
[ [
[ ] [ init-templates ] unit-test [ ] [ init-templates ] unit-test
[ ] [ init-generator ] unit-test H{ } clone compiled set
[ ] [ gensym gensym begin-compiling ] unit-test
[ t ] [ [ end-basic-block ] { } make empty? ] unit-test [ t ] [ [ end-basic-block ] { } make empty? ] unit-test

View File

@ -1,8 +1,7 @@
! Copyright (C) 2005, 2007 Slava Pestov. ! Copyright (C) 2005, 2007 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: arrays kernel kernel.private slots.private math assocs USING: arrays kernel kernel.private slots.private math assocs
math.private sequences sequences.private vectors math.private sequences sequences.private vectors ;
combinators ;
IN: hashtables IN: hashtables
<PRIVATE <PRIVATE
@ -161,17 +160,10 @@ M: hashtable clone
(clone) dup hash-array clone over set-hash-array ; (clone) dup hash-array clone over set-hash-array ;
M: hashtable equal? M: hashtable equal?
{ over hashtable? [
{ [ over hashtable? not ] [ 2drop f ] } 2dup [ assoc-size ] 2apply number=
{ [ 2dup [ assoc-size ] 2apply number= not ] [ 2drop f ] } [ assoc= ] [ 2drop f ] if
{ [ t ] [ assoc= ] } ] [ 2drop f ] if ;
} cond ;
M: hashtable hashcode*
[
dup assoc-size 1 number=
[ assoc-hashcode ] [ nip assoc-size ] if
] recursive-hashcode ;
! Default method ! Default method
M: assoc new-assoc drop <hashtable> ; M: assoc new-assoc drop <hashtable> ;

View File

@ -314,7 +314,7 @@ PREDICATE: #merge #tail-merge node-successor #tail? ;
PREDICATE: #values #tail-values node-successor #tail? ; PREDICATE: #values #tail-values node-successor #tail? ;
UNION: #tail UNION: #tail
POSTPONE: f #return #tail-values #tail-merge ; POSTPONE: f #return #tail-values #tail-merge #terminate ;
: tail-call? ( -- ? ) : tail-call? ( -- ? )
node-stack get [ node-successor #tail? ] all? ; node-stack get [ node-successor #tail? ] all? ;

View File

@ -35,7 +35,7 @@ IN: inference.transforms
dup peek swap 1 head* dup peek swap 1 head*
] [ ] [
[ no-case ] swap [ no-case ] swap
] if hash-case>quot ] if case>quot
] if ] if
] 1 define-transform ] 1 define-transform

View File

@ -0,0 +1,5 @@
USING: help.syntax help.markup ;
IN: io.encodings.binary
HELP: binary
{ $class-description "This is the encoding descriptor for binary I/O." } ;

View File

@ -0,0 +1,6 @@
USING: kernel io.encodings ;
TUPLE: binary ;
M: binary init-decoding drop ;
M: binary init-encoding drop ;

View File

@ -0,0 +1 @@
Dummy encoding for binary I/O

View File

@ -0,0 +1 @@
text

View File

@ -1,7 +1,8 @@
! Copyright (C) 2006, 2007 Daniel Ehrenberg. ! Copyright (C) 2006, 2007 Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: math kernel sequences sbufs vectors USING: math kernel sequences sbufs vectors io.streams.lines io.streams.plain
namespaces unicode.syntax ; namespaces unicode.syntax growable strings io classes io.streams.c
continuations ;
IN: io.encodings IN: io.encodings
TUPLE: encode-error ; TUPLE: encode-error ;
@ -23,6 +24,72 @@ SYMBOL: begin
: finish-decoding ( buf ch state -- str ) : finish-decoding ( buf ch state -- str )
begin eq? [ decode-error ] unless drop "" like ; begin eq? [ decode-error ] unless drop "" like ;
: decode ( seq quot -- str ) : start-decoding ( seq length -- buf ch state seq )
>r [ length <sbuf> 0 begin ] keep r> each <sbuf> 0 begin roll ;
GENERIC: decode-step ( buf byte ch state encoding -- buf ch state )
: decode ( seq quot -- string )
>r dup length start-decoding r>
[ -rot ] swap compose each
finish-decoding ; inline finish-decoding ; inline
: space ( resizable -- room-left )
dup underlying swap [ length ] 2apply - ;
: full? ( resizable -- ? ) space zero? ;
: end-read-loop ( buf ch state stream quot -- string/f )
2drop 2drop >string f like ;
: decode-read-loop ( buf ch state stream encoding -- string/f )
>r >r pick r> r> rot full? [ end-read-loop ] [
over stream-read1 [
-rot tuck >r >r >r -rot r> decode-step r> r> decode-read-loop
] [ end-read-loop ] if*
] if ;
: decode-read ( length stream encoding -- string )
>r swap start-decoding r>
decode-read-loop ;
GENERIC: init-decoding ( stream encoding -- decoded-stream )
: <decoding> ( stream decoding-class -- decoded-stream )
construct-empty init-decoding <line-reader> ;
GENERIC: init-encoding ( stream encoding -- encoded-stream )
: <encoding> ( stream encoding-class -- encoded-stream )
construct-empty init-encoding <plain-writer> ;
GENERIC: encode-string ( string encoding -- byte-array )
M: tuple-class encode-string construct-empty encode-string ;
MIXIN: encoding-stream
M: encoding-stream init-decoding ( stream encoding-stream -- encoding-stream )
tuck set-delegate ;
M: encoding-stream init-encoding ( stream encoding-stream -- encoding-stream )
tuck set-delegate ;
M: encoding-stream stream-read1 1 swap stream-read ;
M: encoding-stream stream-read
[ delegate ] keep decode-read ;
M: encoding-stream stream-read-partial stream-read ;
M: encoding-stream stream-read-until
! Copied from { c-reader stream-read-until }!!!
[ swap read-until-loop ] "" make
swap over empty? over not and [ 2drop f f ] when ;
M: encoding-stream stream-write1
>r 1string r> stream-write ;
M: encoding-stream stream-write
[ encode-string ] keep delegate stream-write ;
M: encoding-stream dispose delegate dispose ;

View File

@ -0,0 +1,5 @@
USING: help.syntax help.markup ;
IN: io.encodings.latin1
HELP: latin1
{ $class-description "This class is used for Latin 1 (ISO 8859-1) encoding and decoding" } ;

View File

@ -0,0 +1,19 @@
USING: io io.encodings strings kernel ;
IN: io.encodings.latin1
TUPLE: latin1 stream ;
M: latin1 init-decoding tuck set-latin1-stream ;
M: latin1 init-encoding drop ;
M: latin1 stream-read1
latin1-stream stream-read1 ;
M: latin1 stream-read
latin1-stream stream-read >string ;
M: latin1 stream-read-until
latin1-stream stream-read-until >string ;
M: latin1 stream-readln
latin1-stream stream-readln >string ;

View File

@ -0,0 +1 @@
ISO 8859-1 encoding/decoding

View File

@ -0,0 +1 @@
text

Binary file not shown.

View File

@ -0,0 +1 @@
Daniel Ehrenberg

View File

@ -0,0 +1 @@
text

View File

@ -1,5 +1,5 @@
USING: help.markup help.syntax io.encodings strings ; USING: help.markup help.syntax io.encodings strings ;
IN: io.utf16 IN: io.encodings.utf16
ARTICLE: "io.utf16" "Working with UTF16-encoded data" ARTICLE: "io.utf16" "Working with UTF16-encoded data"
"The UTF16 encoding is a variable-width encoding. Unicode code points are encoded as 2 or 4 byte sequences." "The UTF16 encoding is a variable-width encoding. Unicode code points are encoded as 2 or 4 byte sequences."

View File

@ -2,7 +2,7 @@
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: math kernel sequences sbufs vectors namespaces io.binary USING: math kernel sequences sbufs vectors namespaces io.binary
io.encodings combinators splitting ; io.encodings combinators splitting ;
IN: io.utf16 IN: io.encodings.utf16
SYMBOL: double SYMBOL: double
SYMBOL: quad1 SYMBOL: quad1
@ -30,7 +30,7 @@ SYMBOL: ignore
>r 2 shift r> BIN: 11 bitand bitor quad3 >r 2 shift r> BIN: 11 bitand bitor quad3
] [ 2drop do-ignore ] if ; ] [ 2drop do-ignore ] if ;
: (decode-utf16be) ( buf byte ch state -- buf ch state ) : decode-utf16be-step ( buf byte ch state -- buf ch state )
{ {
{ begin [ drop begin-utf16be ] } { begin [ drop begin-utf16be ] }
{ double [ end-multibyte ] } { double [ end-multibyte ] }
@ -41,7 +41,7 @@ SYMBOL: ignore
} case ; } case ;
: decode-utf16be ( seq -- str ) : decode-utf16be ( seq -- str )
[ -rot (decode-utf16be) ] decode ; [ decode-utf16be-step ] decode ;
: handle-double ( buf byte ch -- buf ch state ) : handle-double ( buf byte ch -- buf ch state )
swap dup -3 shift BIN: 11011 = [ swap dup -3 shift BIN: 11011 = [
@ -55,7 +55,7 @@ SYMBOL: ignore
BIN: 11 bitand append-nums HEX: 10000 + decoded BIN: 11 bitand append-nums HEX: 10000 + decoded
] [ 2drop push-replacement ] if ; ] [ 2drop push-replacement ] if ;
: (decode-utf16le) ( buf byte ch state -- buf ch state ) : decode-utf16le-step ( buf byte ch state -- buf ch state )
{ {
{ begin [ drop double ] } { begin [ drop double ] }
{ double [ handle-double ] } { double [ handle-double ] }
@ -65,7 +65,7 @@ SYMBOL: ignore
} case ; } case ;
: decode-utf16le ( seq -- str ) : decode-utf16le ( seq -- str )
[ -rot (decode-utf16le) ] decode ; [ decode-utf16le-step ] decode ;
: encode-first : encode-first
-10 shift -10 shift
@ -104,13 +104,23 @@ SYMBOL: ignore
: encode-utf16 ( str -- seq ) : encode-utf16 ( str -- seq )
encode-utf16le bom-le swap append ; encode-utf16le bom-le swap append ;
: utf16le? ( seq1 -- seq2 ? ) bom-le ?head ;
: utf16be? ( seq1 -- seq2 ? ) bom-be ?head ;
: decode-utf16 ( seq -- str ) : decode-utf16 ( seq -- str )
{ {
{ [ utf16le? ] [ decode-utf16le ] } { [ bom-le ?head ] [ decode-utf16le ] }
{ [ utf16be? ] [ decode-utf16be ] } { [ bom-be ?head ] [ decode-utf16be ] }
{ [ t ] [ decode-error ] } { [ t ] [ decode-error ] }
} cond ; } cond ;
TUPLE: utf16le ;
: <utf16le> utf16le construct-delegate ;
INSTANCE: utf16le encoding-stream
M: utf16le encode-string drop encode-utf16le ;
M: utf16le decode-step drop decode-utf16le-step ;
TUPLE: utf16be ;
: <utf16be> utf16be construct-delegate ;
INSTANCE: utf16be encoding-stream
M: utf16be encode-string drop encode-utf16be ;
M: utf16be decode-step drop decode-utf16be-step ;

View File

@ -0,0 +1 @@
Daniel Ehrenberg

View File

@ -0,0 +1 @@
text

View File

@ -1,12 +1,12 @@
USING: help.markup help.syntax io.encodings strings ; USING: help.markup help.syntax io.encodings strings ;
IN: io.utf8 IN: io.encodings.utf8
ARTICLE: "io.utf8" "Working with UTF8-encoded data" ARTICLE: "io.encodings.utf8" "Working with UTF8-encoded data"
"The UTF8 encoding is a variable-width encoding. 7-bit ASCII characters are encoded as single bytes, and other Unicode code points are encoded as 2 to 4 byte sequences." "The UTF8 encoding is a variable-width encoding. 7-bit ASCII characters are encoded as single bytes, and other Unicode code points are encoded as 2 to 4 byte sequences."
{ $subsection encode-utf8 } { $subsection encode-utf8 }
{ $subsection decode-utf8 } ; { $subsection decode-utf8 } ;
ABOUT: "io.utf8" ABOUT: "io.encodings.utf8"
HELP: decode-utf8 HELP: decode-utf8
{ $values { "seq" "a sequence of bytes" } { "str" string } } { $values { "seq" "a sequence of bytes" } { "str" string } }

View File

@ -0,0 +1,23 @@
USING: io.encodings.utf8 tools.test sbufs kernel io
sequences strings arrays unicode.syntax ;
: decode-utf8-w/stream ( array -- newarray )
>sbuf dup reverse-here <utf8> contents >array ;
: encode-utf8-w/stream ( array -- newarray )
SBUF" " clone tuck <utf8> write >array ;
[ { UNICHAR: replacement-character } ] [ { BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 11111111 } decode-utf8-w/stream >array ] unit-test
[ { BIN: 101111111000000111111 } ] [ { BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 } decode-utf8-w/stream >array ] unit-test
[ "x" ] [ "x" decode-utf8-w/stream >string ] unit-test
[ { BIN: 11111000000 } ] [ { BIN: 11011111 BIN: 10000000 } decode-utf8-w/stream >array ] unit-test
[ { UNICHAR: replacement-character } ] [ { BIN: 10000000 } decode-utf8-w/stream >array ] unit-test
[ { BIN: 1111000000111111 } ] [ { BIN: 11101111 BIN: 10000000 BIN: 10111111 } decode-utf8-w/stream >array ] unit-test
[ B{ BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 BIN: 11101111 BIN: 10000000 BIN: 10111111 BIN: 11011111 BIN: 10000000 CHAR: x } ]
[ { BIN: 101111111000000111111 BIN: 1111000000111111 BIN: 11111000000 CHAR: x } encode-utf8 ] unit-test

View File

@ -1,8 +1,10 @@
! Copyright (C) 2006, 2007 Daniel Ehrenberg. ! Copyright (C) 2006, 2007 Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: math kernel sequences sbufs vectors USING: math kernel sequences sbufs vectors growable io continuations
namespaces io.encodings combinators ; namespaces io.encodings combinators strings io.streams.c ;
IN: io.utf8 IN: io.encodings.utf8
! Decoding UTF-8
SYMBOL: double SYMBOL: double
SYMBOL: triple SYMBOL: triple
@ -31,7 +33,7 @@ SYMBOL: quad3
: end-multibyte ( buf byte ch -- buf ch state ) : end-multibyte ( buf byte ch -- buf ch state )
f append-nums [ decoded ] unless* ; f append-nums [ decoded ] unless* ;
: (decode-utf8) ( buf byte ch state -- buf ch state ) : decode-utf8-step ( buf byte ch state -- buf ch state )
{ {
{ begin [ drop begin-utf8 ] } { begin [ drop begin-utf8 ] }
{ double [ end-multibyte ] } { double [ end-multibyte ] }
@ -43,7 +45,9 @@ SYMBOL: quad3
} case ; } case ;
: decode-utf8 ( seq -- str ) : decode-utf8 ( seq -- str )
[ -rot (decode-utf8) ] decode ; [ decode-utf8-step ] decode ;
! Encoding UTF-8
: encoded ( char -- ) : encoded ( char -- )
BIN: 111111 bitand BIN: 10000000 bitor , ; BIN: 111111 bitand BIN: 10000000 bitor , ;
@ -70,3 +74,13 @@ SYMBOL: quad3
: encode-utf8 ( str -- seq ) : encode-utf8 ( str -- seq )
[ [ char>utf8 ] each ] B{ } make ; [ [ char>utf8 ] each ] B{ } make ;
! Interface for streams
TUPLE: utf8 ;
: <utf8> utf8 construct-delegate ;
INSTANCE: utf8 encoding-stream
M: utf8 encode-string drop encode-utf8 ;
M: utf8 decode-step drop decode-utf8-step ;
! In the future, this should detect and ignore a BOM at the beginning

View File

@ -1,16 +0,0 @@
USING: io.utf8 tools.test strings arrays unicode.syntax ;
[ { UNICHAR: replacement-character } ] [ { BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 11111111 } decode-utf8 >array ] unit-test
[ { BIN: 101111111000000111111 } ] [ { BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 } decode-utf8 >array ] unit-test
[ "x" ] [ "x" decode-utf8 >string ] unit-test
[ { BIN: 11111000000 } ] [ { BIN: 11011111 BIN: 10000000 } decode-utf8 >array ] unit-test
[ { UNICHAR: replacement-character } ] [ { BIN: 10000000 } decode-utf8 >array ] unit-test
[ { BIN: 1111000000111111 } ] [ { BIN: 11101111 BIN: 10000000 BIN: 10111111 } decode-utf8 >array ] unit-test
[ B{ BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 BIN: 11101111 BIN: 10000000 BIN: 10111111 BIN: 11011111 BIN: 10000000 CHAR: x } ]
[ { BIN: 101111111000000111111 BIN: 1111000000111111 BIN: 11111000000 CHAR: x } encode-utf8 ] unit-test

View File

@ -3,8 +3,7 @@
USING: arrays generic assocs inference inference.class USING: arrays generic assocs inference inference.class
inference.dataflow inference.backend inference.state io kernel inference.dataflow inference.backend inference.state io kernel
math namespaces sequences vectors words quotations hashtables math namespaces sequences vectors words quotations hashtables
combinators classes generic.math continuations optimizer.def-use combinators classes optimizer.def-use ;
optimizer.pattern-match generic.standard optimizer.specializers ;
IN: optimizer.backend IN: optimizer.backend
SYMBOL: class-substitutions SYMBOL: class-substitutions
@ -68,8 +67,6 @@ DEFER: optimize-nodes
] if ] if
] when ; ] when ;
M: f set-node-successor 2drop ;
: optimize-nodes ( node -- newnode ) : optimize-nodes ( node -- newnode )
[ [
class-substitutions [ clone ] change class-substitutions [ clone ] change
@ -78,19 +75,9 @@ M: f set-node-successor 2drop ;
optimizer-changed get optimizer-changed get
] with-scope optimizer-changed set ; ] with-scope optimizer-changed set ;
! Generic nodes
M: node optimize-node* drop t f ; M: node optimize-node* drop t f ;
: cleanup-inlining ( node -- newnode changed? ) ! Post-inlining cleanup
node-successor [ node-successor t ] [ t f ] if* ;
! #return
M: #return optimize-node* cleanup-inlining ;
! #values
M: #values optimize-node* cleanup-inlining ;
! Some utilities for splicing in dataflow IR subtrees
: follow ( key assoc -- value ) : follow ( key assoc -- value )
2dup at* [ swap follow nip ] [ 2drop ] if ; 2dup at* [ swap follow nip ] [ 2drop ] if ;
@ -103,282 +90,30 @@ M: #values optimize-node* cleanup-inlining ;
#! Not very efficient. #! Not very efficient.
dupd union* update ; dupd union* update ;
: post-inline ( #call/#merge #return/#values -- assoc ) : compute-value-substitutions ( #return/#values #call/#merge -- assoc )
>r node-out-d r> node-in-d 2array unify-lengths flip node-out-d swap node-in-d 2array unify-lengths flip
[ = not ] assoc-subset >hashtable ; [ = not ] assoc-subset >hashtable ;
: substitute-def-use ( node -- ) : cleanup-inlining ( #return/#values -- newnode changed? )
#! As a first approximation, we take all the values used dup node-successor dup [
#! by the set of new nodes, and push a 't' on their class-substitutions get pick node-classes update
#! def-use list here. We could perform a full graph literal-substitutions get pick node-literals update
#! substitution, but we don't need to, because the next tuck compute-value-substitutions value-substitutions get swap update*
#! optimizer iteration will do that. We just need a minimal node-successor t
#! degree of accuracy; the new values should be marked as ] [
#! having _some_ usage, so that flushing doesn't erronously 2drop t f
#! flush them away. ] if ;
[ compute-def-use def-use get keys ] with-scope
def-use get [ [ t swap ?push ] change-at ] curry each ;
: substitute-node ( old new -- ) ! #return
#! The last node of 'new' becomes 'old', then values are M: #return optimize-node* cleanup-inlining ;
#! substituted. A subsequent optimizer phase kills the
#! last node of 'new' and the first node of 'old'.
dup substitute-def-use
last-node
class-substitutions get over node-classes update
literal-substitutions get over node-literals update
2dup post-inline value-substitutions get swap update*
set-node-successor ;
GENERIC: remember-method* ( method-spec node -- ) ! #values
M: #values optimize-node* cleanup-inlining ;
M: #call remember-method* M: f set-node-successor 2drop ;
[ node-history ?push ] keep set-node-history ;
M: node remember-method* : splice-node ( old new -- )
2drop ; dup splice-def-use last-node set-node-successor ;
: remember-method ( method-spec node -- )
swap dup second +inlined+ depends-on
[ swap remember-method* ] curry each-node ;
: (splice-method) ( #call method-spec quot -- node )
#! Must remember the method before splicing in, otherwise
#! the rest of the IR will also remember the method
pick node-in-d dataflow-with
[ remember-method ] keep
[ swap infer-classes/node ] 2keep
[ substitute-node ] keep ;
: splice-quot ( #call quot -- node )
over node-in-d dataflow-with
[ swap infer-classes/node ] 2keep
[ substitute-node ] keep ;
: drop-inputs ( node -- #shuffle ) : drop-inputs ( node -- #shuffle )
node-in-d clone \ #shuffle in-node ; node-in-d clone \ #shuffle in-node ;
! Constant branch folding
: fold-branch ( node branch# -- node )
over node-children nth
swap node-successor over substitute-node ;
! #if
: known-boolean-value? ( node value -- value ? )
2dup node-literal? [
node-literal t
] [
node-class {
{ [ dup null class< ] [ drop f f ] }
{ [ dup general-t class< ] [ drop t t ] }
{ [ dup \ f class< ] [ drop f t ] }
{ [ t ] [ drop f f ] }
} cond
] if ;
M: #if optimize-node*
dup dup node-in-d first known-boolean-value? [
over drop-inputs >r
0 1 ? fold-branch
r> [ set-node-successor ] keep
t
] [ 2drop t f ] if ;
M: #dispatch optimize-node*
dup dup node-in-d first 2dup node-literal? [
"Optimizing #dispatch" print
node-literal
over drop-inputs >r fold-branch r> [ set-node-successor ] keep t
] [
3drop t f
] if ;
! #call
: splice-method ( #call method-spec/t quot/t -- node/t )
#! t indicates failure
{
{ [ dup t eq? ] [ 3drop t ] }
{ [ 2over swap node-history member? ] [ 3drop t ] }
{ [ t ] [ (splice-method) ] }
} cond ;
! Single dispatch method inlining optimization
: already-inlined? ( node -- ? )
#! Was this node inlined from definition of 'word'?
dup node-param swap node-history memq? ;
: specific-method ( class word -- class ) order min-class ;
: node-class# ( node n -- class )
over node-in-d <reversed> ?nth node-class ;
: dispatching-class ( node word -- class )
[ dispatch# node-class# ] keep specific-method ;
! A heuristic to avoid excessive inlining
DEFER: (flat-length)
: word-flat-length ( word -- n )
dup get over inline? not or
[ drop 1 ] [ dup dup set word-def (flat-length) ] if ;
: (flat-length) ( seq -- n )
[
{
{ [ dup quotation? ] [ (flat-length) 1+ ] }
{ [ dup array? ] [ (flat-length) ] }
{ [ dup word? ] [ word-flat-length ] }
{ [ t ] [ drop 1 ] }
} cond
] map sum ;
: flat-length ( seq -- n )
[ word-def (flat-length) ] with-scope ;
: will-inline-method ( node word -- method-spec/t quot/t )
#! t indicates failure
tuck dispatching-class dup [
swap [ 2array ] 2keep
method method-word
dup flat-length 10 >=
[ 1quotation ] [ word-def ] if
] [
2drop t t
] if ;
: inline-standard-method ( node word -- node )
dupd will-inline-method splice-method ;
! Partial dispatch of math-generic words
: math-both-known? ( word left right -- ? )
math-class-max swap specific-method ;
: will-inline-math-method ( word left right -- method-spec/t quot/t )
#! t indicates failure
3dup math-both-known?
[ [ 3array ] 3keep math-method ] [ 3drop t t ] if ;
: inline-math-method ( #call word -- node )
over node-input-classes first2
will-inline-math-method splice-method ;
: inline-method ( #call -- node )
dup node-param {
{ [ dup standard-generic? ] [ inline-standard-method ] }
{ [ dup math-generic? ] [ inline-math-method ] }
{ [ t ] [ 2drop t ] }
} cond ;
! Resolve type checks at compile time where possible
: comparable? ( actual testing -- ? )
#! If actual is a subset of testing or if the two classes
#! are disjoint, return t.
2dup class< >r classes-intersect? not r> or ;
: optimize-predicate? ( #call -- ? )
dup node-param "predicating" word-prop dup [
>r node-class-first r> comparable?
] [
2drop f
] if ;
: literal-quot ( node literals -- quot )
#! Outputs a quotation which drops the node's inputs, and
#! pushes some literals.
>r node-in-d length \ drop <repetition>
r> [ literalize ] map append >quotation ;
: inline-literals ( node literals -- node )
#! Make #shuffle -> #push -> #return -> successor
dupd literal-quot splice-quot ;
: evaluate-predicate ( #call -- ? )
dup node-param "predicating" word-prop >r
node-class-first r> class< ;
: optimize-predicate ( #call -- node )
dup evaluate-predicate swap
dup node-successor #if? [
dup drop-inputs >r
node-successor swap 0 1 ? fold-branch
r> [ set-node-successor ] keep
] [
swap 1array inline-literals
] if ;
: optimizer-hooks ( node -- conditions )
node-param "optimizer-hooks" word-prop ;
: optimizer-hook ( node -- pair/f )
dup optimizer-hooks [ first call ] find 2nip ;
: optimize-hook ( node -- )
dup optimizer-hook second call ;
: define-optimizers ( word optimizers -- )
"optimizer-hooks" set-word-prop ;
: flush-eval? ( #call -- ? )
dup node-param "flushable" word-prop [
node-out-d [ unused? ] all?
] [
drop f
] if ;
: flush-eval ( #call -- node )
dup node-param +inlined+ depends-on
dup node-out-d length f <repetition> inline-literals ;
: partial-eval? ( #call -- ? )
dup node-param "foldable" word-prop [
dup node-in-d [ node-literal? ] with all?
] [
drop f
] if ;
: literal-in-d ( #call -- inputs )
dup node-in-d [ node-literal ] with map ;
: partial-eval ( #call -- node )
dup node-param +inlined+ depends-on
dup literal-in-d over node-param 1quotation
[ with-datastack inline-literals ] [ 2drop 2drop t ] recover ;
: define-identities ( words identities -- )
[ "identities" set-word-prop ] curry each ;
: find-identity ( node -- quot )
[ node-param "identities" word-prop ] keep
[ swap first in-d-match? ] curry find
nip dup [ second ] when ;
: apply-identities ( node -- node/f )
dup find-identity dup [ splice-quot ] [ 2drop f ] if ;
: optimistic-inline? ( #call -- ? )
dup node-param "specializer" word-prop dup [
>r node-input-classes r> specialized-length tail*
[ types length 1 = ] all?
] [
2drop f
] if ;
: optimistic-inline ( #call -- node )
dup node-param dup +inlined+ depends-on
word-def splice-quot ;
: method-body-inline? ( #call -- ? )
node-param dup method-body?
[ flat-length 8 <= ] [ drop f ] if ;
M: #call optimize-node*
{
{ [ dup flush-eval? ] [ flush-eval ] }
{ [ dup partial-eval? ] [ partial-eval ] }
{ [ dup find-identity ] [ apply-identities ] }
{ [ dup optimizer-hook ] [ optimize-hook ] }
{ [ dup optimize-predicate? ] [ optimize-predicate ] }
{ [ dup optimistic-inline? ] [ optimistic-inline ] }
{ [ dup method-body-inline? ] [ optimistic-inline ] }
{ [ t ] [ inline-method ] }
} cond dup not ;

255
core/optimizer/control/control.factor Normal file → Executable file
View File

@ -1,9 +1,60 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: kernel inference.dataflow combinators sequences USING: arrays generic assocs inference inference.class
namespaces math ; inference.dataflow inference.backend inference.state io kernel
math namespaces sequences vectors words quotations hashtables
combinators classes generic.math continuations optimizer.def-use
optimizer.backend generic.standard ;
IN: optimizer.control IN: optimizer.control
! ! ! Loop detection
! A LOOP
!
! #label A
! |
! #if ----> #merge ----> #return
! |
! -------------
! | |
! #call-label A |
! | ...
! #values
!
! NOT A LOOP (call to A not in tail position):
!
!
! #label A
! |
! #if ----> ... ----> #merge ----> #return
! |
! -------------
! | |
! #call-label A |
! | ...
! ...
! |
! #values
!
! NOT A LOOP (call to A nested inside another label/loop):
!
!
! #label A
! |
! #if ----> #merge ----> ... ----> #return
! |
! -------------
! | |
! ... #label B
! |
! #if -> ...
! |
! ---------
! | |
! #call-label A |
! | |
! ... ...
GENERIC: detect-loops* ( node -- ) GENERIC: detect-loops* ( node -- )
M: node detect-loops* drop ; M: node detect-loops* drop ;
@ -34,3 +85,201 @@ M: #call-label detect-loops*
: detect-loops ( node -- ) : detect-loops ( node -- )
[ detect-loops* ] each-node ; [ detect-loops* ] each-node ;
! ! ! Constant branch folding
!
! BEFORE
!
! #if ----> #merge ----> C
! |
! ---------
! | |
! A B
! | |
! #values |
! #values
!
! AFTER
!
! |
! A
! |
! #values
! |
! #merge
! |
! C
: fold-branch ( node branch# -- node )
over node-children nth
swap node-successor over splice-node ;
! #if
: known-boolean-value? ( node value -- value ? )
2dup node-literal? [
node-literal t
] [
node-class {
{ [ dup null class< ] [ drop f f ] }
{ [ dup general-t class< ] [ drop t t ] }
{ [ dup \ f class< ] [ drop f t ] }
{ [ t ] [ drop f f ] }
} cond
] if ;
: fold-if-branch? dup node-in-d first known-boolean-value? ;
: fold-if-branch ( node value -- node' )
over drop-inputs >r
0 1 ? fold-branch
r> [ set-node-successor ] keep ;
! ! ! Lifting code after a conditional if one branch throws
: only-one ( seq -- elt/f )
dup length 1 = [ first ] [ drop f ] if ;
: lift-throw-tail? ( #if -- tail/? )
dup node-successor #tail?
[ drop f ] [ active-children only-one ] if ;
: clone-node ( node -- newnode )
clone dup [ clone ] modify-values ;
! BEFORE
!
! #if ----> #merge ----> B ----> #return/#values
! |
! |
! ---------
! | |
! | A
! #terminate |
! #values
!
! AFTER
!
! #if ----> #merge (*) ----> #return/#values (**)
! |
! |
! ---------
! | |
! | A
! #terminate |
! #values
! |
! #merge (***)
! |
! B
! |
! #return/#values
!
! (*) has the same outputs as the inputs of (**), and it is not
! the same node as (***)
!
! Note: if (**) is #return is is sound to put #terminate there,
! but not if (**) is #values
: lift-branch
over
last-node clone-node
dup node-in-d \ #merge out-node
[ set-node-successor ] keep -rot
>r dup node-successor r> splice-node
set-node-successor ;
M: #if optimize-node*
dup fold-if-branch? [ fold-if-branch t ] [
drop dup lift-throw-tail? dup [
dupd lift-branch t
] [
2drop t f
] if
] if ;
: fold-dispatch-branch? dup node-in-d first tuck node-literal? ;
: fold-dispatch-branch ( node value -- node' )
dupd node-literal
over drop-inputs >r fold-branch r>
[ set-node-successor ] keep ;
M: #dispatch optimize-node*
dup fold-dispatch-branch? [
fold-dispatch-branch t
] [
2drop t f
] if ;
! Loop tail hoising: code after a loop can sometimes go in the
! non-recursive branch of the loop
! BEFORE:
! #label -> C -> #return 1
! |
! -> #if -> #merge -> #return 2
! |
! --------
! | |
! A B
! | |
! #values |
! #call-label
! |
! |
! #values
! AFTER:
! #label -> #terminate
! |
! -> #if -> #terminate
! |
! --------
! | |
! A B
! | |
! #values |
! | #call-label
! #merge |
! | |
! C #values
! |
! #return 1
: find-final-if ( node -- #if/f )
dup [
dup #if? [
dup node-successor #tail? [
node-successor find-final-if
] unless
] [
node-successor find-final-if
] if
] when ;
: detach-node-successor ( node -- successor )
dup node-successor #terminate rot set-node-successor ;
: lift-loop-tail? ( #label -- tail/f )
dup node-successor node-successor [
dup node-param swap node-child find-final-if dup [
node-children [ penultimate-node ] map
[
dup #call-label?
[ node-param eq? not ] [ 2drop t ] if
] with subset only-one
] [ 2drop f ] if
] [ drop f ] if ;
! M: #loop optimize-node*
! dup lift-loop-tail? dup [
! last-node >r
! dup detach-node-successor
! over node-child find-final-if detach-node-successor
! [ set-node-successor ] keep
! r> set-node-successor
! t
! ] [
! 2drop t f
! ] if ;

View File

@ -70,20 +70,6 @@ M: #branch node-def-use
#! #values node. #! #values node.
dup branch-def-use (node-def-use) ; dup branch-def-use (node-def-use) ;
! : dead-literals ( -- values )
! def-use get [ >r value? r> empty? and ] assoc-subset ;
!
! : kill-node* ( node values -- )
! [ swap remove-all ] curry modify-values ;
!
! : kill-node ( node values -- )
! dup assoc-empty?
! [ 2drop ] [ [ kill-node* ] curry each-node ] if ;
!
! : kill-values ( node -- )
! #! Remove literals which are not actually used anywhere.
! dead-literals kill-node ;
: compute-dead-literals ( -- values ) : compute-dead-literals ( -- values )
def-use get [ >r value? r> empty? and ] assoc-subset ; def-use get [ >r value? r> empty? and ] assoc-subset ;
@ -129,8 +115,18 @@ M: #r> kill-node* [ node-in-r empty? ] prune-if ;
dead-literals [ kill-nodes ] with-variable dead-literals [ kill-nodes ] with-variable
] if ; ] if ;
!
: sole-consumer ( #call -- node/f ) : sole-consumer ( #call -- node/f )
node-out-d first used-by node-out-d first used-by
dup length 1 = [ first ] [ drop f ] if ; dup length 1 = [ first ] [ drop f ] if ;
: splice-def-use ( node -- )
#! As a first approximation, we take all the values used
#! by the set of new nodes, and push a 't' on their
#! def-use list here. We could perform a full graph
#! substitution, but we don't need to, because the next
#! optimizer iteration will do that. We just need a minimal
#! degree of accuracy; the new values should be marked as
#! having _some_ usage, so that flushing doesn't erronously
#! flush them away.
[ compute-def-use def-use get keys ] with-scope
def-use get [ [ t swap ?push ] change-at ] curry each ;

View File

@ -0,0 +1,227 @@
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays generic assocs inference inference.class
inference.dataflow inference.backend inference.state io kernel
math namespaces sequences vectors words quotations hashtables
combinators classes generic.math continuations optimizer.def-use
optimizer.backend generic.standard optimizer.specializers
optimizer.def-use optimizer.pattern-match generic.standard
optimizer.control ;
IN: optimizer.inlining
GENERIC: remember-method* ( method-spec node -- )
M: #call remember-method*
[ node-history ?push ] keep set-node-history ;
M: node remember-method*
2drop ;
: remember-method ( method-spec node -- )
swap dup second +inlined+ depends-on
[ swap remember-method* ] curry each-node ;
: (splice-method) ( #call method-spec quot -- node )
#! Must remember the method before splicing in, otherwise
#! the rest of the IR will also remember the method
pick node-in-d dataflow-with
[ remember-method ] keep
[ swap infer-classes/node ] 2keep
[ splice-node ] keep ;
: splice-quot ( #call quot -- node )
over node-in-d dataflow-with
[ swap infer-classes/node ] 2keep
[ splice-node ] keep ;
! #call
: splice-method ( #call method-spec/t quot/t -- node/t )
#! t indicates failure
{
{ [ dup t eq? ] [ 3drop t ] }
{ [ 2over swap node-history member? ] [ 3drop t ] }
{ [ t ] [ (splice-method) ] }
} cond ;
! Single dispatch method inlining optimization
: already-inlined? ( node -- ? )
#! Was this node inlined from definition of 'word'?
dup node-param swap node-history memq? ;
: specific-method ( class word -- class ) order min-class ;
: node-class# ( node n -- class )
over node-in-d <reversed> ?nth node-class ;
: dispatching-class ( node word -- class )
[ dispatch# node-class# ] keep specific-method ;
! A heuristic to avoid excessive inlining
DEFER: (flat-length)
: word-flat-length ( word -- n )
dup get over inline? not or
[ drop 1 ] [ dup dup set word-def (flat-length) ] if ;
: (flat-length) ( seq -- n )
[
{
{ [ dup quotation? ] [ (flat-length) 1+ ] }
{ [ dup array? ] [ (flat-length) ] }
{ [ dup word? ] [ word-flat-length ] }
{ [ t ] [ drop 1 ] }
} cond
] map sum ;
: flat-length ( seq -- n )
[ word-def (flat-length) ] with-scope ;
: will-inline-method ( node word -- method-spec/t quot/t )
#! t indicates failure
tuck dispatching-class dup [
swap [ 2array ] 2keep
method method-word
dup flat-length 10 >=
[ 1quotation ] [ word-def ] if
] [
2drop t t
] if ;
: inline-standard-method ( node word -- node )
dupd will-inline-method splice-method ;
! Partial dispatch of math-generic words
: math-both-known? ( word left right -- ? )
math-class-max swap specific-method ;
: will-inline-math-method ( word left right -- method-spec/t quot/t )
#! t indicates failure
3dup math-both-known?
[ [ 3array ] 3keep math-method ] [ 3drop t t ] if ;
: inline-math-method ( #call word -- node )
over node-input-classes first2
will-inline-math-method splice-method ;
: inline-method ( #call -- node )
dup node-param {
{ [ dup standard-generic? ] [ inline-standard-method ] }
{ [ dup math-generic? ] [ inline-math-method ] }
{ [ t ] [ 2drop t ] }
} cond ;
! Resolve type checks at compile time where possible
: comparable? ( actual testing -- ? )
#! If actual is a subset of testing or if the two classes
#! are disjoint, return t.
2dup class< >r classes-intersect? not r> or ;
: optimize-predicate? ( #call -- ? )
dup node-param "predicating" word-prop dup [
>r node-class-first r> comparable?
] [
2drop f
] if ;
: literal-quot ( node literals -- quot )
#! Outputs a quotation which drops the node's inputs, and
#! pushes some literals.
>r node-in-d length \ drop <repetition>
r> [ literalize ] map append >quotation ;
: inline-literals ( node literals -- node )
#! Make #shuffle -> #push -> #return -> successor
dupd literal-quot splice-quot ;
: evaluate-predicate ( #call -- ? )
dup node-param "predicating" word-prop >r
node-class-first r> class< ;
: optimize-predicate ( #call -- node )
#! If the predicate is followed by a branch we fold it
#! immediately
dup evaluate-predicate swap
dup node-successor #if? [
dup drop-inputs >r
node-successor swap 0 1 ? fold-branch
r> [ set-node-successor ] keep
] [
swap 1array inline-literals
] if ;
: optimizer-hooks ( node -- conditions )
node-param "optimizer-hooks" word-prop ;
: optimizer-hook ( node -- pair/f )
dup optimizer-hooks [ first call ] find 2nip ;
: optimize-hook ( node -- )
dup optimizer-hook second call ;
: define-optimizers ( word optimizers -- )
"optimizer-hooks" set-word-prop ;
: flush-eval? ( #call -- ? )
dup node-param "flushable" word-prop [
node-out-d [ unused? ] all?
] [
drop f
] if ;
: flush-eval ( #call -- node )
dup node-param +inlined+ depends-on
dup node-out-d length f <repetition> inline-literals ;
: partial-eval? ( #call -- ? )
dup node-param "foldable" word-prop [
dup node-in-d [ node-literal? ] with all?
] [
drop f
] if ;
: literal-in-d ( #call -- inputs )
dup node-in-d [ node-literal ] with map ;
: partial-eval ( #call -- node )
dup node-param +inlined+ depends-on
dup literal-in-d over node-param 1quotation
[ with-datastack inline-literals ] [ 2drop 2drop t ] recover ;
: define-identities ( words identities -- )
[ "identities" set-word-prop ] curry each ;
: find-identity ( node -- quot )
[ node-param "identities" word-prop ] keep
[ swap first in-d-match? ] curry find
nip dup [ second ] when ;
: apply-identities ( node -- node/f )
dup find-identity dup [ splice-quot ] [ 2drop f ] if ;
: optimistic-inline? ( #call -- ? )
dup node-param "specializer" word-prop dup [
>r node-input-classes r> specialized-length tail*
[ types length 1 = ] all?
] [
2drop f
] if ;
: optimistic-inline ( #call -- node )
dup node-param dup +inlined+ depends-on
word-def splice-quot ;
: method-body-inline? ( #call -- ? )
node-param dup method-body?
[ flat-length 8 <= ] [ drop f ] if ;
M: #call optimize-node*
{
{ [ dup flush-eval? ] [ flush-eval ] }
{ [ dup partial-eval? ] [ partial-eval ] }
{ [ dup find-identity ] [ apply-identities ] }
{ [ dup optimizer-hook ] [ optimize-hook ] }
{ [ dup optimize-predicate? ] [ optimize-predicate ] }
{ [ dup optimistic-inline? ] [ optimistic-inline ] }
{ [ dup method-body-inline? ] [ optimistic-inline ] }
{ [ t ] [ inline-method ] }
} cond dup not ;

View File

@ -8,7 +8,7 @@ assocs quotations sequences.private io.binary io.crc32
io.streams.string layouts splitting math.intervals io.streams.string layouts splitting math.intervals
math.floats.private tuples tuples.private classes math.floats.private tuples tuples.private classes
optimizer.def-use optimizer.backend optimizer.pattern-match optimizer.def-use optimizer.backend optimizer.pattern-match
float-arrays sequences.private combinators ; optimizer.inlining float-arrays sequences.private combinators ;
! the output of <tuple> and <tuple-boa> has the class which is ! the output of <tuple> and <tuple-boa> has the class which is
! its second-to-last input ! its second-to-last input

View File

@ -7,7 +7,7 @@ inference.class inference.dataflow vectors strings sbufs io
namespaces assocs quotations math.intervals sequences.private namespaces assocs quotations math.intervals sequences.private
combinators splitting layouts math.parser classes generic.math combinators splitting layouts math.parser classes generic.math
optimizer.pattern-match optimizer.backend optimizer.def-use optimizer.pattern-match optimizer.backend optimizer.def-use
generic.standard system ; optimizer.inlining generic.standard system ;
{ + bignum+ float+ fixnum+fast } { { + bignum+ float+ fixnum+fast } {
{ { number 0 } [ drop ] } { { number 0 } [ drop ] }

View File

@ -2,7 +2,7 @@ USING: arrays compiler generic hashtables inference kernel
kernel.private math optimizer prettyprint sequences sbufs kernel.private math optimizer prettyprint sequences sbufs
strings tools.test vectors words sequences.private quotations strings tools.test vectors words sequences.private quotations
optimizer.backend classes inference.dataflow tuples.private optimizer.backend classes inference.dataflow tuples.private
continuations growable ; continuations growable optimizer.inlining ;
IN: temporary IN: temporary
[ H{ { 1 5 } { 3 4 } { 2 5 } } ] [ [ H{ { 1 5 } { 3 4 } { 2 5 } } ] [
@ -301,3 +301,31 @@ TUPLE: silly-tuple a b ;
[ t ] [ \ array \ nth-unsafe should-inline? ] unit-test [ t ] [ \ array \ nth-unsafe should-inline? ] unit-test
[ t ] [ \ growable \ nth-unsafe should-inline? ] unit-test [ t ] [ \ growable \ nth-unsafe should-inline? ] unit-test
[ t ] [ \ sbuf \ set-nth-unsafe should-inline? ] unit-test [ t ] [ \ sbuf \ set-nth-unsafe should-inline? ] unit-test
! Regression
: lift-throw-tail-regression
dup integer? [ "an integer" ] [
dup string? [ "a string" ] [
"error" throw
] if
] if ;
[ t ] [ \ lift-throw-tail-regression compiled? ] unit-test
[ 3 "an integer" ] [ 3 lift-throw-tail-regression ] unit-test
[ "hi" "a string" ] [ "hi" lift-throw-tail-regression ] unit-test
: lift-loop-tail-test-1 ( a quot -- )
over even? [
[ >r 3 - r> call ] keep lift-loop-tail-test-1
] [
over 0 < [
2drop
] [
[ >r 2 - r> call ] keep lift-loop-tail-test-1
] if
] if ; inline
: lift-loop-tail-test-2
10 [ ] lift-loop-tail-test-1 1 2 3 ;
[ 1 2 3 ] [ lift-loop-tail-test-2 ] unit-test

View File

@ -2,7 +2,7 @@
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: kernel namespaces optimizer.backend optimizer.def-use USING: kernel namespaces optimizer.backend optimizer.def-use
optimizer.known-words optimizer.math optimizer.control optimizer.known-words optimizer.math optimizer.control
inference.class ; optimizer.inlining inference.class ;
IN: optimizer IN: optimizer
: optimize-1 ( node -- newnode ? ) : optimize-1 ( node -- newnode ? )
@ -12,7 +12,7 @@ IN: optimizer
H{ } clone value-substitutions set H{ } clone value-substitutions set
dup compute-def-use dup compute-def-use
kill-values kill-values
! dup detect-loops dup detect-loops
dup infer-classes dup infer-classes
optimizer-changed off optimizer-changed off
optimize-nodes optimize-nodes

View File

@ -24,7 +24,7 @@ IN: optimizer.specializers
\ dispatch , \ dispatch ,
] [ ] make ; ] [ ] make ;
: specializer-methods ( word -- alist ) : specializer-methods ( quot word -- default alist )
dup [ array? ] all? [ 1array ] unless [ dup [ array? ] all? [ 1array ] unless [
[ make-specializer ] keep [ make-specializer ] keep
[ declare ] curry pick append [ declare ] curry pick append

2
extra/benchmark/benchmark.factor Normal file → Executable file
View File

@ -8,7 +8,7 @@ IN: benchmark
: run-benchmark ( vocab -- result ) : run-benchmark ( vocab -- result )
"=== Benchmark " write dup print flush "=== Benchmark " write dup print flush
dup require dup require
[ [ run ] benchmark ] [ error. f f ] recover 2array [ [ run ] benchmark ] [ error. drop f f ] recover 2array
dup . ; dup . ;
: run-benchmarks ( -- assoc ) : run-benchmarks ( -- assoc )

View File

@ -22,7 +22,7 @@ IN: benchmark.sockets
CHAR: x write1 CHAR: x write1
] with-stream ; ] with-stream ;
: socket-benchmark ( n -- ) : clients ( n -- )
dup pprint " clients: " write dup pprint " clients: " write
[ [
[ simple-server ] in-thread [ simple-server ] in-thread
@ -33,11 +33,12 @@ IN: benchmark.sockets
] time ; ] time ;
: socket-benchmarks : socket-benchmarks
10 socket-benchmark 10 clients
20 socket-benchmark 20 clients
40 socket-benchmark 40 clients
80 socket-benchmark 80 clients
160 socket-benchmark 160 clients
320 socket-benchmark ; 320 clients
640 clients ;
MAIN: socket-benchmarks MAIN: socket-benchmarks

View File

@ -3,68 +3,18 @@ USING: kernel parser io io.files io.launcher io.sockets hashtables math threads
arrays system continuations namespaces sequences splitting math.parser arrays system continuations namespaces sequences splitting math.parser
prettyprint tools.time calendar bake vars http.client prettyprint tools.time calendar bake vars http.client
combinators bootstrap.image bootstrap.image.download combinators bootstrap.image bootstrap.image.download
combinators.cleave benchmark ; combinators.cleave benchmark
classes strings quotations words parser-combinators new-slots accessors
assocs.lib smtp builder.util ;
IN: builder IN: builder
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: runtime ( quot -- time ) benchmark nip ;
: minutes>ms ( min -- ms ) 60 * 1000 * ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SYMBOL: builder-recipients
: host-name* ( -- name ) host-name "." split first ;
: tag-subject ( str -- str ) `{ "builder@" ,[ host-name* ] ": " , } concat ;
: email-string ( subject -- )
`{ "mutt" "-s" ,[ tag-subject ] %[ builder-recipients get ] }
[ ] with-process-stream drop ;
: email-file ( subject file -- )
`{
{ +stdin+ , }
{ +arguments+
{ "mutt" "-s" ,[ tag-subject ] %[ builder-recipients get ] } }
}
>hashtable run-process drop ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: target ( -- target ) `{ ,[ os ] %[ cpu "." split ] } "-" join ;
: factor-binary ( -- name )
os
{ { "macosx" [ "./Factor.app/Contents/MacOS/factor" ] }
{ "winnt" [ "./factor-nt.exe" ] }
[ drop "./factor" ] }
case ;
: git-pull ( -- desc )
{
"git"
"pull"
"--no-summary"
"git://factorcode.org/git/factor.git"
"master"
} ;
: git-clone ( -- desc ) { "git" "clone" "../factor" } ; : git-clone ( -- desc ) { "git" "clone" "../factor" } ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: datestamp ( -- string )
now `{ ,[ dup timestamp-year ]
,[ dup timestamp-month ]
,[ dup timestamp-day ]
,[ dup timestamp-hour ]
,[ timestamp-minute ] }
[ pad-00 ] map "-" join ;
VAR: stamp VAR: stamp
: enter-build-dir ( -- ) : enter-build-dir ( -- )
@ -82,47 +32,41 @@ VAR: stamp
: make-clean ( -- desc ) { "make" "clean" } ; : make-clean ( -- desc ) { "make" "clean" } ;
: make-vm ( -- ) ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
`{
{ +arguments+ { "make" ,[ target ] } } : target ( -- target ) { os [ cpu "." split ] } to-strings "-" join ;
{ +stdout+ "../compile-log" }
{ +stderr+ +stdout+ } : make-vm ( -- desc )
} <process*>
>hashtable ; { "make" target } to-strings >>arguments
"../compile-log" >>stdout
+stdout+ >>stderr
>desc ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: factor-binary ( -- name )
os
{ { "macosx" [ "./Factor.app/Contents/MacOS/factor" ] }
{ "winnt" [ "./factor-nt.exe" ] }
[ drop "./factor" ] }
case ;
: bootstrap-cmd ( -- cmd )
{ factor-binary [ "-i=" my-boot-image-name append ] "-no-user-init" }
to-strings ;
: bootstrap ( -- desc ) : bootstrap ( -- desc )
`{ <process*>
{ +arguments+ { bootstrap-cmd >>arguments
,[ factor-binary ] +closed+ >>stdin
,[ "-i=" my-boot-image-name append ] "../boot-log" >>stdout
"-no-user-init" +stdout+ >>stderr
} } 20 minutes>ms >>timeout
{ +stdout+ "../boot-log" } >desc ;
{ +stderr+ +stdout+ }
{ +timeout+ ,[ 20 minutes>ms ] }
} ;
: builder-test ( -- desc ) `{ ,[ factor-binary ] "-run=builder.test" } ; : builder-test ( -- desc ) { factor-binary "-run=builder.test" } to-strings ;
SYMBOL: build-status
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: milli-seconds>time ( n -- string )
1000 /i 60 /mod >r 60 /mod r> 3array [ pad-00 ] map ":" join ;
: eval-file ( file -- obj ) <file-reader> contents eval ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: cat ( file -- ) <file-reader> contents print ;
: run-or-bail ( desc quot -- )
[ [ try-process ] curry ]
[ [ throw ] curry ]
bi*
recover ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: (build) ( -- ) : (build) ( -- )
@ -146,24 +90,8 @@ SYMBOL: build-status
[ my-arch download-image ] [ "Image download error" print throw ] recover [ my-arch download-image ] [ "Image download error" print throw ] recover
! bootstrap [ "Bootstrap error" print "../boot-log" cat ] run-or-bail bootstrap [ "Bootstrap error" print "../boot-log" cat ] run-or-bail
! bootstrap
! <process-stream> dup dispose process-stream-process wait-for-process
! zero? not
! [ "Bootstrap error" print "../boot-log" cat "bootstrap error" throw ]
! when
[
bootstrap
<process-stream> dup dispose process-stream-process wait-for-process
zero? not
[ "bootstrap non-zero" throw ]
when
]
[ "Bootstrap error" print "../boot-log" cat "bootstrap" throw ]
recover
[ builder-test try-process ] [ builder-test try-process ]
[ "Builder test error" print throw ] [ "Builder test error" print throw ]
recover recover
@ -180,12 +108,32 @@ SYMBOL: build-status
] with-file-out ; ] with-file-out ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SYMBOL: builder-recipients
: tag-subject ( str -- str ) { "builder@" host-name* ": " , } bake to-string ;
: build ( -- ) : build ( -- )
[ (build) ] [ drop ] recover [ (build) ] [ drop ] recover
"report" "../report" email-file ; <email>
"ed@factorcode.org" >>from
builder-recipients get >>to
"report" tag-subject >>subject
"../report" file>string >>body
send ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: git-pull ( -- desc )
{
"git"
"pull"
"--no-summary"
"git://factorcode.org/git/factor.git"
"master"
} ;
: updates-available? ( -- ? ) : updates-available? ( -- ? )
git-id git-id
git-pull run-process drop git-pull run-process drop

View File

@ -41,28 +41,28 @@ IN: builder.server
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: build-server ( -- ) ! : build-server ( -- )
receive ! receive
{ ! {
{ ! {
"start" ! "start"
[ ! [
build-status get "idle" = ! build-status get "idle" =
build-status get f = ! build-status get f =
or ! or
[ ! [
[ [ build ] [ drop ] recover "idle" build-status set-global ] ! [ [ build ] [ drop ] recover "idle" build-status set-global ]
in-thread ! in-thread
] ! ]
when ! when
] ! ]
} ! }
{ ! {
{ ?from ?tag "status" } ! { ?from ?tag "status" }
[ `{ ?tag ,[ build-status get ] } ?from send ] ! [ `{ ?tag ,[ build-status get ] } ?from send ]
} ! }
} ! }
match-cond ! match-cond
build-server ; ! build-server ;

View File

@ -6,7 +6,7 @@ USING: kernel namespaces sequences assocs builder continuations
prettyprint prettyprint
tools.browser tools.browser
tools.test tools.test
bootstrap.stage2 benchmark ; bootstrap.stage2 benchmark builder.util ;
IN: builder.test IN: builder.test

View File

@ -0,0 +1,83 @@
USING: kernel words namespaces classes parser continuations
io io.files io.launcher io.sockets
math math.parser
combinators sequences splitting quotations arrays strings tools.time
parser-combinators accessors assocs.lib
combinators.cleave bake calendar new-slots ;
IN: builder.util
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: runtime ( quot -- time ) benchmark nip ;
: minutes>ms ( min -- ms ) 60 * 1000 * ;
: file>string ( file -- string ) [ stdio get contents ] with-file-in ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
DEFER: to-strings
: to-string ( obj -- str )
dup class
{
{ string [ ] }
{ quotation [ call ] }
{ word [ execute ] }
{ fixnum [ number>string ] }
{ array [ to-strings concat ] }
}
case ;
: to-strings ( seq -- str )
dup [ string? ] all?
[ ]
[ [ to-string ] map flatten ]
if ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
TUPLE: process* arguments stdin stdout stderr timeout ;
: <process*> process* construct-empty ;
: >desc ( process* -- desc )
H{ } clone
over arguments>> [ +arguments+ swap put-at ] when*
over stdin>> [ +stdin+ swap put-at ] when*
over stdout>> [ +stdout+ swap put-at ] when*
over stderr>> [ +stderr+ swap put-at ] when*
over timeout>> [ +timeout+ swap put-at ] when*
nip ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: host-name* ( -- name ) host-name "." split first ;
: datestamp ( -- string )
now `{ ,[ dup timestamp-year ]
,[ dup timestamp-month ]
,[ dup timestamp-day ]
,[ dup timestamp-hour ]
,[ timestamp-minute ] }
[ pad-00 ] map "-" join ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: milli-seconds>time ( n -- string )
1000 /i 60 /mod >r 60 /mod r> 3array [ pad-00 ] map ":" join ;
: eval-file ( file -- obj ) <file-reader> contents eval ;
: cat ( file -- ) <file-reader> contents print ;
: run-or-bail ( desc quot -- )
[ [ try-process ] curry ]
[ [ throw ] compose ]
bi*
recover ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

View File

@ -1,24 +0,0 @@
USING: kernel parser words sequences ;
IN: const
: define-const ( word value -- )
[ parsed ] curry dupd define
t "parsing" set-word-prop ;
: CONST:
CREATE scan-word dup parsing?
[ execute dup pop ] when define-const ; parsing
: define-enum ( words -- )
dup length [ define-const ] 2each ;
: ENUM:
";" parse-tokens [ create-in ] map define-enum ; parsing
: define-value ( word -- )
{ f } clone [ first ] curry define ;
: VALUE: CREATE define-value ; parsing
: set-value ( value word -- )
word-def first set-first ;

View File

@ -1,7 +1,7 @@
! Copyright (C) 2007 Daniel Ehrenberg ! Copyright (C) 2007 Daniel Ehrenberg
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: delegate sequences.private sequences assocs prettyprint.sections USING: delegate sequences.private sequences assocs prettyprint.sections
io definitions kernel ; io definitions kernel continuations ;
IN: delegate.protocols IN: delegate.protocols
PROTOCOL: sequence-protocol PROTOCOL: sequence-protocol
@ -15,7 +15,7 @@ PROTOCOL: assoc-protocol
! everything should work, just slower (with >alist) ! everything should work, just slower (with >alist)
PROTOCOL: stream-protocol PROTOCOL: stream-protocol
stream-read1 stream-read stream-read-until stream-read1 stream-read stream-read-until dispose
stream-flush stream-write1 stream-write stream-format stream-flush stream-write1 stream-write stream-format
stream-nl make-span-stream make-block-stream stream-readln stream-nl make-span-stream make-block-stream stream-readln
make-cell-stream stream-write-table ; make-cell-stream stream-write-table ;

View File

@ -1,7 +1,7 @@
! Copyright (C) 2003, 2007 Slava Pestov. ! Copyright (C) 2003, 2007 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: hashtables io kernel math namespaces math.parser assocs USING: hashtables io kernel math namespaces math.parser assocs
sequences strings splitting ascii io.utf8 assocs.lib sequences strings splitting ascii io.encodings.utf8 assocs.lib
namespaces unicode.case ; namespaces unicode.case ;
IN: http IN: http

View File

@ -1,7 +1,8 @@
! Copyright (C) 2007 Gavin Harrison ! Copyright (C) 2007 Gavin Harrison
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: kernel math sequences kernel.private namespaces arrays io io.files USING: kernel math sequences kernel.private namespaces arrays io
splitting io.binary math.functions vectors quotations sequences.private ; io.files splitting io.binary math.functions vectors quotations
combinators ;
IN: icfp.2006 IN: icfp.2006
SYMBOL: regs SYMBOL: regs
@ -9,10 +10,6 @@ SYMBOL: arrays
SYMBOL: finger SYMBOL: finger
SYMBOL: open-arrays SYMBOL: open-arrays
: call-nth ( n array -- )
>r >fixnum r> 2dup nth quotation?
[ dispatch ] [ "Not a quotation" throw ] if ; inline
: reg-val ( m -- n ) regs get nth ; : reg-val ( m -- n ) regs get nth ;
: set-reg ( val n -- ) regs get set-nth ; : set-reg ( val n -- ) regs get set-nth ;
@ -117,11 +114,21 @@ SYMBOL: open-arrays
: run-op ( -- bool ) : run-op ( -- bool )
advance advance
{ {
[ op0 ] [ op1 ] [ op2 ] [ op3 ] { 0 [ op0 ] }
[ op4 ] [ op5 ] [ op6 ] [ drop t ] { 1 [ op1 ] }
[ op8 ] [ op9 ] [ op10 ] [ op11 ] { 2 [ op2 ] }
[ op12 ] [ op13 ] { 3 [ op3 ] }
} call-nth ; { 4 [ op4 ] }
{ 5 [ op5 ] }
{ 6 [ op6 ] }
{ 7 [ drop t ] }
{ 8 [ op8 ] }
{ 9 [ op9 ] }
{ 10 [ op10 ] }
{ 11 [ op11 ] }
{ 12 [ op12 ] }
{ 13 [ op13 ] }
} case ;
: exec-loop ( bool -- ) : exec-loop ( bool -- )
[ run-op exec-loop ] unless ; [ run-op exec-loop ] unless ;

View File

@ -119,7 +119,9 @@ HOOK: process-stream* io-backend ( desc -- stream process )
TUPLE: process-stream process ; TUPLE: process-stream process ;
: <process-stream> ( desc -- stream ) : <process-stream> ( desc -- stream )
>descriptor process-stream* >descriptor
[ process-stream* ] keep
+timeout+ swap at [ over set-timeout ] when*
{ set-delegate set-process-stream-process } { set-delegate set-process-stream-process }
process-stream construct ; process-stream construct ;

View File

@ -50,15 +50,16 @@ MEMO: 'arguments' ( -- parser )
: redirect ( obj mode fd -- ) : redirect ( obj mode fd -- )
{ {
{ [ pick not ] [ 2nip F_SETFL 0 fcntl io-error ] } { [ pick not ] [ 2nip F_SETFL 0 fcntl io-error ] }
{ [ pick +closed+ eq? ] [ close 2drop ] }
{ [ pick string? ] [ (redirect) ] } { [ pick string? ] [ (redirect) ] }
} cond ; } cond ;
: ?closed dup +closed+ eq? [ drop "/dev/null" ] when ;
: setup-redirection ( -- ) : setup-redirection ( -- )
+stdin+ get read-flags 0 redirect +stdin+ get ?closed read-flags 0 redirect
+stdout+ get write-flags 1 redirect +stdout+ get ?closed write-flags 1 redirect
+stderr+ get dup +stdout+ eq? +stderr+ get dup +stdout+ eq?
[ drop 1 2 dup2 io-error ] [ write-flags 2 redirect ] if ; [ drop 1 2 dup2 io-error ] [ ?closed write-flags 2 redirect ] if ;
: spawn-process ( -- ) : spawn-process ( -- )
[ [

View File

@ -1,7 +1,7 @@
! Copyright (C) 2007, 2008 Doug Coleman, Slava Pestov. ! Copyright (C) 2007, 2008 Doug Coleman, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types arrays continuations destructors io USING: alien alien.c-types arrays continuations destructors io
io.windows io.windows.pipes libc io.nonblocking io.windows io.windows.nt.pipes libc io.nonblocking
io.streams.duplex windows.types math windows.kernel32 windows io.streams.duplex windows.types math windows.kernel32 windows
namespaces io.launcher kernel sequences windows.errors assocs namespaces io.launcher kernel sequences windows.errors assocs
splitting system threads init strings combinators io.backend ; splitting system threads init strings combinators io.backend ;
@ -87,75 +87,26 @@ TUPLE: CreateProcess-args
over set-CreateProcess-args-lpEnvironment over set-CreateProcess-args-lpEnvironment
] when ; ] when ;
: (redirect) ( path access-mode create-mode -- handle )
>r >r
normalize-pathname
r> ! access-mode
share-mode
security-attributes-inherit
r> ! create-mode
FILE_ATTRIBUTE_NORMAL ! flags and attributes
f ! template file
CreateFile dup invalid-handle? dup close-later ;
: redirect ( obj access-mode create-mode -- handle )
{
{ [ pick not ] [ 3drop f ] }
{ [ pick +closed+ eq? ] [ 3drop t ] }
{ [ pick string? ] [ (redirect) ] }
} cond ;
: ?closed or dup t eq? [ drop f ] when ;
: inherited-stdout ( args -- handle )
CreateProcess-args-stdout-pipe
[ pipe-out ] [ STD_OUTPUT_HANDLE GetStdHandle ] if* ;
: redirect-stdout ( args -- handle )
+stdout+ get GENERIC_WRITE CREATE_ALWAYS redirect
swap inherited-stdout ?closed ;
: inherited-stderr ( args -- handle )
drop STD_ERROR_HANDLE GetStdHandle ;
: redirect-stderr ( args -- handle )
+stderr+ get
dup +stdout+ eq? [
drop
CreateProcess-args-lpStartupInfo STARTUPINFO-hStdOutput
] [
GENERIC_WRITE CREATE_ALWAYS redirect
swap inherited-stderr ?closed
] if ;
: inherited-stdin ( args -- handle )
CreateProcess-args-stdin-pipe
[ pipe-in ] [ STD_INPUT_HANDLE GetStdHandle ] if* ;
: redirect-stdin ( args -- handle )
+stdin+ get GENERIC_READ OPEN_EXISTING redirect
swap inherited-stdin ?closed ;
: fill-startup-info : fill-startup-info
dup CreateProcess-args-lpStartupInfo dup CreateProcess-args-lpStartupInfo
STARTF_USESTDHANDLES over set-STARTUPINFO-dwFlags STARTF_USESTDHANDLES swap set-STARTUPINFO-dwFlags ;
over redirect-stdout over set-STARTUPINFO-hStdOutput HOOK: fill-redirection io-backend ( args -- args )
over redirect-stderr over set-STARTUPINFO-hStdError
over redirect-stdin over set-STARTUPINFO-hStdInput
drop ; M: windows-ce-io fill-redirection ;
: make-CreateProcess-args ( -- args ) : make-CreateProcess-args ( -- args )
default-CreateProcess-args default-CreateProcess-args
wince? [ fill-lpApplicationName ] [ fill-lpCommandLine ] if wince? [ fill-lpApplicationName ] [ fill-lpCommandLine ] if
fill-dwCreateFlags fill-dwCreateFlags
fill-lpEnvironment ; fill-lpEnvironment
fill-startup-info ;
M: windows-io run-process* ( desc -- handle ) M: windows-io run-process* ( desc -- handle )
[ [
[ [
make-CreateProcess-args fill-startup-info make-CreateProcess-args
fill-redirection
dup call-CreateProcess dup call-CreateProcess
CreateProcess-args-lpProcessInformation <process> CreateProcess-args-lpProcessInformation <process>
] with-descriptor ] with-descriptor

View File

@ -3,13 +3,63 @@
USING: alien alien.c-types arrays continuations destructors io USING: alien alien.c-types arrays continuations destructors io
io.windows libc io.nonblocking io.streams.duplex windows.types io.windows libc io.nonblocking io.streams.duplex windows.types
math windows.kernel32 windows namespaces io.launcher kernel math windows.kernel32 windows namespaces io.launcher kernel
sequences windows.errors assocs splitting system sequences windows.errors assocs splitting system strings
io.windows.launcher io.windows.pipes ; io.windows.launcher io.windows.nt.pipes io.backend
combinators ;
IN: io.windows.nt.launcher IN: io.windows.nt.launcher
! The below code is based on the example given in ! The below code is based on the example given in
! http://msdn2.microsoft.com/en-us/library/ms682499.aspx ! http://msdn2.microsoft.com/en-us/library/ms682499.aspx
: (redirect) ( path access-mode create-mode -- handle )
>r >r
normalize-pathname
r> ! access-mode
share-mode
security-attributes-inherit
r> ! create-mode
FILE_ATTRIBUTE_NORMAL ! flags and attributes
f ! template file
CreateFile dup invalid-handle? dup close-later ;
: redirect ( obj access-mode create-mode -- handle )
{
{ [ pick not ] [ 3drop f ] }
{ [ pick +closed+ eq? ] [ drop nip null-pipe ] }
{ [ pick string? ] [ (redirect) ] }
} cond ;
: ?closed or dup t eq? [ drop f ] when ;
: inherited-stdout ( args -- handle )
CreateProcess-args-stdout-pipe
[ pipe-out ] [ STD_OUTPUT_HANDLE GetStdHandle ] if* ;
: redirect-stdout ( args -- handle )
+stdout+ get GENERIC_WRITE CREATE_ALWAYS redirect
swap inherited-stdout ?closed ;
: inherited-stderr ( args -- handle )
drop STD_ERROR_HANDLE GetStdHandle ;
: redirect-stderr ( args -- handle )
+stderr+ get
dup +stdout+ eq? [
drop
CreateProcess-args-lpStartupInfo STARTUPINFO-hStdOutput
] [
GENERIC_WRITE CREATE_ALWAYS redirect
swap inherited-stderr ?closed
] if ;
: inherited-stdin ( args -- handle )
CreateProcess-args-stdin-pipe
[ pipe-in ] [ STD_INPUT_HANDLE GetStdHandle ] if* ;
: redirect-stdin ( args -- handle )
+stdin+ get GENERIC_READ OPEN_EXISTING redirect
swap inherited-stdin ?closed ;
: set-inherit ( handle ? -- ) : set-inherit ( handle ? -- )
>r HANDLE_FLAG_INHERIT r> >BOOLEAN SetHandleInformation win32-error=0/f ; >r HANDLE_FLAG_INHERIT r> >BOOLEAN SetHandleInformation win32-error=0/f ;
@ -30,14 +80,22 @@ IN: io.windows.nt.launcher
dup pipe-out f set-inherit dup pipe-out f set-inherit
over set-CreateProcess-args-stdin-pipe ; over set-CreateProcess-args-stdin-pipe ;
M: windows-io process-stream* M: windows-nt-io fill-redirection
dup CreateProcess-args-lpStartupInfo
over redirect-stdout over set-STARTUPINFO-hStdOutput
over redirect-stderr over set-STARTUPINFO-hStdError
over redirect-stdin over set-STARTUPINFO-hStdInput
drop ;
M: windows-nt-io process-stream*
[ [
[ [
make-CreateProcess-args make-CreateProcess-args
fill-stdout-pipe fill-stdout-pipe
fill-stdin-pipe fill-stdin-pipe
fill-startup-info
fill-redirection
dup call-CreateProcess dup call-CreateProcess

View File

@ -1,9 +1,10 @@
! Copyright (C) 2007 Doug Coleman, Slava Pestov. ! Copyright (C) 2007, 2008 Doug Coleman, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types arrays destructors io io.windows libc USING: alien alien.c-types arrays destructors io io.windows libc
windows.types math windows.kernel32 windows namespaces kernel windows.types math windows.kernel32 windows namespaces kernel
sequences windows.errors assocs math.parser system random ; sequences windows.errors assocs math.parser system random
IN: io.windows.pipes combinators ;
IN: io.windows.nt.pipes
! This code is based on ! This code is based on
! http://twistedmatrix.com/trac/browser/trunk/twisted/internet/iocpreactor/process.py ! http://twistedmatrix.com/trac/browser/trunk/twisted/internet/iocpreactor/process.py
@ -65,3 +66,20 @@ TUPLE: pipe in out ;
: <unique-outgoing-pipe> ( -- pipe ) : <unique-outgoing-pipe> ( -- pipe )
unique-pipe-name <outgoing-pipe> ; unique-pipe-name <outgoing-pipe> ;
! /dev/null simulation
: null-input ( -- pipe )
<unique-outgoing-pipe>
dup pipe-out CloseHandle drop
pipe-in ;
: null-output ( -- pipe )
<unique-incoming-pipe>
dup pipe-in CloseHandle drop
pipe-out ;
: null-pipe ( mode -- pipe )
{
{ [ dup GENERIC_READ = ] [ drop null-input ] }
{ [ dup GENERIC_WRITE = ] [ drop null-output ] }
} cond ;

2
extra/math/analysis/analysis.factor Normal file → Executable file
View File

@ -1,5 +1,5 @@
USING: kernel math math.constants math.functions math.intervals USING: kernel math math.constants math.functions math.intervals
math.vectors namespaces sequences ; math.vectors namespaces sequences combinators.cleave ;
IN: math.analysis IN: math.analysis
<PRIVATE <PRIVATE

View File

@ -7,8 +7,11 @@ IN: multiline
lexer get dup next-line lexer-line-text ; lexer get dup next-line lexer-line-text ;
: (parse-here) ( -- ) : (parse-here) ( -- )
next-line-text dup ";" = next-line-text [
[ drop lexer get next-line ] [ % "\n" % (parse-here) ] if ; dup ";" =
[ drop lexer get next-line ]
[ % "\n" % (parse-here) ] if
] [ ";" unexpected-eof ] if* ;
: parse-here ( -- str ) : parse-here ( -- str )
[ (parse-here) ] "" make 1 head* [ (parse-here) ] "" make 1 head*
@ -19,11 +22,13 @@ IN: multiline
parse-here 1quotation define-inline ; parsing parse-here 1quotation define-inline ; parsing
: (parse-multiline-string) ( start-index end-text -- end-index ) : (parse-multiline-string) ( start-index end-text -- end-index )
lexer get lexer-line-text 2dup start lexer get lexer-line-text [
[ rot dupd >r >r swap subseq % r> r> length + ] [ 2dup start
rot tail % "\n" % 0 [ rot dupd >r >r swap subseq % r> r> length + ] [
lexer get next-line swap (parse-multiline-string) rot tail % "\n" % 0
] if* ; lexer get next-line swap (parse-multiline-string)
] if*
] [ nip unexpected-eof ] if* ;
: parse-multiline-string ( end-text -- str ) : parse-multiline-string ( end-text -- str )
[ [

View File

@ -95,14 +95,18 @@ M: #dispatch node>quot
node-children swap [ dataflow>quot ] curry map , node-children swap [ dataflow>quot ] curry map ,
\ dispatch , ; \ dispatch , ;
M: #return node>quot
dup node-param unparse "#return " swap append comment, ;
M: #>r node>quot nip node-in-d length \ >r <array> % ; M: #>r node>quot nip node-in-d length \ >r <array> % ;
M: #r> node>quot nip node-out-d length \ r> <array> % ; M: #r> node>quot nip node-out-d length \ r> <array> % ;
M: object node>quot dup class word-name comment, ; M: object node>quot
[
dup class word-name %
" " %
dup node-param unparse %
" " %
dup effect-str %
] "" make comment, ;
: (dataflow>quot) ( ? node -- ) : (dataflow>quot) ( ? node -- )
dup [ dup [

View File

@ -29,6 +29,7 @@
USING: combinators kernel prettyprint io io.timeouts io.server USING: combinators kernel prettyprint io io.timeouts io.server
sequences namespaces io.sockets continuations ; sequences namespaces io.sockets continuations ;
IN: smtp.server
SYMBOL: data-mode SYMBOL: data-mode
@ -55,7 +56,7 @@ SYMBOL: data-mode
data-mode off data-mode off
"220 OK\r\n" write flush t "220 OK\r\n" write flush t
] } ] }
{ [ data-mode get ] [ t ] } { [ data-mode get ] [ global [ print ] bind t ] }
{ [ t ] [ { [ t ] [
"500 ERROR\r\n" write flush t "500 ERROR\r\n" write flush t
] } ] }
@ -68,5 +69,6 @@ SYMBOL: data-mode
60000 stdio get set-timeout 60000 stdio get set-timeout
"220 hello\r\n" write flush "220 hello\r\n" write flush
process process
global [ flush ] bind
] with-stream ] with-stream
] with-disposal ; ] with-disposal ;

View File

@ -139,7 +139,7 @@ LOG: smtp-response DEBUG
: prepare-message ( body headers -- body' ) : prepare-message ( body headers -- body' )
[ [
prepare-headers prepare-headers
" " , "" ,
dup string? [ string-lines ] when % dup string? [ string-lines ] when %
] { } make ; ] { } make ;
@ -169,3 +169,15 @@ LOG: smtp-response DEBUG
! : cram-md5-auth ( key login -- ) ! : cram-md5-auth ( key login -- )
! "AUTH CRAM-MD5\r\n" get-ok ! "AUTH CRAM-MD5\r\n" get-ok
! (cram-md5-auth) "\r\n" append get-ok ; ! (cram-md5-auth) "\r\n" append get-ok ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
USE: new-slots
TUPLE: email from to subject body ;
: <email> ( -- email ) email construct-empty ;
: send ( email -- )
{ email-body email-subject email-to email-from } get-slots
send-simple-message ;

View File

@ -132,7 +132,7 @@ MEMO: all-vocabs-seq ( -- seq )
require-all ; require-all ;
: load-everything ( -- ) : load-everything ( -- )
try-everything drop ; try-everything load-failures. ;
: unrooted-child-vocabs ( prefix -- seq ) : unrooted-child-vocabs ( prefix -- seq )
dup empty? [ CHAR: . add ] unless dup empty? [ CHAR: . add ] unless

View File

@ -1,11 +1,11 @@
! Copyright (C) 2005, 2007 Eduardo Cavazos and Slava Pestov ! Copyright (C) 2005, 2007 Eduardo Cavazos and Slava Pestov
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types arrays ui ui.gadgets ui.gestures ui.backend USING: alien alien.c-types arrays ui ui.gadgets ui.gestures
ui.clipboards ui.gadgets.worlds assocs kernel math namespaces ui.backend ui.clipboards ui.gadgets.worlds assocs kernel math
opengl sequences strings x11.xlib x11.events x11.xim x11.glx namespaces opengl sequences strings x11.xlib x11.events x11.xim
x11.clipboard x11.constants x11.windows io.utf8 combinators x11.glx x11.clipboard x11.constants x11.windows
debugger system command-line ui.render math.vectors tuples io.encodings.utf8 combinators debugger system command-line
opengl.gl threads ; ui.render math.vectors tuples opengl.gl threads ;
IN: ui.x11 IN: ui.x11
TUPLE: x11-ui-backend ; TUPLE: x11-ui-backend ;

View File

@ -1,7 +1,7 @@
USING: unicode.categories kernel math combinators splitting USING: unicode.categories kernel math combinators splitting
sequences math.parser io.files io assocs arrays namespaces sequences math.parser io.files io assocs arrays namespaces
combinators.lib assocs.lib math.ranges unicode.normalize combinators.lib assocs.lib math.ranges unicode.normalize
unicode.syntax unicode.data compiler.units alien.syntax const ; unicode.syntax unicode.data compiler.units alien.syntax ;
IN: unicode.breaks IN: unicode.breaks
C-ENUM: Any L V T Extend Control CR LF graphemes ; C-ENUM: Any L V T Extend Control CR LF graphemes ;

View File

@ -1,8 +1,16 @@
USING: assocs math kernel sequences io.files hashtables USING: assocs math kernel sequences io.files hashtables
quotations splitting arrays math.parser combinators.lib hash2 quotations splitting arrays math.parser combinators.lib hash2
byte-arrays words namespaces words compiler.units const ; byte-arrays words namespaces words compiler.units parser ;
IN: unicode.data IN: unicode.data
<<
: VALUE:
CREATE dup reset-generic { f } clone [ first ] curry define ; parsing
: set-value ( value word -- )
word-def first set-first ;
>>
! Convenience functions ! Convenience functions
: 1+* ( n/f _ -- n+1 ) : 1+* ( n/f _ -- n+1 )
drop [ 1+ ] [ 0 ] if* ; drop [ 1+ ] [ 0 ] if* ;

2
extra/x11/clipboard/clipboard.factor Normal file → Executable file
View File

@ -1,7 +1,7 @@
! Copyright (C) 2006, 2007 Slava Pestov ! Copyright (C) 2006, 2007 Slava Pestov
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types alien.syntax arrays kernel math USING: alien alien.c-types alien.syntax arrays kernel math
namespaces sequences io.utf8 x11.xlib x11.constants ; namespaces sequences io.encodings.utf8 x11.xlib x11.constants ;
IN: x11.clipboard IN: x11.clipboard
! This code was based on by McCLIM's Backends/CLX/port.lisp ! This code was based on by McCLIM's Backends/CLX/port.lisp