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

db4
Doug Coleman 2008-08-15 15:16:54 -05:00
commit e846d0d98e
100 changed files with 3454 additions and 529 deletions

View File

@ -2,6 +2,12 @@ IN: alien.c-types.tests
USING: alien alien.syntax alien.c-types kernel tools.test USING: alien alien.syntax alien.c-types kernel tools.test
sequences system libc alien.strings io.encodings.utf8 ; sequences system libc alien.strings io.encodings.utf8 ;
\ expand-constants must-infer
: xyz 123 ;
[ { "blah" 123 } ] [ { "blah" xyz } expand-constants ] unit-test
: foo ( -- n ) "fdafd" f dlsym [ 123 ] unless* ; : foo ( -- n ) "fdafd" f dlsym [ 123 ] unless* ;
[ 123 ] [ foo ] unit-test [ 123 ] [ foo ] unit-test

View File

@ -4,7 +4,7 @@ USING: byte-arrays arrays assocs kernel kernel.private libc math
namespaces parser sequences strings words assocs splitting namespaces parser sequences strings words assocs splitting
math.parser cpu.architecture alien alien.accessors quotations math.parser cpu.architecture alien alien.accessors quotations
layouts system compiler.units io.files io.encodings.binary layouts system compiler.units io.files io.encodings.binary
accessors combinators effects ; accessors combinators effects continuations ;
IN: alien.c-types IN: alien.c-types
DEFER: <int> DEFER: <int>
@ -239,15 +239,20 @@ M: long-long-type box-return ( type -- )
} 2cleave ; } 2cleave ;
: expand-constants ( c-type -- c-type' ) : expand-constants ( c-type -- c-type' )
#! We use def>> call instead of execute to get around
#! staging violations
dup array? [ dup array? [
unclip >r [ dup word? [ def>> call ] when ] map r> prefix unclip >r [
dup word? [
def>> { } swap with-datastack first
] when
] map r> prefix
] when ; ] when ;
: malloc-file-contents ( path -- alien len ) : malloc-file-contents ( path -- alien len )
binary file-contents dup malloc-byte-array swap length ; binary file-contents dup malloc-byte-array swap length ;
: if-void ( type true false -- )
pick "void" = [ drop nip call ] [ nip call ] if ; inline
[ [
<c-type> <c-type>
[ alien-cell ] >>getter [ alien-cell ] >>getter

View File

@ -88,6 +88,14 @@ M:: disjoint-set equate ( a b disjoint-set -- )
disjoint-set link-sets disjoint-set link-sets
] if ; ] if ;
: equate-all-with ( seq a disjoint-set -- )
'[ , , equate ] each ;
: equate-all ( seq disjoint-set -- )
over dup empty? [ 2drop ] [
[ unclip-slice ] dip equate-all-with
] if ;
M: disjoint-set clone M: disjoint-set clone
[ parents>> ] [ ranks>> ] [ counts>> ] tri [ clone ] tri@ [ parents>> ] [ ranks>> ] [ counts>> ] tri [ clone ] tri@
disjoint-set boa ; disjoint-set boa ;

View File

@ -3,9 +3,9 @@
USING: accessors sequences parser kernel help help.markup USING: accessors sequences parser kernel help help.markup
help.topics words strings classes tools.vocabs namespaces io help.topics words strings classes tools.vocabs namespaces io
io.streams.string prettyprint definitions arrays vectors io.streams.string prettyprint definitions arrays vectors
combinators splitting debugger hashtables sorting effects vocabs combinators combinators.short-circuit splitting debugger
vocabs.loader assocs editors continuations classes.predicate hashtables sorting effects vocabs vocabs.loader assocs editors
macros math sets eval ; continuations classes.predicate macros math sets eval ;
IN: help.lint IN: help.lint
: check-example ( element -- ) : check-example ( element -- )
@ -43,15 +43,15 @@ IN: help.lint
: check-values ( word element -- ) : check-values ( word element -- )
{ {
{ [ over "declared-effect" word-prop ] [ 2drop ] } [ drop "declared-effect" word-prop not ]
{ [ dup contains-funky-elements? not ] [ 2drop ] } [ nip contains-funky-elements? ]
{ [ over macro? not ] [ 2drop ] } [ drop macro? ]
[ [
[ effect-values >array ] [ effect-values >array ]
[ extract-values >array ] [ extract-values >array ]
bi* assert= bi* =
] ]
} cond ; } 2|| [ "$values don't match stack effect" throw ] unless ;
: check-see-also ( word element -- ) : check-see-also ( word element -- )
nip \ $see-also swap elements [ nip \ $see-also swap elements [

View File

@ -1,21 +1,27 @@
USING: help.syntax help.markup ; USING: help.syntax help.markup arrays sequences ;
IN: math.ranges IN: math.ranges
ARTICLE: "ranges" "Ranges" ARTICLE: "ranges" "Ranges"
"A " { $emphasis "range" } " is a virtual sequence with real number elements "
"ranging from " { $emphasis "a" } " to " { $emphasis "b" } " by " { $emphasis "step" } "."
$nl
"The class of ranges:"
{ $subsection range }
"Creating ranges with integer end-points. The standard mathematical convention is used, where " { $snippet "(" } " or " { $snippet ")" } " denotes that the end-point itself " { $emphasis "is not" } " part of the range; " { $snippet "[" } " or " { $snippet "]" } " denotes that the end-point " { $emphasis "is" } " part of the range:"
{ $subsection [a,b] }
{ $subsection (a,b] }
{ $subsection [a,b) }
{ $subsection (a,b) }
{ $subsection [0,b] }
{ $subsection [1,b] }
{ $subsection [0,b) }
"Creating general ranges:"
{ $subsection <range> }
"Ranges are most frequently used with sequence combinators as a means of iterating over integers. For example,"
{ $code
"3 10 [a,b] [ sqrt ] map"
}
"A range can be converted into a concrete sequence using a word such as " { $link >array } ". In most cases this is unnecessary since ranges implement the sequence protocol already. It is necessary if a mutable sequence is needed, for use with words such as " { $link set-nth } " or " { $link change-each } "." ;
"A " { $emphasis "range" } " is a virtual sequence with real elements " ABOUT: "ranges"
"ranging from " { $emphasis "a" } " to " { $emphasis "b" } " by " { $emphasis "step" } "."
$nl
"Creating ranges:"
{ $subsection <range> }
{ $subsection [a,b] }
{ $subsection (a,b] }
{ $subsection [a,b) }
{ $subsection (a,b) }
{ $subsection [0,b] }
{ $subsection [1,b] }
{ $subsection [0,b) } ;

View File

@ -171,10 +171,11 @@ M: block section-fits? ( section -- ? )
line-limit? [ drop t ] [ call-next-method ] if ; line-limit? [ drop t ] [ call-next-method ] if ;
: pprint-sections ( block advancer -- ) : pprint-sections ( block advancer -- )
swap sections>> [ line-break? not ] filter [
unclip pprint-section [ sections>> [ line-break? not ] filter
dup rot call pprint-section unclip-slice pprint-section
] with each ; inline ] dip
[ [ pprint-section ] bi ] curry each ; inline
M: block short-section ( block -- ) M: block short-section ( block -- )
[ advance ] pprint-sections ; [ advance ] pprint-sections ;

View File

@ -48,8 +48,8 @@ DEFER: (del-page)
: del-page ( name tabbed -- ) : del-page ( name tabbed -- )
[ names>> index ] 2keep (del-page) ; [ names>> index ] 2keep (del-page) ;
: <tabbed> ( assoc -- tabbed ) : new-tabbed ( assoc class -- tabbed )
tabbed new-frame new-frame
0 <model> >>model 0 <model> >>model
<pile> 1 >>fill >>toggler <pile> 1 >>fill >>toggler
dup toggler>> @left grid-add dup toggler>> @left grid-add
@ -59,3 +59,4 @@ DEFER: (del-page)
bi bi
dup redo-toggler ; dup redo-toggler ;
: <tabbed> ( assoc -- tabbed ) tabbed new-tabbed ;

View File

@ -7,13 +7,16 @@ IN: unix
: MAXPATHLEN 1024 ; inline : MAXPATHLEN 1024 ; inline
: O_RDONLY HEX: 0000 ; inline : O_RDONLY HEX: 0000 ; inline
: O_WRONLY HEX: 0001 ; inline : O_WRONLY HEX: 0001 ; inline
: O_RDWR HEX: 0002 ; inline : O_RDWR HEX: 0002 ; inline
: O_APPEND HEX: 0008 ; inline : O_NONBLOCK HEX: 0004 ; inline
: O_CREAT HEX: 0200 ; inline : O_APPEND HEX: 0008 ; inline
: O_TRUNC HEX: 0400 ; inline : O_CREAT HEX: 0200 ; inline
: O_EXCL HEX: 0800 ; inline : O_TRUNC HEX: 0400 ; inline
: O_EXCL HEX: 0800 ; inline
: O_NOCTTY HEX: 20000 ; inline
: O_NDELAY O_NONBLOCK ; inline
: SOL_SOCKET HEX: ffff ; inline : SOL_SOCKET HEX: ffff ; inline
: SO_REUSEADDR HEX: 4 ; inline : SO_REUSEADDR HEX: 4 ; inline
@ -24,7 +27,6 @@ IN: unix
: F_SETFD 2 ; inline : F_SETFD 2 ; inline
: F_SETFL 4 ; inline : F_SETFL 4 ; inline
: FD_CLOEXEC 1 ; inline : FD_CLOEXEC 1 ; inline
: O_NONBLOCK 4 ; inline
C-STRUCT: sockaddr-in C-STRUCT: sockaddr-in
{ "uchar" "len" } { "uchar" "len" }

View File

@ -7,13 +7,16 @@ USING: alien.syntax ;
: MAXPATHLEN 1024 ; inline : MAXPATHLEN 1024 ; inline
: O_RDONLY HEX: 0000 ; inline : O_RDONLY HEX: 0000 ; inline
: O_WRONLY HEX: 0001 ; inline : O_WRONLY HEX: 0001 ; inline
: O_RDWR HEX: 0002 ; inline : O_RDWR HEX: 0002 ; inline
: O_CREAT HEX: 0040 ; inline : O_CREAT HEX: 0040 ; inline
: O_EXCL HEX: 0080 ; inline : O_EXCL HEX: 0080 ; inline
: O_TRUNC HEX: 0200 ; inline : O_NOCTTY HEX: 0100 ; inline
: O_APPEND HEX: 0400 ; inline : O_TRUNC HEX: 0200 ; inline
: O_APPEND HEX: 0400 ; inline
: O_NONBLOCK HEX: 0800 ; inline
: O_NDELAY O_NONBLOCK ; inline
: SOL_SOCKET 1 ; inline : SOL_SOCKET 1 ; inline
@ -28,7 +31,6 @@ USING: alien.syntax ;
: FD_CLOEXEC 1 ; inline : FD_CLOEXEC 1 ; inline
: F_SETFL 4 ; inline : F_SETFL 4 ; inline
: O_NONBLOCK HEX: 800 ; inline
C-STRUCT: addrinfo C-STRUCT: addrinfo
{ "int" "flags" } { "int" "flags" }

View File

@ -192,4 +192,3 @@ FUNCTION: ssize_t write ( int fd, void* buf, size_t nbytes ) ;
{ [ os bsd? ] [ "unix.bsd" require ] } { [ os bsd? ] [ "unix.bsd" require ] }
{ [ os solaris? ] [ "unix.solaris" require ] } { [ os solaris? ] [ "unix.solaris" require ] }
} cond } cond

View File

@ -1,7 +1,7 @@
! Copyright (C) 2006, 2008 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.
USING: kernel math namespaces sequences strings words assocs USING: kernel math math.parser namespaces sequences strings
combinators accessors arrays ; words assocs combinators accessors arrays ;
IN: effects IN: effects
TUPLE: effect in out terminated? ; TUPLE: effect in out terminated? ;
@ -25,10 +25,11 @@ TUPLE: effect in out terminated? ;
GENERIC: effect>string ( obj -- str ) GENERIC: effect>string ( obj -- str )
M: string effect>string ; M: string effect>string ;
M: word effect>string name>> ; M: word effect>string name>> ;
M: integer effect>string drop "object" ; M: integer effect>string number>string ;
M: pair effect>string first2 [ effect>string ] bi@ ": " swap 3append ; M: pair effect>string first2 [ effect>string ] bi@ ": " swap 3append ;
: stack-picture ( seq -- string ) : stack-picture ( seq -- string )
dup integer? [ "object" <repetition> ] when
[ [ effect>string % CHAR: \s , ] each ] "" make ; [ [ effect>string % CHAR: \s , ] each ] "" make ;
M: effect effect>string ( effect -- string ) M: effect effect>string ( effect -- string )

View File

@ -31,12 +31,12 @@ HELP: 24-able ( -- vector )
"just using the provided commands and the 4 numbers. The Following are the " "just using the provided commands and the 4 numbers. The Following are the "
"provided commands: " "provided commands: "
{ $link + } ", " { $link - } ", " { $link * } ", " { $link + } ", " { $link - } ", " { $link * } ", "
{ $link / } ", and " { $link swap } "." { $link / } ", " { $link swap } ", and " { $link rot } "."
} }
{ $examples { $examples
{ $example { $example
"USE: 24-game" "USE: 24-game"
"24-able vector-24-able?" "24-able vector-24-able? ."
"t" "t"
} }
{ $notes { $link 24-able? } " is used in " { $link 24-able } "." } { $notes { $link 24-able? } " is used in " { $link 24-able } "." }

View File

@ -60,3 +60,4 @@ DEFER: check-status
: 24-able ( -- vector ) build-quad dup 24-able? [ drop build-quad ] unless ; : 24-able ( -- vector ) build-quad dup 24-able? [ drop build-quad ] unless ;
: set-commands ( -- ) { + - * / rot swap q } commands set ; : set-commands ( -- ) { + - * / rot swap q } commands set ;
: play-game ( -- ) set-commands 24-able repeat ; : play-game ( -- ) set-commands 24-able repeat ;
MAIN: play-game

View File

@ -1,34 +1,65 @@
USING: help.markup help.syntax ; USING: help.markup help.syntax ;
IN: extra.animations IN: animations
HELP: animate ( quot duration -- ) HELP: animate ( quot duration -- )
{ $values { $values
{ "quot" "a quot which uses " { $link progress } } { "quot" "a quot which uses " { $link progress } }
{ "duration" "a duration of time" } { "duration" "a duration of time" }
} }
{ $description { $link animate } " calls " { $link reset-progress } " , then continously calls the given quot until the duration of time has elapsed. The quot should use " { $link progress } " at least once." } { $description
{ $example { $link animate } " calls " { $link reset-progress }
"USING: extra.animations calendar threads prettyprint ;" " , then continously calls the given quot until the"
"[ 1 sleep progress unparse write \" ms elapsed\" print ] 1/20 seconds animate ;" " duration of time has elapsed. The quot should use "
"46 ms elapsed\n17 ms elapsed" { $link progress } " at least once."
}
{ $examples
{ $unchecked-example
"USING: animations calendar threads prettyprint ;"
"[ 1 sleep progress unparse write \" ms elapsed\" print ] "
"1/20 seconds animate ;"
"46 ms elapsed\n17 ms elapsed"
}
{ $notes "The amount of time elapsed between these iterations will very." }
} ; } ;
HELP: reset-progress ( -- ) HELP: reset-progress ( -- )
{ $description "Initiates the timer. Call this before using a loop which makes use of " { $link progress } "." } ; { $description
"Initiates the timer. Call this before using "
"a loop which makes use of " { $link progress } "."
} ;
HELP: progress ( -- time ) HELP: progress ( -- time )
{ $values { "time" "an integer" } } { $values { "time" "an integer" } }
{ $description "Gives the time elapsed since the last time this word was called, in milliseconds." } { $description
{ $example "Gives the time elapsed since the last time"
"USING: extra.animations threads prettyprint ;" " this word was called, in milliseconds."
"reset-progress 3 [ 1 sleep progress unparse write \"ms elapsed\" print ] times ;" }
"31 ms elapsed\n18 ms elapsed\n16 ms elapsed" { $examples
{ $unchecked-example
"USING: animations threads prettyprint ;"
"reset-progress 3 "
"[ 1 sleep progress unparse write \"ms elapsed\" print ] "
"times ;"
"31 ms elapsed\n18 ms elapsed\n16 ms elapsed"
}
{ $notes "The amount of time elapsed between these iterations will very." }
} ; } ;
ARTICLE: "extra.animations" "Animations" ARTICLE: "animations" "Animations"
"Provides a lightweight framework for properly simulating continuous functions of real time. This framework helps one create animations that use rates which do not change across platforms. The speed of the computer should correlate with the smoothness of the animation, not the speed of the animation!" "Provides a lightweight framework for properly simulating continuous"
" functions of real time. This framework helps one create animations "
"that use rates which do not change across platforms. The speed of the "
"computer should correlate with the smoothness of the animation, not "
"the speed of the animation!"
{ $subsection animate } { $subsection animate }
{ $subsection reset-progress } { $subsection reset-progress }
{ $subsection progress } { $subsection progress }
{ $link progress } " specifically provides the length of time since " { $link reset-progress } " was called, and also calls " { $link reset-progress } " as its last action. This can be directly used when one's quote runs for a specific number of iterations, instead of a length of time. If the animation is like most, and is expected to run for a specific length of time, " { $link animate } " should be used." ; ! A little talk about when to use progress and when to use animate
ABOUT: "extra.animations" { $link progress } " specifically provides the length of time since "
{ $link reset-progress } " was called, and also calls "
{ $link reset-progress } " as its last action. This can be directly "
"used when one's quote runs for a specific number of iterations, instead "
"of a length of time. If the animation is like most, and is expected to "
"run for a specific length of time, " { $link animate } " should be used." ;
ABOUT: "animations"

View File

@ -2,11 +2,16 @@
USING: kernel shuffle system locals USING: kernel shuffle system locals
prettyprint math io namespaces threads calendar ; prettyprint math io namespaces threads calendar ;
IN: extra.animations IN: animations
SYMBOL: last-loop SYMBOL: last-loop
SYMBOL: sleep-period
: reset-progress ( -- ) millis last-loop set ; : reset-progress ( -- ) millis last-loop set ;
! : my-progress ( -- progress ) millis
: progress ( -- progress ) millis last-loop get - reset-progress ; : progress ( -- progress ) millis last-loop get - reset-progress ;
: progress-peek ( -- progress ) millis last-loop get - ;
: set-end ( duration -- end-time ) dt>milliseconds millis + ; : set-end ( duration -- end-time ) dt>milliseconds millis + ;
: loop ( quot end -- ) dup millis > [ [ dup call ] dip loop ] [ 2drop ] if ; : loop ( quot end -- ) dup millis > [ [ dup call ] dip loop ] [ 2drop ] if ; inline
: animate ( quot duration -- ) reset-progress set-end loop ; : animate ( quot duration -- ) reset-progress set-end loop ; inline
: sample ( revs quot -- avg ) reset-progress dupd times progress swap / ; inline

View File

@ -1 +1 @@
Reginald Keith Ford II Reginald Ford

View File

@ -66,3 +66,5 @@ MACRO: amb-execute ( seq -- quot )
tri* if tri* if
] with-scope ; inline ] with-scope ; inline
: cut-amb ( -- )
f failure set ;

View File

@ -140,6 +140,12 @@ TUPLE: link attributes clickable ;
: href-contains? ( str tag -- ? ) : href-contains? ( str tag -- ? )
attributes>> "href" swap at* [ subseq? ] [ 2drop f ] if ; attributes>> "href" swap at* [ subseq? ] [ 2drop f ] if ;
: find-hrefs ( vector -- vector' )
find-links
[ [
[ name>> "a" = ]
[ attributes>> "href" swap key? ] bi and ] filter
] map sift [ [ attributes>> "href" swap at ] map ] map concat ;
: find-forms ( vector -- vector' ) : find-forms ( vector -- vector' )
"form" over find-opening-tags-by-name "form" over find-opening-tags-by-name

View File

@ -1,4 +1,4 @@
USING: arrays html.parser.utils hashtables io kernel USING: accessors arrays html.parser.utils hashtables io kernel
namespaces prettyprint quotations namespaces prettyprint quotations
sequences splitting state-parser strings unicode.categories unicode.case ; sequences splitting state-parser strings unicode.categories unicode.case ;
IN: html.parser IN: html.parser
@ -23,8 +23,10 @@ SYMBOL: tagstack
] if ; ] if ;
: <tag> ( name attributes closing? -- tag ) : <tag> ( name attributes closing? -- tag )
{ set-tag-name set-tag-attributes set-tag-closing? } tag new
tag construct ; swap >>closing?
swap >>attributes
swap >>name ;
: make-tag ( str attribs -- tag ) : make-tag ( str attribs -- tag )
>r [ closing-tag? ] keep "/" trim1 r> rot <tag> ; >r [ closing-tag? ] keep "/" trim1 r> rot <tag> ;
@ -75,7 +77,7 @@ SYMBOL: tagstack
read-quote read-quote
] [ ] [
read-token read-token
] if ; ] if [ blank? ] trim ;
: read-comment ( -- ) : read-comment ( -- )
"-->" take-string* make-comment-tag push-tag ; "-->" take-string* make-comment-tag push-tag ;

View File

@ -83,13 +83,6 @@ M: src-printer print-closing-named-tag ( tag -- )
SYMBOL: tab-width SYMBOL: tab-width
SYMBOL: #indentations SYMBOL: #indentations
: html-pp ( vector -- )
[
0 #indentations set
2 tab-width set
] with-scope ;
: print-tabs ( -- ) : print-tabs ( -- )
tab-width get #indentations get * CHAR: \s <repetition> write ; tab-width get #indentations get * CHAR: \s <repetition> write ;
@ -125,3 +118,6 @@ M: printer print-tag ( tag -- )
! H{ { table-gap { 10 10 } } } [ ! H{ { table-gap { 10 10 } } } [
! [ [ [ [ . ] with-cell ] each ] with-row ] each ! [ [ [ [ . ] with-cell ] each ] with-row ] each
! ] tabular-output ! ] tabular-output
! : html-pp ( vector -- )
! [ 0 #indentations set 2 tab-width set ] with-scope ;

View File

@ -0,0 +1 @@
Doug Coleman

View File

@ -0,0 +1,22 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien.c-types assocs combinators destructors
kernel math math.bitfields math.parser sequences summary system
vocabs.loader ;
IN: io.serial
TUPLE: serial stream path baud
termios iflag oflag cflag lflag ;
ERROR: invalid-baud baud ;
M: invalid-baud summary ( invalid-baud -- string )
"Baud rate "
swap baud>> number>string
" not supported" 3append ;
HOOK: lookup-baud os ( m -- n )
HOOK: open-serial os ( serial -- stream )
{
{ [ os unix? ] [ "io.serial.unix" ] }
} cond require

View File

@ -0,0 +1 @@
Serial port library

1
extra/io/serial/tags.txt Normal file
View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1,86 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien.syntax kernel math.bitfields sequences system io.serial ;
IN: io.serial.unix
M: bsd lookup-baud ( m -- n )
dup {
0 50 75 110 134 150 200 300 600 1200 1800 2400 4800
7200 9600 14400 19200 28800 38400 57600 76800 115200
230400 460800 921600
} member? [ invalid-baud ] unless ;
: TCSANOW 0 ; inline
: TCSADRAIN 1 ; inline
: TCSAFLUSH 2 ; inline
: TCSASOFT HEX: 10 ; inline
: TCIFLUSH 1 ; inline
: TCOFLUSH 2 ; inline
: TCIOFLUSH 3 ; inline
: TCOOFF 1 ; inline
: TCOON 2 ; inline
: TCIOFF 3 ; inline
: TCION 4 ; inline
! iflags
: IGNBRK HEX: 00000001 ; inline
: BRKINT HEX: 00000002 ; inline
: IGNPAR HEX: 00000004 ; inline
: PARMRK HEX: 00000008 ; inline
: INPCK HEX: 00000010 ; inline
: ISTRIP HEX: 00000020 ; inline
: INLCR HEX: 00000040 ; inline
: IGNCR HEX: 00000080 ; inline
: ICRNL HEX: 00000100 ; inline
: IXON HEX: 00000200 ; inline
: IXOFF HEX: 00000400 ; inline
: IXANY HEX: 00000800 ; inline
: IMAXBEL HEX: 00002000 ; inline
: IUTF8 HEX: 00004000 ; inline
! oflags
: OPOST HEX: 00000001 ; inline
: ONLCR HEX: 00000002 ; inline
: OXTABS HEX: 00000004 ; inline
: ONOEOT HEX: 00000008 ; inline
! cflags
: CIGNORE HEX: 00000001 ; inline
: CSIZE HEX: 00000300 ; inline
: CS5 HEX: 00000000 ; inline
: CS6 HEX: 00000100 ; inline
: CS7 HEX: 00000200 ; inline
: CS8 HEX: 00000300 ; inline
: CSTOPB HEX: 00000400 ; inline
: CREAD HEX: 00000800 ; inline
: PARENB HEX: 00001000 ; inline
: PARODD HEX: 00002000 ; inline
: HUPCL HEX: 00004000 ; inline
: CLOCAL HEX: 00008000 ; inline
: CCTS_OFLOW HEX: 00010000 ; inline
: CRTS_IFLOW HEX: 00020000 ; inline
: CRTSCTS { CCTS_OFLOW CRTS_IFLOW } flags ; inline
: CDTR_IFLOW HEX: 00040000 ; inline
: CDSR_OFLOW HEX: 00080000 ; inline
: CCAR_OFLOW HEX: 00100000 ; inline
: MDMBUF HEX: 00100000 ; inline
! lflags
: ECHOKE HEX: 00000001 ; inline
: ECHOE HEX: 00000002 ; inline
: ECHOK HEX: 00000004 ; inline
: ECHO HEX: 00000008 ; inline
: ECHONL HEX: 00000010 ; inline
: ECHOPRT HEX: 00000020 ; inline
: ECHOCTL HEX: 00000040 ; inline
: ISIG HEX: 00000080 ; inline
: ICANON HEX: 00000100 ; inline
: ALTWERASE HEX: 00000200 ; inline
: IEXTEN HEX: 00000400 ; inline
: EXTPROC HEX: 00000800 ; inline
: TOSTOP HEX: 00400000 ; inline
: FLUSHO HEX: 00800000 ; inline
: NOKERNINFO HEX: 02000000 ; inline
: PENDIN HEX: 20000000 ; inline
: NOFLSH HEX: 80000000 ; inline

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1,130 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: assocs alien.syntax kernel io.serial system unix ;
IN: io.serial.unix
: TCSANOW 0 ; inline
: TCSADRAIN 1 ; inline
: TCSAFLUSH 2 ; inline
: TCIFLUSH 0 ; inline
: TCOFLUSH 1 ; inline
: TCIOFLUSH 2 ; inline
: TCOOFF 0 ; inline
: TCOON 1 ; inline
: TCIOFF 2 ; inline
: TCION 3 ; inline
! iflag
: IGNBRK OCT: 0000001 ; inline
: BRKINT OCT: 0000002 ; inline
: IGNPAR OCT: 0000004 ; inline
: PARMRK OCT: 0000010 ; inline
: INPCK OCT: 0000020 ; inline
: ISTRIP OCT: 0000040 ; inline
: INLCR OCT: 0000100 ; inline
: IGNCR OCT: 0000200 ; inline
: ICRNL OCT: 0000400 ; inline
: IUCLC OCT: 0001000 ; inline
: IXON OCT: 0002000 ; inline
: IXANY OCT: 0004000 ; inline
: IXOFF OCT: 0010000 ; inline
: IMAXBEL OCT: 0020000 ; inline
: IUTF8 OCT: 0040000 ; inline
! oflag
: OPOST OCT: 0000001 ; inline
: OLCUC OCT: 0000002 ; inline
: ONLCR OCT: 0000004 ; inline
: OCRNL OCT: 0000010 ; inline
: ONOCR OCT: 0000020 ; inline
: ONLRET OCT: 0000040 ; inline
: OFILL OCT: 0000100 ; inline
: OFDEL OCT: 0000200 ; inline
: NLDLY OCT: 0000400 ; inline
: NL0 OCT: 0000000 ; inline
: NL1 OCT: 0000400 ; inline
: CRDLY OCT: 0003000 ; inline
: CR0 OCT: 0000000 ; inline
: CR1 OCT: 0001000 ; inline
: CR2 OCT: 0002000 ; inline
: CR3 OCT: 0003000 ; inline
: TABDLY OCT: 0014000 ; inline
: TAB0 OCT: 0000000 ; inline
: TAB1 OCT: 0004000 ; inline
: TAB2 OCT: 0010000 ; inline
: TAB3 OCT: 0014000 ; inline
: BSDLY OCT: 0020000 ; inline
: BS0 OCT: 0000000 ; inline
: BS1 OCT: 0020000 ; inline
: FFDLY OCT: 0100000 ; inline
: FF0 OCT: 0000000 ; inline
: FF1 OCT: 0100000 ; inline
! cflags
: CSIZE OCT: 0000060 ; inline
: CS5 OCT: 0000000 ; inline
: CS6 OCT: 0000020 ; inline
: CS7 OCT: 0000040 ; inline
: CS8 OCT: 0000060 ; inline
: CSTOPB OCT: 0000100 ; inline
: CREAD OCT: 0000200 ; inline
: PARENB OCT: 0000400 ; inline
: PARODD OCT: 0001000 ; inline
: HUPCL OCT: 0002000 ; inline
: CLOCAL OCT: 0004000 ; inline
: CIBAUD OCT: 002003600000 ; inline
: CRTSCTS OCT: 020000000000 ; inline
! lflags
: ISIG OCT: 0000001 ; inline
: ICANON OCT: 0000002 ; inline
: XCASE OCT: 0000004 ; inline
: ECHO OCT: 0000010 ; inline
: ECHOE OCT: 0000020 ; inline
: ECHOK OCT: 0000040 ; inline
: ECHONL OCT: 0000100 ; inline
: NOFLSH OCT: 0000200 ; inline
: TOSTOP OCT: 0000400 ; inline
: ECHOCTL OCT: 0001000 ; inline
: ECHOPRT OCT: 0002000 ; inline
: ECHOKE OCT: 0004000 ; inline
: FLUSHO OCT: 0010000 ; inline
: PENDIN OCT: 0040000 ; inline
: IEXTEN OCT: 0100000 ; inline
M: linux lookup-baud ( n -- n )
dup H{
{ 0 OCT: 0000000 }
{ 50 OCT: 0000001 }
{ 75 OCT: 0000002 }
{ 110 OCT: 0000003 }
{ 134 OCT: 0000004 }
{ 150 OCT: 0000005 }
{ 200 OCT: 0000006 }
{ 300 OCT: 0000007 }
{ 600 OCT: 0000010 }
{ 1200 OCT: 0000011 }
{ 1800 OCT: 0000012 }
{ 2400 OCT: 0000013 }
{ 4800 OCT: 0000014 }
{ 9600 OCT: 0000015 }
{ 19200 OCT: 0000016 }
{ 38400 OCT: 0000017 }
{ 57600 OCT: 0010001 }
{ 115200 OCT: 0010002 }
{ 230400 OCT: 0010003 }
{ 460800 OCT: 0010004 }
{ 500000 OCT: 0010005 }
{ 576000 OCT: 0010006 }
{ 921600 OCT: 0010007 }
{ 1000000 OCT: 0010010 }
{ 1152000 OCT: 0010011 }
{ 1500000 OCT: 0010012 }
{ 2000000 OCT: 0010013 }
{ 2500000 OCT: 0010014 }
{ 3000000 OCT: 0010015 }
{ 3500000 OCT: 0010016 }
{ 4000000 OCT: 0010017 }
} at* [ nip ] [ drop invalid-baud ] if ;

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1,19 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien.syntax kernel sequences system ;
IN: io.serial.unix.termios
: NCCS 20 ; inline
TYPEDEF: uint tcflag_t
TYPEDEF: uchar cc_t
TYPEDEF: uint speed_t
C-STRUCT: termios
{ "tcflag_t" "iflag" } ! input mode flags
{ "tcflag_t" "oflag" } ! output mode flags
{ "tcflag_t" "cflag" } ! control mode flags
{ "tcflag_t" "lflag" } ! local mode flags
{ { "cc_t" NCCS } "cc" } ! control characters
{ "speed_t" "ispeed" } ! input speed
{ "speed_t" "ospeed" } ; ! output speed

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1,20 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien.syntax kernel system unix ;
IN: io.serial.unix.termios
: NCCS 32 ; inline
TYPEDEF: uchar cc_t
TYPEDEF: uint speed_t
TYPEDEF: uint tcflag_t
C-STRUCT: termios
{ "tcflag_t" "iflag" } ! input mode flags
{ "tcflag_t" "oflag" } ! output mode flags
{ "tcflag_t" "cflag" } ! control mode flags
{ "tcflag_t" "lflag" } ! local mode flags
{ "cc_t" "line" } ! line discipline
{ { "cc_t" NCCS } "cc" } ! control characters
{ "speed_t" "ispeed" } ! input speed
{ "speed_t" "ospeed" } ; ! output speed

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1,9 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: combinators system vocabs.loader ;
IN: io.serial.unix.termios
{
{ [ os linux? ] [ "io.serial.unix.termios.linux" ] }
{ [ os bsd? ] [ "io.serial.unix.termios.bsd" ] }
} cond require

View File

@ -0,0 +1,21 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel math.bitfields serial serial.unix ;
IN: io.serial.unix
: serial-obj ( -- obj )
serial new
"/dev/ttyS0" >>path
19200 >>baud
{ IGNPAR ICRNL } flags >>iflag
{ } flags >>oflag
{ CS8 CLOCAL CREAD } flags >>cflag
{ ICANON } flags >>lflag ;
: serial-test ( -- serial )
serial-obj
open-serial
dup get-termios >>termios
dup configure-termios
dup tciflush
dup apply-termios ;

View File

@ -0,0 +1,62 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien.c-types alien.syntax combinators io.ports
io.streams.duplex io.unix.backend system kernel math math.bitfields
vocabs.loader unix io.serial io.serial.unix.termios ;
IN: io.serial.unix
<< {
{ [ os linux? ] [ "io.serial.unix.linux" ] }
{ [ os bsd? ] [ "io.serial.unix.bsd" ] }
} cond require >>
FUNCTION: speed_t cfgetispeed ( termios* t ) ;
FUNCTION: speed_t cfgetospeed ( termios* t ) ;
FUNCTION: int cfsetispeed ( termios* t, speed_t s ) ;
FUNCTION: int cfsetospeed ( termios* t, speed_t s ) ;
FUNCTION: int tcgetattr ( int i1, termios* t ) ;
FUNCTION: int tcsetattr ( int i1, int i2, termios* t ) ;
FUNCTION: int tcdrain ( int i1 ) ;
FUNCTION: int tcflow ( int i1, int i2 ) ;
FUNCTION: int tcflush ( int i1, int i2 ) ;
FUNCTION: int tcsendbreak ( int i1, int i2 ) ;
FUNCTION: void cfmakeraw ( termios* t ) ;
FUNCTION: int cfsetspeed ( termios* t, speed_t s ) ;
: fd>duplex-stream ( fd -- duplex-stream )
<fd> init-fd
[ <input-port> ] [ <output-port> ] bi <duplex-stream> ;
: open-rw ( path -- fd ) O_RDWR file-mode open-file ;
: <file-rw> ( path -- stream ) open-rw fd>duplex-stream ;
M: unix open-serial ( serial -- serial' )
path>> { O_RDWR O_NOCTTY O_NDELAY } flags file-mode open-file
fd>duplex-stream ;
: serial-fd ( serial -- fd )
stream>> in>> handle>> fd>> ;
: get-termios ( serial -- termios )
serial-fd
"termios" <c-object> [ tcgetattr io-error ] keep ;
: configure-termios ( serial -- )
dup termios>>
{
[ [ iflag>> ] dip over [ set-termios-iflag ] [ 2drop ] if ]
[ [ oflag>> ] dip over [ set-termios-oflag ] [ 2drop ] if ]
[
[
[ cflag>> 0 or ] [ baud>> lookup-baud ] bi bitor
] dip set-termios-cflag
]
[ [ lflag>> ] dip over [ set-termios-lflag ] [ 2drop ] if ]
} 2cleave ;
: tciflush ( serial -- )
serial-fd TCIFLUSH tcflush io-error ;
: apply-termios ( serial -- )
[ serial-fd TCSANOW ]
[ termios>> ] bi tcsetattr io-error ;

View File

@ -1,190 +1,178 @@
USING: kernel tools.test accessors arrays sequences qualified USING: kernel tools.test accessors arrays sequences qualified
io.streams.string io.streams.duplex namespaces threads io io.streams.duplex namespaces threads
calendar irc.client.private irc.client irc.messages.private calendar irc.client.private irc.client irc.messages.private
concurrency.mailboxes classes assocs combinators ; concurrency.mailboxes classes assocs combinators ;
EXCLUDE: irc.messages => join ; EXCLUDE: irc.messages => join ;
RENAME: join irc.messages => join_ RENAME: join irc.messages => join_
IN: irc.client.tests IN: irc.client.tests
! Utilities ! Streams for testing
: <test-stream> ( lines -- stream ) TUPLE: mb-writer lines last-line disposed ;
"\n" join <string-reader> <string-writer> <duplex-stream> ; TUPLE: mb-reader lines disposed ;
: <mb-writer> ( -- mb-writer ) V{ } clone V{ } clone f mb-writer boa ;
: <mb-reader> ( -- mb-reader ) <mailbox> f mb-reader boa ;
: push-line ( line test-reader-stream -- ) lines>> mailbox-put ;
: <test-stream> ( -- stream ) <mb-reader> <mb-writer> <duplex-stream> ;
M: mb-writer stream-write ( line mb-writer -- ) last-line>> push ;
M: mb-writer stream-flush ( mb-writer -- ) drop ;
M: mb-reader stream-readln ( mb-reader -- str/f ) lines>> mailbox-get ;
M: mb-writer stream-nl ( mb-writer -- )
[ [ last-line>> concat ] [ lines>> ] bi push ] keep
V{ } clone >>last-line drop ;
: make-client ( lines -- irc-client ) : spawn-client ( lines listeners -- irc-client )
"someserver" irc-port "factorbot" f <irc-profile> <irc-client> "someserver" irc-port "factorbot" f <irc-profile>
swap [ 2nip <test-stream> f ] curry >>connect ; <irc-client>
t >>is-running
<test-stream> >>stream
dup [ spawn-irc yield ] with-irc-client ;
: set-nick ( irc-client nickname -- ) ! to be used inside with-irc-client quotations
swap profile>> (>>nickname) ; : %add-named-listener ( listener -- ) [ name>> ] keep set+run-listener ;
: %join ( channel -- ) <irc-channel-listener> irc> add-listener ;
: %push-line ( line -- ) irc> stream>> in>> push-line yield ;
: with-dummy-client ( irc-client quot -- ) : read-matching-message ( listener quot: ( msg -- ? ) -- irc-message )
[ current-irc-client ] dip with-variable ; inline [ in-messages>> 0.1 seconds ] dip mailbox-get-timeout? ;
{ "" } make-client dup "factorbot" set-nick [ : with-irc ( quot: ( -- ) -- )
{ t } [ irc> profile>> nickname>> me? ] unit-test [ spawn-client ] dip [ f %push-line ] compose with-irc-client ; inline
{ "factorbot" } [ irc> profile>> nickname>> ] unit-test ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! TESTS
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
{ "someuser" } [ "someuser!n=user@some.where" parse-name ] unit-test [ { t } [ irc> profile>> nickname>> me? ] unit-test
{ "#factortest" } [ ":someuser!n=user@some.where PRIVMSG #factortest :hi" { "factorbot" } [ irc> profile>> nickname>> ] unit-test
parse-irc-line irc-message-origin ] unit-test
{ "someuser" } [ ":someuser!n=user@some.where PRIVMSG factorbot :hi" { "someuser" } [ "someuser!n=user@some.where" parse-name ] unit-test
parse-irc-line irc-message-origin ] unit-test
] with-dummy-client { "#factortest" } [ ":someuser!n=user@some.where PRIVMSG #factortest :hi"
parse-irc-line forward-name ] unit-test
{ "someuser" } [ ":someuser!n=user@some.where PRIVMSG factorbot :hi"
parse-irc-line forward-name ] unit-test
] with-irc
! Test login and nickname set ! Test login and nickname set
{ "factorbot" } [ [ { "factorbot2" } [
{ "NOTICE AUTH :*** Looking up your hostname..." ":some.where 001 factorbot2 :Welcome factorbot2" %push-line
"NOTICE AUTH :*** Checking ident" irc> profile>> nickname>>
"NOTICE AUTH :*** Found your hostname" ] unit-test
"NOTICE AUTH :*** No identd (auth) response" ] with-irc
":some.where 001 factorbot :Welcome factorbot"
} make-client
{ [ connect-irc ]
[ drop 0.1 seconds sleep ]
[ profile>> nickname>> ]
[ terminate-irc ]
} cleave ] unit-test
{ join_ "#factortest" } [ [ { join_ "#factortest" } [
{ ":factorbot!n=factorbo@some.where JOIN :#factortest" { ":factorbot!n=factorbo@some.where JOIN :#factortest"
":ircserver.net MODE #factortest +ns" ":ircserver.net 353 factorbot @ #factortest :@factorbot "
":ircserver.net 353 factorbot @ #factortest :@factorbot " ":ircserver.net 366 factorbot #factortest :End of /NAMES list."
":ircserver.net 366 factorbot #factortest :End of /NAMES list." ":ircserver.net 477 factorbot #factortest :[ircserver-info] blah blah"
":ircserver.net 477 factorbot #factortest :[ircserver-info] blah blah" } [ %push-line ] each
} make-client irc> join-messages>> 0.1 seconds mailbox-get-timeout
{ [ "factorbot" set-nick ] [ class ] [ trailing>> ] bi
[ connect-irc ] ] unit-test
[ drop 0.1 seconds sleep ] ] with-irc
[ join-messages>> 0.1 seconds mailbox-get-timeout ]
[ terminate-irc ]
} cleave
[ class ] [ trailing>> ] bi ] unit-test
{ +join+ "somebody" } [ [ { T{ participant-changed f "somebody" +join+ } } [
{ ":somebody!n=somebody@some.where JOIN :#factortest" } make-client "#factortest" <irc-channel-listener> [ %add-named-listener ] keep
{ [ "factorbot" set-nick ] ":somebody!n=somebody@some.where JOIN :#factortest" %push-line
[ listeners>> [ participant-changed? ] read-matching-message
[ "#factortest" [ <irc-channel-listener> ] keep ] dip set-at ] ] unit-test
[ connect-irc ] ] with-irc
[ listeners>> [ "#factortest" ] dip at
[ read-message drop ] [ read-message drop ] [ read-message ] tri ]
[ terminate-irc ]
} cleave
[ action>> ] [ nick>> ] bi
] unit-test
{ privmsg "#factortest" "hello" } [ [ { privmsg "#factortest" "hello" } [
{ ":somebody!n=somebody@some.where PRIVMSG #factortest :hello" } make-client "#factortest" <irc-channel-listener> [ %add-named-listener ] keep
{ [ "factorbot" set-nick ] ":somebody!n=somebody@some.where PRIVMSG #factortest :hello" %push-line
[ listeners>> [ privmsg? ] read-matching-message
[ "#factortest" [ <irc-channel-listener> ] keep ] dip set-at ] [ class ] [ name>> ] [ trailing>> ] tri
[ connect-irc ] ] unit-test
[ listeners>> [ "#factortest" ] dip at ] with-irc
[ read-message drop ] [ read-message ] bi ]
[ terminate-irc ]
} cleave
[ class ] [ name>> ] [ trailing>> ] tri
] unit-test
{ privmsg "factorbot" "hello" } [ [ { privmsg "factorbot" "hello" } [
{ ":somedude!n=user@isp.net PRIVMSG factorbot :hello" } make-client "somedude" <irc-nick-listener> [ %add-named-listener ] keep
{ [ "factorbot" set-nick ] ":somedude!n=user@isp.net PRIVMSG factorbot :hello" %push-line
[ listeners>> [ privmsg? ] read-matching-message
[ "somedude" [ <irc-nick-listener> ] keep ] dip set-at ] [ class ] [ name>> ] [ trailing>> ] tri
[ connect-irc ] ] unit-test
[ listeners>> [ "somedude" ] dip at ] with-irc
[ read-message drop ] [ read-message ] bi ]
[ terminate-irc ]
} cleave
[ class ] [ name>> ] [ trailing>> ] tri
] unit-test
! Participants lists tests [ { mode } [
{ H{ { "somedude" +normal+ } } } [ "#factortest" <irc-channel-listener> [ %add-named-listener ] keep
{ ":somedude!n=user@isp.net JOIN :#factortest" } make-client ":ircserver.net MODE #factortest +ns" %push-line
{ [ "factorbot" set-nick ] [ mode? ] read-matching-message class
[ listeners>> ] unit-test
[ "#factortest" [ <irc-channel-listener> ] keep ] dip set-at ] ] with-irc
[ connect-irc ]
[ drop 0.1 seconds sleep ]
[ listeners>> [ "#factortest" ] dip at participants>> ]
[ terminate-irc ]
} cleave
] unit-test
{ H{ { "somedude2" +normal+ } } } [ ! Participant lists tests
{ ":somedude!n=user@isp.net PART #factortest" } make-client [ { H{ { "somedude" +normal+ } } } [
{ [ "factorbot" set-nick ] "#factortest" <irc-channel-listener> [ %add-named-listener ] keep
[ listeners>> ":somedude!n=user@isp.net JOIN :#factortest" %push-line
[ "#factortest" [ <irc-channel-listener> participants>>
H{ { "somedude2" +normal+ } ] unit-test
{ "somedude" +normal+ } } clone >>participants ] keep ] with-irc
] dip set-at ]
[ connect-irc ]
[ drop 0.1 seconds sleep ]
[ listeners>> [ "#factortest" ] dip at participants>> ]
[ terminate-irc ]
} cleave
] unit-test
{ H{ { "somedude2" +normal+ } } } [ [ { H{ { "somedude2" +normal+ } } } [
{ ":somedude!n=user@isp.net QUIT" } make-client "#factortest" <irc-channel-listener>
{ [ "factorbot" set-nick ] H{ { "somedude2" +normal+ }
[ listeners>> { "somedude" +normal+ } } clone >>participants
[ "#factortest" [ <irc-channel-listener> [ %add-named-listener ] keep
H{ { "somedude2" +normal+ } ":somedude!n=user@isp.net PART #factortest" %push-line
{ "somedude" +normal+ } } clone >>participants ] keep participants>>
] dip set-at ] ] unit-test
[ connect-irc ] ] with-irc
[ drop 0.1 seconds sleep ]
[ listeners>> [ "#factortest" ] dip at participants>> ]
[ terminate-irc ]
} cleave
] unit-test
{ H{ { "somedude2" +normal+ } } } [ [ { H{ { "somedude2" +normal+ } } } [
{ ":somedude2!n=user2@isp.net KICK #factortest somedude" } make-client "#factortest" <irc-channel-listener>
{ [ "factorbot" set-nick ] H{ { "somedude2" +normal+ }
[ listeners>> { "somedude" +normal+ } } clone >>participants
[ "#factortest" [ <irc-channel-listener> [ %add-named-listener ] keep
H{ { "somedude2" +normal+ } ":somedude!n=user@isp.net QUIT" %push-line
{ "somedude" +normal+ } } clone >>participants ] keep participants>>
] dip set-at ] ] unit-test
[ connect-irc ] ] with-irc
[ drop 0.1 seconds sleep ]
[ listeners>> [ "#factortest" ] dip at participants>> ] [ { H{ { "somedude2" +normal+ } } } [
[ terminate-irc ] "#factortest" <irc-channel-listener>
} cleave H{ { "somedude2" +normal+ }
] unit-test { "somedude" +normal+ } } clone >>participants
[ %add-named-listener ] keep
":somedude2!n=user2@isp.net KICK #factortest somedude" %push-line
participants>>
] unit-test
] with-irc
[ { H{ { "somedude2" +normal+ } } } [
"#factortest" <irc-channel-listener>
H{ { "somedude" +normal+ } } clone >>participants
[ %add-named-listener ] keep
":somedude!n=user2@isp.net NICK :somedude2" %push-line
participants>>
] unit-test
] with-irc
! Namelist change notification ! Namelist change notification
{ T{ participant-changed f f f } } [ [ { T{ participant-changed f f f f } } [
{ ":ircserver.net 353 factorbot @ #factortest :@factorbot " "#factortest" <irc-channel-listener> [ %add-named-listener ] keep
":ircserver.net 366 factorbot #factortest :End of /NAMES list." } make-client ":ircserver.net 353 factorbot @ #factortest :@factorbot " %push-line
{ [ "factorbot" set-nick ] ":ircserver.net 366 factorbot #factortest :End of /NAMES list." %push-line
[ listeners>> [ participant-changed? ] read-matching-message
[ "#factortest" [ <irc-channel-listener> ] keep ] dip set-at ] ] unit-test
[ connect-irc ] ] with-irc
[ drop 0.1 seconds sleep ]
[ listeners>> [ "#factortest" ] dip at [ read-message drop ] [ read-message ] bi ]
[ terminate-irc ]
} cleave
] unit-test
{ T{ participant-changed f "somedude" +part+ } } [ [ { T{ participant-changed f "somedude" +part+ f } } [
{ ":somedude!n=user@isp.net QUIT" } make-client "#factortest" <irc-channel-listener>
{ [ "factorbot" set-nick ] H{ { "somedude" +normal+ } } clone >>participants
[ listeners>> [ %add-named-listener ] keep
[ "#factortest" [ <irc-channel-listener> ":somedude!n=user@isp.net QUIT" %push-line
H{ { "somedude" +normal+ } } clone >>participants ] keep [ participant-changed? ] read-matching-message
] dip set-at ] ] unit-test
[ connect-irc ] ] with-irc
[ drop 0.1 seconds sleep ]
[ listeners>> [ "#factortest" ] dip at [ { T{ participant-changed f "somedude" +nick+ "somedude2" } } [
[ read-message drop ] [ read-message drop ] [ read-message ] tri ] "#factortest" <irc-channel-listener>
[ terminate-irc ] H{ { "somedude" +normal+ } } clone >>participants
} cleave [ %add-named-listener ] keep
] unit-test ":somedude!n=user2@isp.net NICK :somedude2" %push-line
[ participant-changed? ] read-matching-message
] unit-test
] with-irc

View File

@ -3,7 +3,7 @@
USING: concurrency.mailboxes kernel io.sockets io.encodings.8-bit calendar USING: concurrency.mailboxes kernel io.sockets io.encodings.8-bit calendar
accessors destructors namespaces io assocs arrays qualified fry accessors destructors namespaces io assocs arrays qualified fry
continuations threads strings classes combinators splitting hashtables continuations threads strings classes combinators splitting hashtables
ascii irc.messages irc.messages.private ; ascii irc.messages ;
RENAME: join sequences => sjoin RENAME: join sequences => sjoin
EXCLUDE: sequences => join ; EXCLUDE: sequences => join ;
IN: irc.client IN: irc.client
@ -41,6 +41,7 @@ SYMBOL: +normal+
SYMBOL: +join+ SYMBOL: +join+
SYMBOL: +part+ SYMBOL: +part+
SYMBOL: +mode+ SYMBOL: +mode+
SYMBOL: +nick+
! listener objects ! listener objects
: <irc-listener> ( -- irc-listener ) <mailbox> <mailbox> irc-listener boa ; : <irc-listener> ( -- irc-listener ) <mailbox> <mailbox> irc-listener boa ;
@ -59,14 +60,13 @@ SYMBOL: +mode+
! Message objects ! Message objects
! ====================================== ! ======================================
TUPLE: participant-changed nick action ; TUPLE: participant-changed nick action parameter ;
C: <participant-changed> participant-changed C: <participant-changed> participant-changed
SINGLETON: irc-listener-end ! send to a listener to stop its execution SINGLETON: irc-listener-end ! send to a listener to stop its execution
SINGLETON: irc-end ! sent when the client isn't running anymore SINGLETON: irc-end ! sent when the client isn't running anymore
SINGLETON: irc-disconnected ! sent when connection is lost SINGLETON: irc-disconnected ! sent when connection is lost
SINGLETON: irc-connected ! sent when connection is established SINGLETON: irc-connected ! sent when connection is established
UNION: irc-broadcasted-message irc-end irc-disconnected irc-connected ;
: terminate-irc ( irc-client -- ) : terminate-irc ( irc-client -- )
[ is-running>> ] keep and [ [ is-running>> ] keep and [
@ -100,33 +100,54 @@ M: string to-listener ( message string -- )
listener> [ +server-listener+ listener> ] unless* listener> [ +server-listener+ listener> ] unless*
[ to-listener ] [ drop ] if* ; [ to-listener ] [ drop ] if* ;
M: irc-listener to-listener ( message irc-listener -- )
in-messages>> mailbox-put ;
: unregister-listener ( name -- ) : unregister-listener ( name -- )
irc> listeners>> irc> listeners>>
[ at [ irc-listener-end ] dip to-listener ] [ at [ irc-listener-end ] dip to-listener ]
[ delete-at ] [ delete-at ]
2bi ; 2bi ;
M: irc-listener to-listener ( message irc-listener -- ) : (remove-participant) ( nick listener -- )
in-messages>> mailbox-put ; [ participants>> delete-at ]
[ [ +part+ f <participant-changed> ] dip to-listener ] 2bi ;
: remove-participant ( nick channel -- ) : remove-participant ( nick channel -- )
listener> [ participants>> delete-at ] [ drop ] if* ; listener> [ (remove-participant) ] [ drop ] if* ;
: listeners-with-participant ( nick -- seq ) : listeners-with-participant ( nick -- seq )
irc> listeners>> values irc> listeners>> values
[ dup irc-channel-listener? [ participants>> key? ] [ 2drop f ] if ] [ dup irc-channel-listener? [ participants>> key? ] [ 2drop f ] if ]
with filter ; with filter ;
: to-listeners-with-participant ( message nickname -- )
listeners-with-participant [ to-listener ] with each ;
: remove-participant-from-all ( nick -- ) : remove-participant-from-all ( nick -- )
dup listeners-with-participant [ participants>> delete-at ] with each ; dup listeners-with-participant [ (remove-participant) ] with each ;
: notify-rename ( newnick oldnick listener -- )
[ participant-changed new +nick+ >>action
[ (>>nick) ] [ (>>parameter) ] [ ] tri ] dip to-listener ;
: rename-participant ( newnick oldnick listener -- )
[ participants>> [ delete-at* drop ] [ [ swap ] dip set-at ] bi ]
[ notify-rename ] 3bi ;
: rename-participant-in-all ( oldnick newnick -- )
swap dup listeners-with-participant [ rename-participant ] with with each ;
: add-participant ( mode nick channel -- ) : add-participant ( mode nick channel -- )
listener> [ participants>> set-at ] [ 2drop ] if* ; listener> [
[ participants>> set-at ]
[ [ +join+ f <participant-changed> ] dip to-listener ] 2bi
] [ 2drop ] if* ;
DEFER: me? DEFER: me?
: maybe-forward-join ( join -- ) : maybe-forward-join ( join -- )
[ prefix>> parse-name me? ] keep and [ irc-message-sender me? ] keep and
[ irc> join-messages>> mailbox-put ] when* ; [ irc> join-messages>> mailbox-put ] when* ;
! ====================================== ! ======================================
@ -158,78 +179,64 @@ DEFER: me?
: me? ( string -- ? ) : me? ( string -- ? )
irc> profile>> nickname>> = ; irc> profile>> nickname>> = ;
: irc-message-origin ( irc-message -- name ) GENERIC: forward-name ( irc-message -- name )
dup name>> me? [ prefix>> parse-name ] [ name>> ] if ; M: join forward-name ( join -- name ) trailing>> ;
M: part forward-name ( part -- name ) channel>> ;
M: kick forward-name ( kick -- name ) channel>> ;
M: mode forward-name ( mode -- name ) channel>> ;
M: privmsg forward-name ( privmsg -- name )
dup name>> me? [ irc-message-sender ] [ name>> ] if ;
: broadcast-message-to-listeners ( message -- ) UNION: single-forward join part kick mode privmsg ;
irc> listeners>> values [ to-listener ] with each ; UNION: multiple-forward nick quit ;
UNION: broadcast-forward irc-end irc-disconnected irc-connected ;
GENERIC: forward-message ( irc-message -- )
GENERIC: handle-participant-change ( irc-message -- ) M: irc-message forward-message ( irc-message -- )
M: join handle-participant-change ( join -- )
[ prefix>> parse-name +join+ <participant-changed> ]
[ trailing>> ] bi to-listener ;
M: part handle-participant-change ( part -- )
[ prefix>> parse-name +part+ <participant-changed> ]
[ channel>> ] bi to-listener ;
M: kick handle-participant-change ( kick -- )
[ who>> +part+ <participant-changed> ]
[ channel>> ] bi to-listener ;
M: quit handle-participant-change ( quit -- )
prefix>> parse-name
[ +part+ <participant-changed> ] [ listeners-with-participant ] bi
[ to-listener ] with each ;
GENERIC: handle-incoming-irc ( irc-message -- )
M: irc-message handle-incoming-irc ( irc-message -- )
+server-listener+ listener> [ to-listener ] [ drop ] if* ; +server-listener+ listener> [ to-listener ] [ drop ] if* ;
M: logged-in handle-incoming-irc ( logged-in -- ) M: single-forward forward-message ( forward-single -- )
dup forward-name to-listener ;
M: multiple-forward forward-message ( multiple-forward -- )
dup irc-message-sender to-listeners-with-participant ;
M: join forward-message ( join -- )
[ maybe-forward-join ] [ call-next-method ] bi ;
M: broadcast-forward forward-message ( irc-broadcasted-message -- )
irc> listeners>> values [ to-listener ] with each ;
GENERIC: process-message ( irc-message -- )
M: object process-message ( object -- )
drop ;
M: logged-in process-message ( logged-in -- )
name>> irc> profile>> (>>nickname) ; name>> irc> profile>> (>>nickname) ;
M: ping handle-incoming-irc ( ping -- ) M: ping process-message ( ping -- )
trailing>> /PONG ; trailing>> /PONG ;
M: nick-in-use handle-incoming-irc ( nick-in-use -- ) M: nick-in-use process-message ( nick-in-use -- )
name>> "_" append /NICK ; name>> "_" append /NICK ;
M: privmsg handle-incoming-irc ( privmsg -- ) M: join process-message ( join -- )
dup irc-message-origin to-listener ; [ drop +normal+ ] [ irc-message-sender ] [ trailing>> ] tri add-participant ;
M: join handle-incoming-irc ( join -- ) M: part process-message ( part -- )
{ [ maybe-forward-join ] [ irc-message-sender ] [ channel>> ] bi remove-participant ;
[ dup trailing>> to-listener ]
[ [ drop +normal+ ] [ prefix>> parse-name ] [ trailing>> ] tri add-participant ]
[ handle-participant-change ]
} cleave ;
M: part handle-incoming-irc ( part -- ) M: kick process-message ( kick -- )
[ dup channel>> to-listener ] [ [ who>> ] [ channel>> ] bi remove-participant ]
[ [ prefix>> parse-name ] [ channel>> ] bi remove-participant ] [ dup who>> me? [ unregister-listener ] [ drop ] if ]
[ handle-participant-change ] bi ;
tri ;
M: kick handle-incoming-irc ( kick -- ) M: quit process-message ( quit -- )
{ [ dup channel>> to-listener ] irc-message-sender remove-participant-from-all ;
[ [ who>> ] [ channel>> ] bi remove-participant ]
[ handle-participant-change ]
[ dup who>> me? [ unregister-listener ] [ drop ] if ]
} cleave ;
M: quit handle-incoming-irc ( quit -- ) M: nick process-message ( nick -- )
[ dup prefix>> parse-name listeners-with-participant [ irc-message-sender ] [ trailing>> ] bi rename-participant-in-all ;
[ to-listener ] with each ]
[ handle-participant-change ]
[ prefix>> parse-name remove-participant-from-all ]
tri ;
! FIXME: implement this
! M: mode handle-incoming-irc ( mode -- ) call-next-method ;
! M: nick handle-incoming-irc ( nick -- ) call-next-method ;
: >nick/mode ( string -- nick mode ) : >nick/mode ( string -- nick mode )
dup first "+@" member? [ unclip ] [ 0 ] if participant-mode ; dup first "+@" member? [ unclip ] [ 0 ] if participant-mode ;
@ -238,22 +245,20 @@ M: quit handle-incoming-irc ( quit -- )
trailing>> [ blank? ] trim " " split trailing>> [ blank? ] trim " " split
[ >nick/mode 2array ] map >hashtable ; [ >nick/mode 2array ] map >hashtable ;
M: names-reply handle-incoming-irc ( names-reply -- ) M: names-reply process-message ( names-reply -- )
[ names-reply>participants ] [ channel>> listener> ] bi [ [ names-reply>participants ] [ channel>> listener> ] bi [
[ (>>participants) ] [ (>>participants) ]
[ [ f f <participant-changed> ] dip name>> to-listener ] bi [ [ f f f <participant-changed> ] dip name>> to-listener ] bi
] [ drop ] if* ; ] [ drop ] if* ;
M: irc-broadcasted-message handle-incoming-irc ( irc-broadcasted-message -- ) : handle-incoming-irc ( irc-message -- )
broadcast-message-to-listeners ; [ forward-message ] [ process-message ] bi ;
! ====================================== ! ======================================
! Client message handling ! Client message handling
! ====================================== ! ======================================
GENERIC: handle-outgoing-irc ( obj -- ) : handle-outgoing-irc ( irc-message -- )
M: irc-message handle-outgoing-irc ( irc-message -- )
irc-message>client-line irc-print ; irc-message>client-line irc-print ;
! ====================================== ! ======================================
@ -367,7 +372,7 @@ M: irc-server-listener (remove-listener) ( irc-server-listener -- )
in-messages>> [ irc-connected ] dip mailbox-put ; in-messages>> [ irc-connected ] dip mailbox-put ;
: with-irc-client ( irc-client quot: ( -- ) -- ) : with-irc-client ( irc-client quot: ( -- ) -- )
[ current-irc-client ] dip with-variable ; inline [ \ current-irc-client ] dip with-variable ; inline
PRIVATE> PRIVATE>

View File

@ -3,7 +3,9 @@ USING: kernel tools.test accessors arrays qualified
EXCLUDE: sequences => join ; EXCLUDE: sequences => join ;
IN: irc.messages.tests IN: irc.messages.tests
! Parsing tests
{ "someuser" } [ "someuser!n=user@some.where" parse-name ] unit-test
irc-message new irc-message new
":someuser!n=user@some.where PRIVMSG #factortest :hi" >>line ":someuser!n=user@some.where PRIVMSG #factortest :hi" >>line
"someuser!n=user@some.where" >>prefix "someuser!n=user@some.where" >>prefix

7
extra/irc/messages/messages.factor Normal file → Executable file
View File

@ -46,7 +46,7 @@ GENERIC: irc-command-parameters ( irc-message -- seq )
M: irc-message irc-command-parameters ( irc-message -- seq ) parameters>> ; M: irc-message irc-command-parameters ( irc-message -- seq ) parameters>> ;
M: ping irc-command-parameters ( ping -- seq ) drop { } ; M: ping irc-command-parameters ( ping -- seq ) drop { } ;
M: join irc-command-parameters ( join -- seq ) drop { } ; M: join irc-command-parameters ( join -- seq ) drop { } ;
M: part irc-command-parameters ( part -- seq ) name>> 1array ; M: part irc-command-parameters ( part -- seq ) channel>> 1array ;
M: quit irc-command-parameters ( quit -- seq ) drop { } ; M: quit irc-command-parameters ( quit -- seq ) drop { } ;
M: nick irc-command-parameters ( nick -- seq ) drop { } ; M: nick irc-command-parameters ( nick -- seq ) drop { } ;
M: privmsg irc-command-parameters ( privmsg -- seq ) name>> 1array ; M: privmsg irc-command-parameters ( privmsg -- seq ) name>> 1array ;
@ -98,6 +98,11 @@ M: irc-message irc-message>server-line ( irc-message -- string )
PRIVATE> PRIVATE>
UNION: sender-in-prefix privmsg join part quit kick mode nick ;
GENERIC: irc-message-sender ( irc-message -- sender )
M: sender-in-prefix irc-message-sender ( sender-in-prefix -- sender )
prefix>> parse-name ;
: string>irc-message ( string -- object ) : string>irc-message ( string -- object )
dup split-prefix split-trailing dup split-prefix split-trailing
[ [ blank? ] trim " " split unclip swap ] dip [ [ blank? ] trim " " split unclip swap ] dip

View File

@ -1,13 +1,24 @@
! Copyright (C) 2008 William Schlieper ! Copyright (C) 2008 William Schlieper
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel irc.client irc.messages irc.ui namespaces ; USING: accessors kernel arrays irc.client irc.messages irc.ui namespaces ;
IN: irc.ui.commands IN: irc.ui.commands
: say ( string -- ) : say ( string -- )
[ client get profile>> nickname>> <own-message> print-irc ] irc-tab get
[ listener get write-message ] bi ; [ window>> client>> profile>> nickname>> <own-message> print-irc ]
[ listener>> write-message ] 2bi ;
: join ( string -- )
irc-tab get window>> join-channel ;
: query ( string -- )
irc-tab get window>> query-nick ;
: whois ( string -- )
"WHOIS" swap { } clone swap <irc-client-message>
irc-tab get listener>> write-message ;
: quote ( string -- ) : quote ( string -- )
drop ; ! THIS WILL CHANGE drop ; ! THIS WILL CHANGE

View File

@ -8,7 +8,7 @@ USING: accessors kernel threads combinators concurrency.mailboxes
ui.gadgets.scrollers ui.commands ui.gadgets.frames ui.gestures ui.gadgets.scrollers ui.commands ui.gadgets.frames ui.gestures
ui.gadgets.tabs ui.gadgets.grids ui.gadgets.packs ui.gadgets.labels ui.gadgets.tabs ui.gadgets.grids ui.gadgets.packs ui.gadgets.labels
io io.styles namespaces calendar calendar.format models continuations io io.styles namespaces calendar calendar.format models continuations
irc.client irc.client.private irc.messages irc.messages.private irc.client irc.client.private irc.messages
irc.ui.commandparser irc.ui.load ; irc.ui.commandparser irc.ui.load ;
RENAME: join sequences => sjoin RENAME: join sequences => sjoin
@ -19,9 +19,12 @@ SYMBOL: listener
SYMBOL: client SYMBOL: client
TUPLE: ui-window client tabs ; TUPLE: ui-window < tabbed client ;
TUPLE: irc-tab < frame listener client userlist ; M: ui-window ungraft*
client>> terminate-irc ;
TUPLE: irc-tab < frame listener client window ;
: write-color ( str color -- ) : write-color ( str color -- )
foreground associate format ; foreground associate format ;
@ -39,7 +42,7 @@ M: ping write-irc
M: privmsg write-irc M: privmsg write-irc
"<" blue write-color "<" blue write-color
[ prefix>> parse-name write ] keep [ irc-message-sender write ] keep
"> " blue write-color "> " blue write-color
trailing>> write ; trailing>> write ;
@ -61,24 +64,24 @@ M: own-message write-irc
M: join write-irc M: join write-irc
"* " dark-green write-color "* " dark-green write-color
prefix>> parse-name write irc-message-sender write
" has entered the channel." dark-green write-color ; " has entered the channel." dark-green write-color ;
M: part write-irc M: part write-irc
"* " dark-red write-color "* " dark-red write-color
[ prefix>> parse-name write ] keep [ irc-message-sender write ] keep
" has left the channel" dark-red write-color " has left the channel" dark-red write-color
trailing>> dot-or-parens dark-red write-color ; trailing>> dot-or-parens dark-red write-color ;
M: quit write-irc M: quit write-irc
"* " dark-red write-color "* " dark-red write-color
[ prefix>> parse-name write ] keep [ irc-message-sender write ] keep
" has left IRC" dark-red write-color " has left IRC" dark-red write-color
trailing>> dot-or-parens dark-red write-color ; trailing>> dot-or-parens dark-red write-color ;
M: kick write-irc M: kick write-irc
"* " dark-red write-color "* " dark-red write-color
[ prefix>> parse-name write ] keep [ irc-message-sender write ] keep
" has kicked " dark-red write-color " has kicked " dark-red write-color
[ who>> write ] keep [ who>> write ] keep
" from the channel" dark-red write-color " from the channel" dark-red write-color
@ -89,7 +92,7 @@ M: kick write-irc
M: mode write-irc M: mode write-irc
"* " blue write-color "* " blue write-color
[ prefix>> parse-name write ] keep [ irc-message-sender write ] keep
" has applied mode " blue write-color " has applied mode " blue write-color
[ full-mode write ] keep [ full-mode write ] keep
" to " blue write-color " to " blue write-color
@ -97,7 +100,7 @@ M: mode write-irc
M: nick write-irc M: nick write-irc
"* " blue write-color "* " blue write-color
[ prefix>> parse-name write ] keep [ irc-message-sender write ] keep
" is now known as " blue write-color " is now known as " blue write-color
trailing>> write ; trailing>> write ;
@ -120,8 +123,11 @@ M: irc-listener-end write-irc
M: irc-message write-irc M: irc-message write-irc
drop ; ! catch all unimplemented writes, THIS WILL CHANGE drop ; ! catch all unimplemented writes, THIS WILL CHANGE
: time-happened ( irc-message -- timestamp ) GENERIC: time-happened ( message -- timestamp )
[ timestamp>> ] [ 2drop now ] recover ;
M: irc-message time-happened timestamp>> ;
M: object time-happened drop now ;
: print-irc ( irc-message -- ) : print-irc ( irc-message -- )
[ time-happened timestamp>hms write " " write ] [ time-happened timestamp>hms write " " write ]
@ -139,16 +145,6 @@ GENERIC: handle-inbox ( tab message -- )
: add-gadget-color ( pack seq color -- pack ) : add-gadget-color ( pack seq color -- pack )
'[ , >>color add-gadget ] each ; '[ , >>color add-gadget ] each ;
: update-participants ( tab -- )
[ userlist>> [ clear-gadget ] keep ]
[ listener>> participants>> ] bi
[ +operator+ value-labels dark-green add-gadget-color ]
[ +voice+ value-labels blue add-gadget-color ]
[ +normal+ value-labels black add-gadget-color ] tri drop ;
M: participant-changed handle-inbox
drop update-participants ;
M: object handle-inbox M: object handle-inbox
nip print-irc ; nip print-irc ;
@ -161,44 +157,60 @@ M: object handle-inbox
<scrolling-pane> <scrolling-pane>
[ <pane-stream> swap display ] 2keep ; [ <pane-stream> swap display ] 2keep ;
TUPLE: irc-editor < editor outstream listener client ; TUPLE: irc-editor < editor outstream tab ;
: <irc-editor> ( tab pane -- tab editor ) : <irc-editor> ( tab pane -- tab editor )
over irc-editor new-editor irc-editor new-editor
swap listener>> >>listener swap <pane-stream> >>outstream swap <pane-stream> >>outstream ;
over client>> >>client ;
: editor-send ( irc-editor -- ) : editor-send ( irc-editor -- )
{ [ outstream>> ] { [ outstream>> ]
[ listener>> ] [ [ irc-tab? ] find-parent ]
[ client>> ]
[ editor-string ] [ editor-string ]
[ "" swap set-editor-string ] } cleave [ "" swap set-editor-string ] } cleave
'[ , listener set , client set , parse-message ] with-output-stream ; '[ , irc-tab set , parse-message ] with-output-stream ;
irc-editor "general" f { irc-editor "general" f {
{ T{ key-down f f "RET" } editor-send } { T{ key-down f f "RET" } editor-send }
{ T{ key-down f f "ENTER" } editor-send } { T{ key-down f f "ENTER" } editor-send }
} define-command-map } define-command-map
: <irc-tab> ( listener client -- irc-tab ) : new-irc-tab ( listener ui-window class -- irc-tab )
irc-tab new-frame new-frame
swap client>> >>client swap >>listener swap >>window
swap >>listener
<irc-pane> [ <scroller> @center grid-add ] keep <irc-pane> [ <scroller> @center grid-add ] keep
<irc-editor> <scroller> @bottom grid-add ; <irc-editor> <scroller> @bottom grid-add ;
: <irc-channel-tab> ( listener client -- irc-tab )
<irc-tab>
<pile> [ <scroller> @right grid-add ] keep >>userlist ;
: <irc-server-tab> ( listener client -- irc-tab )
<irc-tab> ;
M: irc-tab graft* M: irc-tab graft*
[ listener>> ] [ client>> ] bi add-listener ; [ listener>> ] [ window>> client>> ] bi add-listener ;
M: irc-tab ungraft* M: irc-tab ungraft*
[ listener>> ] [ client>> ] bi remove-listener ; [ listener>> ] [ window>> client>> ] bi remove-listener ;
TUPLE: irc-channel-tab < irc-tab userlist ;
: <irc-channel-tab> ( listener ui-window -- irc-tab )
irc-channel-tab new-irc-tab
<pile> [ <scroller> @right grid-add ] keep >>userlist ;
: update-participants ( tab -- )
[ userlist>> [ clear-gadget ] keep ]
[ listener>> participants>> ] bi
[ +operator+ value-labels dark-green add-gadget-color ]
[ +voice+ value-labels blue add-gadget-color ]
[ +normal+ value-labels black add-gadget-color ] tri drop ;
M: participant-changed handle-inbox
drop update-participants ;
TUPLE: irc-server-tab < irc-tab ;
: <irc-server-tab> ( listener -- irc-tab )
f irc-server-tab new-irc-tab ;
: <irc-nick-tab> ( listener ui-window -- irc-tab )
irc-tab new-irc-tab ;
M: irc-tab pref-dim* M: irc-tab pref-dim*
drop { 480 480 } ; drop { 480 480 } ;
@ -206,19 +218,25 @@ M: irc-tab pref-dim*
: join-channel ( name ui-window -- ) : join-channel ( name ui-window -- )
[ dup <irc-channel-listener> ] dip [ dup <irc-channel-listener> ] dip
[ <irc-channel-tab> swap ] keep [ <irc-channel-tab> swap ] keep
tabs>> add-page ; add-page ;
: query-nick ( nick ui-window -- )
[ dup <irc-nick-listener> ] dip
[ <irc-nick-tab> swap ] keep
add-page ;
: irc-window ( ui-window -- ) : irc-window ( ui-window -- )
[ tabs>> ] [ ]
[ client>> profile>> server>> ] bi [ client>> profile>> server>> ] bi
open-window ; open-window ;
: ui-connect ( profile -- ui-window ) : ui-connect ( profile -- ui-window )
<irc-client> ui-window new over >>client swap <irc-client>
[ connect-irc ] { [ [ <irc-server-listener> ] dip add-listener ]
[ [ <irc-server-listener> ] dip add-listener ] [ listeners>> +server-listener+ swap at <irc-server-tab> dup
[ listeners>> +server-listener+ swap at over <irc-tab> "Server" associate ui-window new-tabbed [ swap (>>window) ] keep ]
"Server" associate <tabbed> >>tabs ] tri ; [ >>client ]
[ connect-irc ] } cleave ;
: server-open ( server port nick password channels -- ) : server-open ( server port nick password channels -- )
[ <irc-profile> ui-connect [ irc-window ] keep ] dip [ <irc-profile> ui-connect [ irc-window ] keep ] dip

View File

@ -13,11 +13,6 @@ IN: math.combinatorics.tests
[ { 0 1 3 2 } ] [ 1 4 permutation-indices ] unit-test [ { 0 1 3 2 } ] [ 1 4 permutation-indices ] unit-test
[ { 1 2 0 6 3 5 4 } ] [ 859 7 permutation-indices ] unit-test [ { 1 2 0 6 3 5 4 } ] [ 859 7 permutation-indices ] unit-test
[ { "b" "d" } ] [ { "a" "b" "c" "d" } { 1 3 } reorder ] unit-test
[ { "a" "b" "c" "d" } ] [ { "a" "b" "c" "d" } { 0 1 2 3 } reorder ] unit-test
[ { "d" "c" "b" "a" } ] [ { "a" "b" "c" "d" } { 3 2 1 0 } reorder ] unit-test
[ { "d" "a" "b" "c" } ] [ { "a" "b" "c" "d" } { 3 0 1 2 } reorder ] unit-test
[ 1 ] [ 0 factorial ] unit-test [ 1 ] [ 0 factorial ] unit-test
[ 1 ] [ 1 factorial ] unit-test [ 1 ] [ 1 factorial ] unit-test
[ 3628800 ] [ 10 factorial ] unit-test [ 3628800 ] [ 10 factorial ] unit-test

View File

@ -1,7 +1,7 @@
! Copyright (c) 2007, 2008 Slava Pestov, Doug Coleman, Aaron Schaefer. ! Copyright (c) 2007, 2008 Slava Pestov, Doug Coleman, Aaron Schaefer.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: assocs kernel math math.order math.ranges mirrors USING: assocs kernel math math.order math.ranges mirrors
namespaces sequences sorting ; namespaces sequences sequences.lib sorting ;
IN: math.combinatorics IN: math.combinatorics
<PRIVATE <PRIVATE
@ -27,9 +27,6 @@ IN: math.combinatorics
: permutation-indices ( n seq -- permutation ) : permutation-indices ( n seq -- permutation )
length [ factoradic ] dip 0 pad-left >permutation ; length [ factoradic ] dip 0 pad-left >permutation ;
: reorder ( seq indices -- seq )
[ [ over nth , ] each drop ] { } make ;
PRIVATE> PRIVATE>
: factorial ( n -- n! ) : factorial ( n -- n! )
@ -42,7 +39,7 @@ PRIVATE>
twiddle [ nPk ] keep factorial / ; twiddle [ nPk ] keep factorial / ;
: permutation ( n seq -- seq ) : permutation ( n seq -- seq )
tuck permutation-indices reorder ; tuck permutation-indices nths ;
: all-permutations ( seq -- seq ) : all-permutations ( seq -- seq )
[ [

View File

@ -1 +1,2 @@
Reginald Ford Reginald Ford
Eduardo Cavazos

View File

@ -1,9 +1,101 @@
USING: help.markup help.syntax ; USING: help.markup help.syntax math.functions ;
IN: math.derivatives IN: math.derivatives
HELP: derivative ( x function -- m ) HELP: derivative ( x function -- m )
{ $values { "x" "the x-position on the function" } { "function" "a differentiable function" } } { $values { "x" "a position on the function" } { "function" "a differentiable function" } }
{ $description "Finds the slope of the tangent line at the given x-position on the given function." } ; { $description
"Approximates the slope of the tangent line by using Ridders' "
"method of computing derivatives, from the chapter \"Accurate computation "
"of F'(x) and F'(x)F''(x)\", from \"Advances in Engineering Software, Vol. 4, pp. 75-76 ."
}
{ $examples
{ $example
"USING: math.derivatives prettyprint ;"
"[ sq ] 4 derivative ."
"8"
}
{ $notes
"For applied scientists, you may play with the settings "
"in the source file to achieve arbitrary accuracy. "
}
} ;
{ derivative-func } related-words HELP: (derivative) ( x function h err -- m )
{ $values
{ "x" "a position on the function" }
{ "function" "a differentiable function" }
{
"h" "distance between the points of the first secant line used for "
"approximation of the tangent. This distance will be divided "
"constantly, by " { $link con } ". See " { $link init-hh }
" for the code which enforces this. H should be .001 to .5 -- too "
"small can cause bad convergence. Also, h should be small enough "
"to give the correct sgn(f'(x)). In other words, if you're expecting "
"a positive derivative, make h small enough to give the same "
"when plugged into the academic limit definition of a derivative. "
"See " { $link update-hh } " for the code which performs this task."
}
{
"err" "maximum tolerance of increase in error. For example, if this "
"is set to 2.0, the program will terminate with its nearest answer "
"when the error multiplies by 2. See " { $link check-safe } " for "
"the enforcing code."
}
}
{ $description
"Approximates the slope of the tangent line by using Ridders' "
"method of computing derivatives, from the chapter \"Accurate computation "
"of F'(x) and F'(x)F''(x)\", from \"Advances in Engineering Software, "
"Vol. 4, pp. 75-76 ."
}
{ $examples
{ $example
"USING: math.derivatives prettyprint ;"
"[ sq ] 4 derivative ."
"8"
}
{ $notes
"For applied scientists, you may play with the settings "
"in the source file to achieve arbitrary accuracy. "
}
} ;
HELP: derivative-func ( function -- der )
{ $values { "func" "a differentiable function" } { "der" "the derivative" } }
{ $description
"Provides the derivative of the function. The implementation simply "
"attaches the " { $link derivative } " word to the end of the function."
}
{ $examples
{ $example
"USING: math.derivatives prettyprint ;"
"60 deg>rad [ sin ] derivative-func call ."
"0.5000000000000173"
}
{ $notes
"Without a heavy algebraic system, derivatives must be "
"approximated. With the current settings, there is a fair trade of "
"speed and accuracy; the first 12 digits "
"will always be correct with " { $link sin } " and " { $link cos }
". The following code performs a minumum and maximum error test."
{ $code
"USING: kernel math math.functions math.trig sequences sequences.lib ;"
"360"
"["
" deg>rad"
" [ [ sin ] derivative-func call ]"
" ! Note: the derivative of sin is cos"
" [ cos ]"
" bi - abs"
"] map minmax"
}
}
} ;
ARTICLE: "derivatives" "The Derivative Toolkit"
"A toolkit for computing the derivative of functions."
{ $subsection derivative }
{ $subsection derivative-func }
{ $subsection (derivative) } ;
ABOUT: "derivatives"

View File

@ -1,10 +1,123 @@
! Copyright © 2008 Reginald Keith Ford II
! Tool for computing the derivative of a function at a point USING: kernel continuations combinators sequences math
USING: kernel math math.points math.function-tools ; math.order math.ranges accessors float-arrays ;
IN: math.derivatives IN: math.derivatives
: small-amount ( -- n ) 1.0e-14 ; TUPLE: state x func h err i j errt fac hh ans a done ;
: some-more ( x -- y ) small-amount + ;
: some-less ( x -- y ) small-amount - ; : largest-float ( -- x ) HEX: 7fefffffffffffff bits>double ; foldable
: derivative ( x function -- m ) [ [ some-more ] dip eval ] [ [ some-less ] dip eval ] 2bi slope ; : ntab ( -- val ) 8 ;
: derivative-func ( function -- function ) [ derivative ] curry ; : con ( -- val ) 1.6 ;
: con2 ( -- val ) con con * ;
: big ( -- val ) largest-float ;
: safe ( -- val ) 2.0 ;
! Yes, this was ported from C code.
: a[i][i] ( state -- elt ) [ i>> ] [ i>> ] [ a>> ] tri nth nth ;
: a[j][i] ( state -- elt ) [ i>> ] [ j>> ] [ a>> ] tri nth nth ;
: a[j-1][i] ( state -- elt ) [ i>> ] [ j>> 1 - ] [ a>> ] tri nth nth ;
: a[j-1][i-1] ( state -- elt ) [ i>> 1 - ] [ j>> 1 - ] [ a>> ] tri nth nth ;
: a[i-1][i-1] ( state -- elt ) [ i>> 1 - ] [ i>> 1 - ] [ a>> ] tri nth nth ;
: check-h ( state -- state )
dup h>> 0 = [ "h must be nonzero in dfridr" throw ] when ;
: init-a ( state -- state ) ntab [ ntab <float-array> ] replicate >>a ;
: init-hh ( state -- state ) dup h>> >>hh ;
: init-err ( state -- state ) big >>err ;
: update-hh ( state -- state ) dup hh>> con / >>hh ;
: reset-fac ( state -- state ) con2 >>fac ;
: update-fac ( state -- state ) dup fac>> con2 * >>fac ;
! If error is decreased, save the improved answer
: error-decreased? ( state -- state ? ) [ ] [ errt>> ] [ err>> ] tri <= ;
: save-improved-answer ( state -- state )
dup err>> >>errt
dup a[j][i] >>ans ;
! If higher order is worse by a significant factor SAFE, then quit early.
: check-safe ( state -- state )
dup
[ [ a[i][i] ] [ a[i-1][i-1] ] bi - abs ] [ err>> safe * ] bi >=
[ t >>done ]
when ;
: x+hh ( state -- val ) [ x>> ] [ hh>> ] bi + ;
: x-hh ( state -- val ) [ x>> ] [ hh>> ] bi - ;
: limit-approx ( state -- val )
[
[ [ x+hh ] [ func>> ] bi call ]
[ [ x-hh ] [ func>> ] bi call ]
bi -
]
[ hh>> 2.0 * ]
bi / ;
: a[0][0]! ( state -- state )
{ [ ] [ limit-approx ] [ drop 0 ] [ drop 0 ] [ a>> ] } cleave nth set-nth ;
: a[0][i]! ( state -- state )
{ [ ] [ limit-approx ] [ i>> ] [ drop 0 ] [ a>> ] } cleave nth set-nth ;
: a[j-1][i]*fac ( state -- val ) [ a[j-1][i] ] [ fac>> ] bi * ;
: new-a[j][i] ( state -- val )
[ [ a[j-1][i]*fac ] [ a[j-1][i-1] ] bi - ]
[ fac>> 1.0 - ]
bi / ;
: a[j][i]! ( state -- state )
{ [ ] [ new-a[j][i] ] [ i>> ] [ j>> ] [ a>> ] } cleave nth set-nth ;
: update-errt ( state -- state )
dup
[ [ a[j][i] ] [ a[j-1][i] ] bi - abs ]
[ [ a[j][i] ] [ a[j-1][i-1] ] bi - abs ]
bi max
>>errt ;
: not-done? ( state -- state ? ) dup done>> not ;
: derive ( state -- state )
init-a
check-h
init-hh
a[0][0]!
init-err
1 ntab [a,b)
[
>>i
not-done?
[
update-hh
a[0][i]!
reset-fac
1 over i>> [a,b]
[
>>j
a[j][i]!
update-fac
update-errt
error-decreased? [ save-improved-answer ] when
]
each
check-safe
]
when
]
each ;
: derivative-state ( x func h err -- state )
state new
swap >>err
swap >>h
swap >>func
swap >>x ;
! For scientists:
! h should be .001 to .5 -- too small can cause bad convergence,
! h should be small enough to give the correct sgn(f'(x))
! err is the max tolerance of gain in error for a single iteration-
: (derivative) ( x func h err -- ans error )
derivative-state
derive
[ ans>> ]
[ errt>> ]
bi ;
: derivative ( x func -- m ) 0.01 2.0 (derivative) drop ;
: derivative-func ( func -- der ) [ derivative ] curry ;

View File

@ -3,7 +3,7 @@
USING: kernel math arrays sequences sequences.lib ; USING: kernel math arrays sequences sequences.lib ;
IN: math.function-tools IN: math.function-tools
: difference-func ( func func -- func ) [ bi - ] 2curry ; : difference-func ( func func -- func ) [ bi - ] 2curry ; inline
: eval ( x func -- pt ) dupd call 2array ; : eval ( x func -- pt ) dupd call 2array ; inline
: eval-inverse ( y func -- pt ) dupd call swap 2array ; : eval-inverse ( y func -- pt ) dupd call swap 2array ; inline
: eval3d ( x y func -- pt ) [ 2dup ] dip call 3array ; : eval3d ( x y func -- pt ) [ 2dup ] dip call 3array ; inline

View File

@ -211,8 +211,11 @@ PRIVATE>
: insert-nth ( elt n seq -- seq' ) : insert-nth ( elt n seq -- seq' )
swap cut-slice [ swap 1array ] dip 3append ; swap cut-slice [ swap 1array ] dip 3append ;
: if-seq ( seq quot1 quot2 -- ) : if-seq ( seq quot1 quot2 -- ) [ f like ] 2dip if* ; inline
[ f like ] 2dip if* ; inline
: if-empty ( seq quot1 quot2 -- ) swap if-seq ; inline
: when-empty ( seq quot1 -- ) [ ] if-empty ; inline
: unless-empty ( seq quot1 -- ) [ ] swap if-empty ; inline
: if-empty ( seq quot1 quot2 -- )
swap if-seq ; inline

1
extra/serial/authors.txt Normal file
View File

@ -0,0 +1 @@
Doug Coleman

View File

@ -0,0 +1,23 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien.c-types assocs combinators destructors
kernel math math.bitfields math.parser sequences summary system
vocabs.loader ;
IN: serial
TUPLE: serial stream path baud
termios iflag oflag cflag lflag ;
ERROR: invalid-baud baud ;
M: invalid-baud summary ( invalid-baud -- string )
"Baud rate "
swap baud>> number>string
" not supported" 3append ;
HOOK: lookup-baud os ( m -- n )
HOOK: open-serial os ( serial -- serial' )
M: serial dispose ( serial -- ) stream>> dispose ;
{
{ [ os unix? ] [ "serial.unix" ] }
} cond require

1
extra/serial/summary.txt Normal file
View File

@ -0,0 +1 @@
Serial port library

1
extra/serial/tags.txt Normal file
View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1,86 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien.syntax kernel math.bitfields sequences system serial ;
IN: serial.unix
M: bsd lookup-baud ( m -- n )
dup {
0 50 75 110 134 150 200 300 600 1200 1800 2400 4800
7200 9600 14400 19200 28800 38400 57600 76800 115200
230400 460800 921600
} member? [ invalid-baud ] unless ;
: TCSANOW 0 ; inline
: TCSADRAIN 1 ; inline
: TCSAFLUSH 2 ; inline
: TCSASOFT HEX: 10 ; inline
: TCIFLUSH 1 ; inline
: TCOFLUSH 2 ; inline
: TCIOFLUSH 3 ; inline
: TCOOFF 1 ; inline
: TCOON 2 ; inline
: TCIOFF 3 ; inline
: TCION 4 ; inline
! iflags
: IGNBRK HEX: 00000001 ; inline
: BRKINT HEX: 00000002 ; inline
: IGNPAR HEX: 00000004 ; inline
: PARMRK HEX: 00000008 ; inline
: INPCK HEX: 00000010 ; inline
: ISTRIP HEX: 00000020 ; inline
: INLCR HEX: 00000040 ; inline
: IGNCR HEX: 00000080 ; inline
: ICRNL HEX: 00000100 ; inline
: IXON HEX: 00000200 ; inline
: IXOFF HEX: 00000400 ; inline
: IXANY HEX: 00000800 ; inline
: IMAXBEL HEX: 00002000 ; inline
: IUTF8 HEX: 00004000 ; inline
! oflags
: OPOST HEX: 00000001 ; inline
: ONLCR HEX: 00000002 ; inline
: OXTABS HEX: 00000004 ; inline
: ONOEOT HEX: 00000008 ; inline
! cflags
: CIGNORE HEX: 00000001 ; inline
: CSIZE HEX: 00000300 ; inline
: CS5 HEX: 00000000 ; inline
: CS6 HEX: 00000100 ; inline
: CS7 HEX: 00000200 ; inline
: CS8 HEX: 00000300 ; inline
: CSTOPB HEX: 00000400 ; inline
: CREAD HEX: 00000800 ; inline
: PARENB HEX: 00001000 ; inline
: PARODD HEX: 00002000 ; inline
: HUPCL HEX: 00004000 ; inline
: CLOCAL HEX: 00008000 ; inline
: CCTS_OFLOW HEX: 00010000 ; inline
: CRTS_IFLOW HEX: 00020000 ; inline
: CRTSCTS { CCTS_OFLOW CRTS_IFLOW } flags ; inline
: CDTR_IFLOW HEX: 00040000 ; inline
: CDSR_OFLOW HEX: 00080000 ; inline
: CCAR_OFLOW HEX: 00100000 ; inline
: MDMBUF HEX: 00100000 ; inline
! lflags
: ECHOKE HEX: 00000001 ; inline
: ECHOE HEX: 00000002 ; inline
: ECHOK HEX: 00000004 ; inline
: ECHO HEX: 00000008 ; inline
: ECHONL HEX: 00000010 ; inline
: ECHOPRT HEX: 00000020 ; inline
: ECHOCTL HEX: 00000040 ; inline
: ISIG HEX: 00000080 ; inline
: ICANON HEX: 00000100 ; inline
: ALTWERASE HEX: 00000200 ; inline
: IEXTEN HEX: 00000400 ; inline
: EXTPROC HEX: 00000800 ; inline
: TOSTOP HEX: 00400000 ; inline
: FLUSHO HEX: 00800000 ; inline
: NOKERNINFO HEX: 02000000 ; inline
: PENDIN HEX: 20000000 ; inline
: NOFLSH HEX: 80000000 ; inline

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1,130 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: assocs alien.syntax kernel serial system unix ;
IN: serial.unix
: TCSANOW 0 ; inline
: TCSADRAIN 1 ; inline
: TCSAFLUSH 2 ; inline
: TCIFLUSH 0 ; inline
: TCOFLUSH 1 ; inline
: TCIOFLUSH 2 ; inline
: TCOOFF 0 ; inline
: TCOON 1 ; inline
: TCIOFF 2 ; inline
: TCION 3 ; inline
! iflag
: IGNBRK OCT: 0000001 ; inline
: BRKINT OCT: 0000002 ; inline
: IGNPAR OCT: 0000004 ; inline
: PARMRK OCT: 0000010 ; inline
: INPCK OCT: 0000020 ; inline
: ISTRIP OCT: 0000040 ; inline
: INLCR OCT: 0000100 ; inline
: IGNCR OCT: 0000200 ; inline
: ICRNL OCT: 0000400 ; inline
: IUCLC OCT: 0001000 ; inline
: IXON OCT: 0002000 ; inline
: IXANY OCT: 0004000 ; inline
: IXOFF OCT: 0010000 ; inline
: IMAXBEL OCT: 0020000 ; inline
: IUTF8 OCT: 0040000 ; inline
! oflag
: OPOST OCT: 0000001 ; inline
: OLCUC OCT: 0000002 ; inline
: ONLCR OCT: 0000004 ; inline
: OCRNL OCT: 0000010 ; inline
: ONOCR OCT: 0000020 ; inline
: ONLRET OCT: 0000040 ; inline
: OFILL OCT: 0000100 ; inline
: OFDEL OCT: 0000200 ; inline
: NLDLY OCT: 0000400 ; inline
: NL0 OCT: 0000000 ; inline
: NL1 OCT: 0000400 ; inline
: CRDLY OCT: 0003000 ; inline
: CR0 OCT: 0000000 ; inline
: CR1 OCT: 0001000 ; inline
: CR2 OCT: 0002000 ; inline
: CR3 OCT: 0003000 ; inline
: TABDLY OCT: 0014000 ; inline
: TAB0 OCT: 0000000 ; inline
: TAB1 OCT: 0004000 ; inline
: TAB2 OCT: 0010000 ; inline
: TAB3 OCT: 0014000 ; inline
: BSDLY OCT: 0020000 ; inline
: BS0 OCT: 0000000 ; inline
: BS1 OCT: 0020000 ; inline
: FFDLY OCT: 0100000 ; inline
: FF0 OCT: 0000000 ; inline
: FF1 OCT: 0100000 ; inline
! cflags
: CSIZE OCT: 0000060 ; inline
: CS5 OCT: 0000000 ; inline
: CS6 OCT: 0000020 ; inline
: CS7 OCT: 0000040 ; inline
: CS8 OCT: 0000060 ; inline
: CSTOPB OCT: 0000100 ; inline
: CREAD OCT: 0000200 ; inline
: PARENB OCT: 0000400 ; inline
: PARODD OCT: 0001000 ; inline
: HUPCL OCT: 0002000 ; inline
: CLOCAL OCT: 0004000 ; inline
: CIBAUD OCT: 002003600000 ; inline
: CRTSCTS OCT: 020000000000 ; inline
! lflags
: ISIG OCT: 0000001 ; inline
: ICANON OCT: 0000002 ; inline
: XCASE OCT: 0000004 ; inline
: ECHO OCT: 0000010 ; inline
: ECHOE OCT: 0000020 ; inline
: ECHOK OCT: 0000040 ; inline
: ECHONL OCT: 0000100 ; inline
: NOFLSH OCT: 0000200 ; inline
: TOSTOP OCT: 0000400 ; inline
: ECHOCTL OCT: 0001000 ; inline
: ECHOPRT OCT: 0002000 ; inline
: ECHOKE OCT: 0004000 ; inline
: FLUSHO OCT: 0010000 ; inline
: PENDIN OCT: 0040000 ; inline
: IEXTEN OCT: 0100000 ; inline
M: linux lookup-baud ( n -- n )
dup H{
{ 0 OCT: 0000000 }
{ 50 OCT: 0000001 }
{ 75 OCT: 0000002 }
{ 110 OCT: 0000003 }
{ 134 OCT: 0000004 }
{ 150 OCT: 0000005 }
{ 200 OCT: 0000006 }
{ 300 OCT: 0000007 }
{ 600 OCT: 0000010 }
{ 1200 OCT: 0000011 }
{ 1800 OCT: 0000012 }
{ 2400 OCT: 0000013 }
{ 4800 OCT: 0000014 }
{ 9600 OCT: 0000015 }
{ 19200 OCT: 0000016 }
{ 38400 OCT: 0000017 }
{ 57600 OCT: 0010001 }
{ 115200 OCT: 0010002 }
{ 230400 OCT: 0010003 }
{ 460800 OCT: 0010004 }
{ 500000 OCT: 0010005 }
{ 576000 OCT: 0010006 }
{ 921600 OCT: 0010007 }
{ 1000000 OCT: 0010010 }
{ 1152000 OCT: 0010011 }
{ 1500000 OCT: 0010012 }
{ 2000000 OCT: 0010013 }
{ 2500000 OCT: 0010014 }
{ 3000000 OCT: 0010015 }
{ 3500000 OCT: 0010016 }
{ 4000000 OCT: 0010017 }
} at* [ nip ] [ drop invalid-baud ] if ;

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1,19 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien.syntax kernel sequences system ;
IN: serial.unix.termios
: NCCS 20 ; inline
TYPEDEF: uint tcflag_t
TYPEDEF: uchar cc_t
TYPEDEF: uint speed_t
C-STRUCT: termios
{ "tcflag_t" "iflag" } ! input mode flags
{ "tcflag_t" "oflag" } ! output mode flags
{ "tcflag_t" "cflag" } ! control mode flags
{ "tcflag_t" "lflag" } ! local mode flags
{ { "cc_t" NCCS } "cc" } ! control characters
{ "speed_t" "ispeed" } ! input speed
{ "speed_t" "ospeed" } ; ! output speed

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1,20 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien.syntax kernel system unix ;
IN: serial.unix.termios
: NCCS 32 ; inline
TYPEDEF: uchar cc_t
TYPEDEF: uint speed_t
TYPEDEF: uint tcflag_t
C-STRUCT: termios
{ "tcflag_t" "iflag" } ! input mode flags
{ "tcflag_t" "oflag" } ! output mode flags
{ "tcflag_t" "cflag" } ! control mode flags
{ "tcflag_t" "lflag" } ! local mode flags
{ "cc_t" "line" } ! line discipline
{ { "cc_t" NCCS } "cc" } ! control characters
{ "speed_t" "ispeed" } ! input speed
{ "speed_t" "ospeed" } ; ! output speed

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1 @@
unportable

View File

@ -0,0 +1,9 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: combinators system vocabs.loader ;
IN: serial.unix.termios
{
{ [ os linux? ] [ "serial.unix.termios.linux" ] }
{ [ os bsd? ] [ "serial.unix.termios.bsd" ] }
} cond require

View File

@ -0,0 +1,21 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel math.bitfields serial serial.unix ;
IN: serial.unix
: serial-obj ( -- obj )
serial new
"/dev/ttyS0" >>path
19200 >>baud
{ IGNPAR ICRNL } flags >>iflag
{ } flags >>oflag
{ CS8 CLOCAL CREAD } flags >>cflag
{ ICANON } flags >>lflag ;
: serial-test ( -- serial )
serial-obj
open-serial
dup get-termios >>termios
dup configure-termios
dup tciflush
dup apply-termios ;

View File

@ -0,0 +1,63 @@
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien.c-types alien.syntax combinators io.ports
io.streams.duplex io.unix.backend system kernel math math.bitfields
vocabs.loader unix serial serial.unix.termios ;
IN: serial.unix
<< {
{ [ os linux? ] [ "serial.unix.linux" ] }
{ [ os bsd? ] [ "serial.unix.bsd" ] }
} cond require >>
FUNCTION: speed_t cfgetispeed ( termios* t ) ;
FUNCTION: speed_t cfgetospeed ( termios* t ) ;
FUNCTION: int cfsetispeed ( termios* t, speed_t s ) ;
FUNCTION: int cfsetospeed ( termios* t, speed_t s ) ;
FUNCTION: int tcgetattr ( int i1, termios* t ) ;
FUNCTION: int tcsetattr ( int i1, int i2, termios* t ) ;
FUNCTION: int tcdrain ( int i1 ) ;
FUNCTION: int tcflow ( int i1, int i2 ) ;
FUNCTION: int tcflush ( int i1, int i2 ) ;
FUNCTION: int tcsendbreak ( int i1, int i2 ) ;
FUNCTION: void cfmakeraw ( termios* t ) ;
FUNCTION: int cfsetspeed ( termios* t, speed_t s ) ;
: fd>duplex-stream ( fd -- duplex-stream )
<fd> init-fd
[ <input-port> ] [ <output-port> ] bi <duplex-stream> ;
: open-rw ( path -- fd ) O_RDWR file-mode open-file ;
: <file-rw> ( path -- stream ) open-rw fd>duplex-stream ;
M: unix open-serial ( serial -- serial' )
dup
path>> { O_RDWR O_NOCTTY O_NDELAY } flags file-mode open-file
fd>duplex-stream >>stream ;
: serial-fd ( serial -- fd )
stream>> in>> handle>> fd>> ;
: get-termios ( serial -- termios )
serial-fd
"termios" <c-object> [ tcgetattr io-error ] keep ;
: configure-termios ( serial -- )
dup termios>>
{
[ [ iflag>> ] dip over [ set-termios-iflag ] [ 2drop ] if ]
[ [ oflag>> ] dip over [ set-termios-oflag ] [ 2drop ] if ]
[
[
[ cflag>> 0 or ] [ baud>> lookup-baud ] bi bitor
] dip set-termios-cflag
]
[ [ lflag>> ] dip over [ set-termios-lflag ] [ 2drop ] if ]
} 2cleave ;
: tciflush ( serial -- )
serial-fd TCIFLUSH tcflush io-error ;
: apply-termios ( serial -- )
[ serial-fd TCSANOW ]
[ termios>> ] bi tcsetattr io-error ;

View File

@ -0,0 +1,4 @@
IN: compiler.cfg.builder.tests
USING: compiler.cfg.builder tools.test ;
\ build-cfg must-infer

View File

@ -1,29 +1,33 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: arrays kernel assocs sequences sequences.lib fry accessors USING: arrays kernel assocs sequences sequences.lib fry accessors
compiler.cfg compiler.vops compiler.vops.builder namespaces math combinators math.order
namespaces math inference.dataflow optimizer.allot combinators compiler.tree
math.order ; compiler.tree.combinators
compiler.tree.propagation.info
compiler.cfg
compiler.vops
compiler.vops.builder ;
IN: compiler.cfg.builder IN: compiler.cfg.builder
! Convert dataflow IR to procedure CFG. ! Convert tree SSA IR to CFG SSA IR.
! We construct the graph and set successors first, then we ! We construct the graph and set successors first, then we
! set predecessors in a separate pass. This simplifies the ! set predecessors in a separate pass. This simplifies the
! logic. ! logic.
SYMBOL: procedures SYMBOL: procedures
SYMBOL: values>vregs
SYMBOL: loop-nesting SYMBOL: loop-nesting
GENERIC: convert* ( node -- ) SYMBOL: values>vregs
GENERIC: convert ( node -- ) GENERIC: convert ( node -- )
M: #introduce convert drop ;
: init-builder ( -- ) : init-builder ( -- )
H{ } clone values>vregs set H{ } clone values>vregs set ;
V{ } clone loop-nesting set ;
: end-basic-block ( -- ) : end-basic-block ( -- )
basic-block get [ %b emit ] when ; basic-block get [ %b emit ] when ;
@ -40,15 +44,12 @@ GENERIC: convert ( node -- )
set-basic-block ; set-basic-block ;
: convert-nodes ( node -- ) : convert-nodes ( node -- )
dup basic-block get and [ [ convert ] each ;
[ convert ] [ successor>> convert-nodes ] bi
] [ drop ] if ;
: (build-cfg) ( node word -- ) : (build-cfg) ( node word -- )
init-builder init-builder
begin-basic-block begin-basic-block
basic-block get swap procedures get set-at basic-block get swap procedures get set-at
%prolog emit
convert-nodes ; convert-nodes ;
: build-cfg ( node word -- procedures ) : build-cfg ( node word -- procedures )
@ -73,10 +74,9 @@ GENERIC: convert ( node -- )
2bi 2bi
] if ; ] if ;
: load-inputs ( node -- ) : load-in-d ( node -- ) in-d>> %data (load-inputs) ;
[ in-d>> %data (load-inputs) ]
[ in-r>> %retain (load-inputs) ] : load-in-r ( node -- ) in-r>> %retain (load-inputs) ;
bi ;
: (store-outputs) ( seq stack -- ) : (store-outputs) ( seq stack -- )
over empty? [ 2drop ] [ over empty? [ 2drop ] [
@ -86,40 +86,21 @@ GENERIC: convert ( node -- )
2bi 2bi
] if ; ] if ;
: store-outputs ( node -- ) : store-out-d ( node -- ) out-d>> %data (store-outputs) ;
[ out-d>> %data (store-outputs) ]
[ out-r>> %retain (store-outputs) ]
bi ;
M: #push convert* : store-out-r ( node -- ) out-r>> %retain (store-outputs) ;
out-d>> [
[ produce-vreg ] [ value-literal ] bi
emit-literal
] each ;
M: #shuffle convert* drop ;
M: #>r convert* drop ;
M: #r> convert* drop ;
M: node convert
[ load-inputs ]
[ convert* ]
[ store-outputs ]
tri ;
: (emit-call) ( word -- ) : (emit-call) ( word -- )
begin-basic-block %call emit begin-basic-block ; begin-basic-block %call emit begin-basic-block ;
: intrinsic-inputs ( node -- ) : intrinsic-inputs ( node -- )
[ load-inputs ] [ load-in-d ]
[ in-d>> { #1 #2 #3 #4 } [ [ value>vreg ] dip set ] 2each ] [ in-d>> { #1 #2 #3 #4 } [ [ value>vreg ] dip set ] 2each ]
bi ; bi ;
: intrinsic-outputs ( node -- ) : intrinsic-outputs ( node -- )
[ out-d>> { ^1 ^2 ^3 ^4 } [ get output-vreg ] 2each ] [ out-d>> { ^1 ^2 ^3 ^4 } [ get output-vreg ] 2each ]
[ store-outputs ] [ store-out-d ]
bi ; bi ;
: intrinsic ( node quot -- ) : intrinsic ( node quot -- )
@ -132,19 +113,17 @@ M: node convert
tri tri
] with-scope ; inline ] with-scope ; inline
USING: kernel.private math.private slots.private USING: kernel.private math.private slots.private ;
optimizer.allot ;
: maybe-emit-fixnum-shift-fast ( node -- node ) : maybe-emit-fixnum-shift-fast ( node -- node )
dup dup in-d>> second node-literal? [ dup dup in-d>> second node-value-info literal>> dup fixnum? [
dup dup in-d>> second node-literal
'[ , emit-fixnum-shift-fast ] intrinsic '[ , emit-fixnum-shift-fast ] intrinsic
] [ ] [
dup param>> (emit-call) drop dup word>> (emit-call)
] if ; ] if ;
: emit-call ( node -- ) : emit-call ( node -- )
dup param>> { dup word>> {
{ \ tag [ [ emit-tag ] intrinsic ] } { \ tag [ [ emit-tag ] intrinsic ] }
{ \ slot [ [ dup emit-slot ] intrinsic ] } { \ slot [ [ dup emit-slot ] intrinsic ] }
@ -175,24 +154,43 @@ optimizer.allot ;
{ \ float> [ [ emit-float> ] intrinsic ] } { \ float> [ [ emit-float> ] intrinsic ] }
{ \ float? [ [ emit-float= ] intrinsic ] } { \ float? [ [ emit-float= ] intrinsic ] }
{ \ (tuple) [ dup first-input '[ , emit-(tuple) ] intrinsic ] } ! { \ (tuple) [ dup first-input '[ , emit-(tuple) ] intrinsic ] }
{ \ (array) [ dup first-input '[ , emit-(array) ] intrinsic ] } ! { \ (array) [ dup first-input '[ , emit-(array) ] intrinsic ] }
{ \ (byte-array) [ dup first-input '[ , emit-(byte-array) ] intrinsic ] } ! { \ (byte-array) [ dup first-input '[ , emit-(byte-array) ] intrinsic ] }
[ (emit-call) ] [ (emit-call) ]
} case drop ; } case drop ;
M: #call convert emit-call ; M: #call convert emit-call ;
M: #call-label convert : emit-call-loop ( #recursive -- )
dup param>> loop-nesting get at [ dup label>> loop-nesting get at basic-block get successors>> push
basic-block get successors>> push end-basic-block
end-basic-block basic-block off
basic-block off drop ;
drop
] [ : emit-call-recursive ( #recursive -- )
(emit-call) label>> id>> (emit-call) ;
] if* ;
M: #call-recursive convert
dup label>> loop?>>
[ emit-call-loop ] [ emit-call-recursive ] if ;
M: #push convert
[
[ out-d>> first produce-vreg ]
[ node-output-infos first literal>> ]
bi emit-literal
]
[ store-out-d ] bi ;
M: #shuffle convert [ load-in-d ] [ store-out-d ] bi ;
M: #>r convert [ load-in-d ] [ store-out-r ] bi ;
M: #r> convert [ load-in-r ] [ store-out-d ] bi ;
M: #terminate convert drop ;
: integer-conditional ( in1 in2 cc -- ) : integer-conditional ( in1 in2 cc -- )
[ [ next-vreg dup ] 2dip %icmp emit ] dip %bi emit ; inline [ [ next-vreg dup ] 2dip %icmp emit ] dip %bi emit ; inline
@ -221,50 +219,38 @@ M: #call-label convert
[ set-basic-block ] [ set-basic-block ]
bi ; bi ;
: phi-inputs ( #if -- vregs-seq )
children>>
[ last-node ] map
[ #values? ] filter
[ in-d>> [ value>vreg ] map ] map ;
: phi-outputs ( #if -- vregs )
successor>> out-d>> [ produce-vreg ] map ;
: emit-phi ( #if -- )
[ phi-outputs ] [ phi-inputs ] bi %phi emit ;
M: #if convert M: #if convert
{ [ load-in-d ] [ emit-if ] [ convert-if-children ] tri ;
[ load-inputs ]
[ emit-if ]
[ convert-if-children ]
[ emit-phi ]
} cleave ;
M: #values convert drop ; M: #dispatch convert
"Unimplemented" throw ;
M: #merge convert drop ; M: #phi convert drop ;
M: #entry convert drop ;
M: #declare convert drop ; M: #declare convert drop ;
M: #terminate convert drop ; M: #return convert drop %return emit ;
M: #label convert : convert-recursive ( #recursive -- )
#! Labels create a new procedure. [ [ label>> id>> ] [ child>> ] bi (build-cfg) ]
[ [ param>> ] [ node-child ] bi (build-cfg) ] [ (emit-call) ] bi ; [ (emit-call) ]
bi ;
M: #loop convert : begin-loop ( #recursive -- )
#! Loops become part of the current CFG. label>> basic-block get 2array loop-nesting get push ;
begin-basic-block
[ param>> basic-block get 2array loop-nesting get push ] : end-loop ( -- )
[ node-child convert-nodes ]
bi
loop-nesting get pop* ; loop-nesting get pop* ;
M: #return convert : convert-loop ( #recursive -- )
param>> loop-nesting get key? [ begin-basic-block
%epilog emit [ begin-loop ]
%return emit [ child>> convert-nodes ]
] unless ; [ drop end-loop ]
tri ;
M: #recursive convert
dup label>> loop?>>
[ convert-loop ] [ convert-recursive ] if ;
M: #copy convert drop ;

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,16 @@
USING: help.syntax help.markup math kernel
words strings alien ;
IN: compiler.generator.fixup
HELP: frame-required
{ $values { "n" "a non-negative integer" } }
{ $description "Notify the code generator that the currently compiling code block needs a stack frame with room for at least " { $snippet "n" } " parameters." } ;
HELP: add-literal
{ $values { "obj" object } { "n" integer } }
{ $description "Adds a literal to the " { $link literal-table } ", if it is not already there, and outputs the index of the literal in the table. This literal can then be used as an argument for a " { $link rt-literal } " relocation with " { $link rel-fixup } "." } ;
HELP: rel-dlsym
{ $values { "name" string } { "dll" "a " { $link dll } " or " { $link f } } { "class" "a relocation class" } }
{ $description "Records that the most recently assembled instruction contains a reference to the " { $snippet "name" } " symbol from " { $snippet "dll" } ". The correct " { $snippet "class" } " to use depends on instruction formats."
} ;

View File

@ -0,0 +1,154 @@
! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays byte-arrays generic assocs hashtables io.binary
kernel kernel.private math namespaces sequences words
quotations strings alien.accessors alien.strings layouts system
combinators math.bitfields words.private cpu.architecture
math.order accessors growable ;
IN: compiler.generator.fixup
: no-stack-frame -1 ; inline
TUPLE: frame-required n ;
: frame-required ( n -- ) \ frame-required boa , ;
: stack-frame-size ( code -- n )
no-stack-frame [
dup frame-required? [ frame-required-n max ] [ drop ] if
] reduce ;
GENERIC: fixup* ( frame-size obj -- frame-size )
: code-format 22 getenv ;
: compiled-offset ( -- n ) building get length code-format * ;
TUPLE: label offset ;
: <label> ( -- label ) label new ;
M: label fixup*
compiled-offset swap set-label-offset ;
: define-label ( name -- ) <label> swap set ;
: resolve-label ( label/name -- ) dup label? [ get ] unless , ;
: if-stack-frame ( frame-size quot -- )
swap dup no-stack-frame =
[ 2drop ] [ stack-frame swap call ] if ; inline
M: word fixup*
{
{ \ %prologue-later [ dup [ %prologue ] if-stack-frame ] }
{ \ %epilogue-later [ dup [ %epilogue ] if-stack-frame ] }
} case ;
SYMBOL: relocation-table
SYMBOL: label-table
! Relocation classes
: rc-absolute-cell 0 ;
: rc-absolute 1 ;
: rc-relative 2 ;
: rc-absolute-ppc-2/2 3 ;
: rc-relative-ppc-2 4 ;
: rc-relative-ppc-3 5 ;
: rc-relative-arm-3 6 ;
: rc-indirect-arm 7 ;
: rc-indirect-arm-pc 8 ;
: rc-absolute? ( n -- ? )
dup rc-absolute-cell =
over rc-absolute =
rot rc-absolute-ppc-2/2 = or or ;
! Relocation types
: rt-primitive 0 ;
: rt-dlsym 1 ;
: rt-literal 2 ;
: rt-dispatch 3 ;
: rt-xt 4 ;
: rt-here 5 ;
: rt-label 6 ;
: rt-immediate 7 ;
TUPLE: label-fixup label class ;
: label-fixup ( label class -- ) \ label-fixup boa , ;
M: label-fixup fixup*
dup class>> rc-absolute?
[ "Absolute labels not supported" throw ] when
dup label>> swap class>> compiled-offset 4 - rot
3array label-table get push ;
TUPLE: rel-fixup arg class type ;
: rel-fixup ( arg class type -- ) \ rel-fixup boa , ;
: push-4 ( value vector -- )
[ length ] [ B{ 0 0 0 0 } swap push-all ] [ underlying>> ] tri
swap set-alien-unsigned-4 ;
M: rel-fixup fixup*
[ [ arg>> ] [ class>> ] [ type>> ] tri { 0 8 16 } bitfield ]
[ class>> rc-absolute-cell = cell 4 ? compiled-offset swap - ] bi
[ relocation-table get push-4 ] bi@ ;
M: frame-required fixup* drop ;
M: integer fixup* , ;
: adjoin* ( obj table -- n )
2dup swap [ eq? ] curry find drop
[ 2nip ] [ dup length >r push r> ] if* ;
SYMBOL: literal-table
: add-literal ( obj -- n ) literal-table get adjoin* ;
: add-dlsym-literals ( symbol dll -- )
>r string>symbol r> 2array literal-table get push-all ;
: rel-dlsym ( name dll class -- )
>r literal-table get length >r
add-dlsym-literals
r> r> rt-dlsym rel-fixup ;
: rel-word ( word class -- )
>r add-literal r> rt-xt rel-fixup ;
: rel-primitive ( word class -- )
>r def>> first r> rt-primitive rel-fixup ;
: rel-literal ( literal class -- )
>r add-literal r> rt-literal rel-fixup ;
: rel-this ( class -- )
0 swap rt-label rel-fixup ;
: rel-here ( class -- )
0 swap rt-here rel-fixup ;
: init-fixup ( -- )
BV{ } clone relocation-table set
V{ } clone label-table set ;
: resolve-labels ( labels -- labels' )
[
first3 label-offset
[ "Unresolved label" throw ] unless*
3array
] map concat ;
: fixup ( code -- literals relocation labels code )
[
init-fixup
dup stack-frame-size swap [ fixup* ] each drop
literal-table get >array
relocation-table get >byte-array
label-table get resolve-labels
] { } make ;

View File

@ -0,0 +1 @@
Support for generation of relocatable code

View File

@ -0,0 +1,88 @@
USING: help.markup help.syntax words debugger generator.fixup
generator.registers quotations kernel vectors arrays effects
sequences ;
IN: compiler.generator
ARTICLE: "generator" "Compiled code generator"
"Most of the words in the " { $vocab-link "generator" } " vocabulary are internal to the compiler and user code has no reason to call them."
$nl
"Debugging information can be enabled or disabled; this hook is used by " { $link "tools.deploy" } ":"
{ $subsection compiled-stack-traces? }
"Assembler intrinsics can be defined for low-level optimization:"
{ $subsection define-intrinsic }
{ $subsection define-intrinsics }
{ $subsection define-if-intrinsic }
{ $subsection define-if-intrinsics }
"The main entry point into the code generator:"
{ $subsection generate } ;
ABOUT: "generator"
HELP: compiled
{ $var-description "During compilation, holds a hashtable mapping words to 5-element arrays holding compiled code." } ;
HELP: compiling-word
{ $var-description "The word currently being compiled, set by " { $link with-generator } "." } ;
HELP: compiling-label
{ $var-description "The label currently being compiled, set by " { $link with-generator } "." } ;
HELP: compiled-stack-traces?
{ $values { "?" "a boolean" } }
{ $description "Iftrue, compiled code blocks will retain what word they were compiled from. This information is used by " { $link :c } " to display call stack traces after an error is thrown from compiled code. This is on by default; the deployment tool switches it off to save some space in the deployed image." } ;
HELP: literal-table
{ $var-description "Holds a vector of literal objects referenced from the currently compiling word. If " { $link compiled-stack-traces? } " is on, " { $link begin-compiling } " ensures that the first entry is the word being compiled." } ;
HELP: begin-compiling
{ $values { "word" word } { "label" word } }
{ $description "Prepares to generate machine code for a word." } ;
HELP: with-generator
{ $values { "node" "a dataflow node" } { "word" word } { "label" word } { "quot" "a quotation with stack effect " { $snippet "( node -- )" } } }
{ $description "Generates machine code for " { $snippet "label" } " by applying the quotation to the dataflow node." } ;
HELP: generate-node
{ $values { "node" "a dataflow node" } { "next" "a dataflow node" } }
{ $contract "Generates machine code for a dataflow node, and outputs the next node to generate machine code for." }
{ $notes "This word can only be called from inside the quotation passed to " { $link with-generator } "." } ;
HELP: generate-nodes
{ $values { "node" "a dataflow node" } }
{ $description "Recursively generate machine code for a dataflow graph." }
{ $notes "This word can only be called from inside the quotation passed to " { $link with-generator } "." } ;
HELP: generate
{ $values { "word" word } { "label" word } { "node" "a dataflow node" } }
{ $description "Generates machine code for " { $snippet "label" } " from " { $snippet "node" } ". The value of " { $snippet "word" } " is retained for debugging purposes; it is the word which will appear in a call stack trace if this compiled code block throws an error when run." } ;
HELP: define-intrinsics
{ $values { "word" word } { "intrinsics" "a sequence of " { $snippet "{ quot assoc }" } " pairs" } }
{ $description "Defines a set of assembly intrinsics for the word. When a call to the word is being compiled, each intrinsic is tested in turn; the first applicable one will be called to generate machine code. If no suitable intrinsic is found, a simple call to the word is compiled instead."
$nl
"See " { $link with-template } " for an explanation of the keys which may appear in " { $snippet "assoc" } "." } ;
HELP: define-intrinsic
{ $values { "word" word } { "quot" quotation } { "assoc" "an assoc" } }
{ $description "Defines an assembly intrinsic for the word. When a call to the word is being compiled, this intrinsic will be used if it is found to be applicable. If it is not applicable, a simple call to the word is compiled instead."
$nl
"See " { $link with-template } " for an explanation of the keys which may appear in " { $snippet "assoc" } "." } ;
HELP: if>boolean-intrinsic
{ $values { "quot" "a quotation with stack effect " { $snippet "( label -- )" } } }
{ $description "Generates code which pushes " { $link t } " or " { $link f } " on the data stack, depending on whether the quotation jumps to the label or not." } ;
HELP: define-if-intrinsics
{ $values { "word" word } { "intrinsics" "a sequence of " { $snippet "{ quot inputs }" } " pairs" } }
{ $description "Defines a set of conditional assembly intrinsics for the word, which must have a boolean value as its single output."
$nl
"The quotations must have stack effect " { $snippet "( label -- )" } "; they are required to branch to the label if the word evaluates to true."
$nl
"The " { $snippet "inputs" } " are in the same format as the " { $link +input+ } " key to " { $link with-template } "; a description can be found in the documentation for thatt word." }
{ $notes "Conditional intrinsics are used when the word is followed by a call to " { $link if } ". They allow for tighter code to be generated in certain situations; for example, if two integers are being compared and the result is immediately used to branch, the intermediate boolean does not need to be pushed at all." } ;
HELP: define-if-intrinsic
{ $values { "word" word } { "quot" "a quotation with stack effect " { $snippet "( label -- )" } } { "inputs" "a sequence of input register specifiers" } }
{ $description "Defines a conditional assembly intrinsic for the word, which must have a boolean value as its single output."
$nl
"See " { $link define-if-intrinsics } " for a description of the parameters." } ;

View File

@ -0,0 +1,584 @@
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs classes combinators
cpu.architecture effects generic hashtables io kernel
kernel.private layouts math math.parser namespaces prettyprint
quotations sequences system threads words vectors sets dequeues
cursors continuations.private summary alien alien.c-types
alien.structs alien.strings alien.arrays libc compiler.errors
stack-checker.inlining
compiler.tree compiler.tree.builder compiler.tree.combinators
compiler.tree.propagation.info compiler.generator.fixup
compiler.generator.registers compiler.generator.iterator ;
IN: compiler.generator
SYMBOL: compile-queue
SYMBOL: compiled
: queue-compile ( word -- )
{
{ [ dup "forgotten" word-prop ] [ ] }
{ [ dup compiled get key? ] [ ] }
{ [ dup inlined-block? ] [ ] }
{ [ dup primitive? ] [ ] }
[ dup compile-queue get push-front ]
} cond drop ;
: maybe-compile ( word -- )
dup compiled>> [ drop ] [ queue-compile ] if ;
SYMBOL: compiling-word
SYMBOL: compiling-label
SYMBOL: compiling-loops
! Label of current word, after prologue, makes recursion faster
SYMBOL: current-label-start
: compiled-stack-traces? ( -- ? ) 59 getenv ;
: begin-compiling ( word label -- )
H{ } clone compiling-loops set
compiling-label set
compiling-word set
compiled-stack-traces?
compiling-word get f ?
1vector literal-table set
f compiling-label get compiled get set-at ;
: save-machine-code ( literals relocation labels code -- )
4array compiling-label get compiled get set-at ;
: with-generator ( nodes word label quot -- )
[
>r begin-compiling r>
{ } make fixup
save-machine-code
] with-scope ; inline
GENERIC: generate-node ( node -- next )
: generate-nodes ( nodes -- )
[ current-node generate-node ] iterate-nodes end-basic-block ;
: init-generate-nodes ( -- )
init-templates
%save-word-xt
%prologue-later
current-label-start define-label
current-label-start resolve-label ;
: generate ( nodes word label -- )
[
init-generate-nodes
[ generate-nodes ] with-node-iterator
] with-generator ;
: intrinsics ( #call -- quot )
word>> "intrinsics" word-prop ;
: if-intrinsics ( #call -- quot )
word>> "if-intrinsics" word-prop ;
! node
M: node generate-node drop iterate-next ;
: %jump ( word -- )
dup compiling-label get eq?
[ drop current-label-start get ] [ %epilogue-later ] if
%jump-label ;
: generate-call ( label -- next )
dup maybe-compile
end-basic-block
dup compiling-loops get at [
%jump-label f
] [
tail-call? [
%jump f
] [
0 frame-required
%call
iterate-next
] if
] ?if ;
! #recursive
: compile-recursive ( node -- )
dup label>> id>> generate-call >r
[ child>> ] [ label>> word>> ] [ label>> id>> ] tri generate
r> ;
: compiling-loop ( word -- )
<label> dup resolve-label swap compiling-loops get set-at ;
: compile-loop ( node -- )
end-basic-block
[ label>> id>> compiling-loop ] [ child>> generate-nodes ] bi
iterate-next ;
M: #recursive generate-node
dup label>> loop?>> [ compile-loop ] [ compile-recursive ] if ;
! #if
: end-false-branch ( label -- )
tail-call? [ %return drop ] [ %jump-label ] if ;
: generate-branch ( nodes -- )
[ copy-templates generate-nodes ] with-scope ;
: generate-if ( node label -- next )
<label> [
>r >r children>> first2 swap generate-branch
r> r> end-false-branch resolve-label
generate-branch
init-templates
] keep resolve-label iterate-next ;
M: #if generate-node
[ <label> dup %jump-f ]
H{ { +input+ { { f "flag" } } } }
with-template
generate-if ;
! #dispatch
: dispatch-branch ( nodes word -- label )
gensym [
[
copy-templates
%save-dispatch-xt
%prologue-later
[ generate-nodes ] with-node-iterator
] with-generator
] keep ;
: dispatch-branches ( node -- )
children>> [
compiling-word get dispatch-branch
%dispatch-label
] each ;
: generate-dispatch ( node -- )
%dispatch dispatch-branches init-templates ;
M: #dispatch generate-node
#! The order here is important, dispatch-branches must
#! run after %dispatch, so that each branch gets the
#! correct register state
tail-call? [
generate-dispatch iterate-next
] [
compiling-word get gensym [
[
init-generate-nodes
generate-dispatch
] with-generator
] keep generate-call
] if ;
! #call
: define-intrinsics ( word intrinsics -- )
"intrinsics" set-word-prop ;
: define-intrinsic ( word quot assoc -- )
2array 1array define-intrinsics ;
: define-if>branch-intrinsics ( word intrinsics -- )
"if-intrinsics" set-word-prop ;
: if>boolean-intrinsic ( quot -- )
"false" define-label
"end" define-label
"false" get swap call
t "if-scratch" get load-literal
"end" get %jump-label
"false" resolve-label
f "if-scratch" get load-literal
"end" resolve-label
"if-scratch" get phantom-push ; inline
: define-if>boolean-intrinsics ( word intrinsics -- )
[
>r [ if>boolean-intrinsic ] curry r>
{ { f "if-scratch" } } +scratch+ associate assoc-union
] assoc-map "intrinsics" set-word-prop ;
: define-if-intrinsics ( word intrinsics -- )
[ +input+ associate ] assoc-map
2dup define-if>branch-intrinsics
define-if>boolean-intrinsics ;
: define-if-intrinsic ( word quot inputs -- )
2array 1array define-if-intrinsics ;
: do-if-intrinsic ( pair -- next )
<label> [
swap do-template
node> next dup >node
] keep generate-if ;
: find-intrinsic ( #call -- pair/f )
intrinsics find-template ;
: find-if-intrinsic ( #call -- pair/f )
node@ next #if? [
if-intrinsics find-template
] [
drop f
] if ;
M: #call generate-node
dup node-input-infos [ class>> ] map set-operand-classes
dup find-if-intrinsic [
do-if-intrinsic
] [
dup find-intrinsic [
do-template iterate-next
] [
word>> generate-call
] ?if
] ?if ;
! #call-recursive
M: #call-recursive generate-node label>> id>> generate-call ;
! #push
M: #push generate-node
literal>> <constant> phantom-push iterate-next ;
! #shuffle
M: #shuffle generate-node
shuffle-effect phantom-shuffle iterate-next ;
M: #>r generate-node
in-d>> length
phantom->r
iterate-next ;
M: #r> generate-node
out-d>> length
phantom-r>
iterate-next ;
! #return
M: #return generate-node
drop end-basic-block %return f ;
M: #return-recursive generate-node
end-basic-block
label>> id>> compiling-loops get key?
[ %return ] unless f ;
! #alien-invoke
: large-struct? ( ctype -- ? )
dup c-struct? [
heap-size struct-small-enough? not
] [ drop f ] if ;
: alien-parameters ( params -- seq )
dup parameters>>
swap return>> large-struct? [ "void*" prefix ] when ;
: alien-return ( params -- ctype )
return>> dup large-struct? [ drop "void" ] when ;
: c-type-stack-align ( type -- align )
dup c-type-stack-align? [ c-type-align ] [ drop cell ] if ;
: parameter-align ( n type -- n delta )
over >r c-type-stack-align align dup r> - ;
: parameter-sizes ( types -- total offsets )
#! Compute stack frame locations.
[
0 [
[ parameter-align drop dup , ] keep stack-size +
] reduce cell align
] { } make ;
: return-size ( ctype -- n )
#! Amount of space we reserve for a return value.
dup large-struct? [ heap-size ] [ drop 0 ] if ;
: alien-stack-frame ( params -- n )
alien-parameters parameter-sizes drop ;
: alien-invoke-frame ( params -- n )
#! One cell is temporary storage, temp@
dup return>> return-size
swap alien-stack-frame +
cell + ;
: set-stack-frame ( n -- )
dup [ frame-required ] when* \ stack-frame set ;
: with-stack-frame ( n quot -- )
swap set-stack-frame
call
f set-stack-frame ; inline
GENERIC: reg-size ( register-class -- n )
M: int-regs reg-size drop cell ;
M: single-float-regs reg-size drop 4 ;
M: double-float-regs reg-size drop 8 ;
GENERIC: reg-class-variable ( register-class -- symbol )
M: reg-class reg-class-variable ;
M: float-regs reg-class-variable drop float-regs ;
GENERIC: inc-reg-class ( register-class -- )
M: reg-class inc-reg-class
dup reg-class-variable inc
fp-shadows-int? [ reg-size stack-params +@ ] [ drop ] if ;
M: float-regs inc-reg-class
dup call-next-method
fp-shadows-int? [ reg-size cell /i int-regs +@ ] [ drop ] if ;
: reg-class-full? ( class -- ? )
[ reg-class-variable get ] [ param-regs length ] bi >= ;
: spill-param ( reg-class -- n reg-class )
stack-params get
>r reg-size stack-params +@ r>
stack-params ;
: fastcall-param ( reg-class -- n reg-class )
[ reg-class-variable get ] [ inc-reg-class ] [ ] tri ;
: alloc-parameter ( parameter -- reg reg-class )
c-type-reg-class dup reg-class-full?
[ spill-param ] [ fastcall-param ] if
[ param-reg ] keep ;
: (flatten-int-type) ( size -- )
cell /i "void*" c-type <repetition> % ;
GENERIC: flatten-value-type ( type -- )
M: object flatten-value-type , ;
M: struct-type flatten-value-type ( type -- )
stack-size cell align (flatten-int-type) ;
M: long-long-type flatten-value-type ( type -- )
stack-size cell align (flatten-int-type) ;
: flatten-value-types ( params -- params )
#! Convert value type structs to consecutive void*s.
[
0 [
c-type
[ parameter-align (flatten-int-type) ] keep
[ stack-size cell align + ] keep
flatten-value-type
] reduce drop
] { } make ;
: each-parameter ( parameters quot -- )
>r [ parameter-sizes nip ] keep r> 2each ; inline
: reverse-each-parameter ( parameters quot -- )
>r [ parameter-sizes nip ] keep r> 2reverse-each ; inline
: reset-freg-counts ( -- )
{ int-regs float-regs stack-params } [ 0 swap set ] each ;
: with-param-regs ( quot -- )
#! In quot you can call alloc-parameter
[ reset-freg-counts call ] with-scope ; inline
: move-parameters ( node word -- )
#! Moves values from C stack to registers (if word is
#! %load-param-reg) and registers to C stack (if word is
#! %save-param-reg).
>r
alien-parameters
flatten-value-types
r> [ >r alloc-parameter r> execute ] curry each-parameter ;
inline
: unbox-parameters ( offset node -- )
parameters>> [
%prepare-unbox >r over + r> unbox-parameter
] reverse-each-parameter drop ;
: prepare-box-struct ( node -- offset )
#! Return offset on C stack where to store unboxed
#! parameters. If the C function is returning a structure,
#! the first parameter is an implicit target area pointer,
#! so we need to use a different offset.
return>> dup large-struct?
[ heap-size %prepare-box-struct cell ] [ drop 0 ] if ;
: objects>registers ( params -- )
#! Generate code for unboxing a list of C types, then
#! generate code for moving these parameters to register on
#! architectures where parameters are passed in registers.
[
[ prepare-box-struct ] keep
[ unbox-parameters ] keep
\ %load-param-reg move-parameters
] with-param-regs ;
: box-return* ( node -- )
return>> [ ] [ box-return ] if-void ;
TUPLE: no-such-library name ;
M: no-such-library summary
drop "Library not found" ;
M: no-such-library compiler-error-type
drop +linkage+ ;
: no-such-library ( name -- )
\ no-such-library boa
compiling-word get compiler-error ;
TUPLE: no-such-symbol name ;
M: no-such-symbol summary
drop "Symbol not found" ;
M: no-such-symbol compiler-error-type
drop +linkage+ ;
: no-such-symbol ( name -- )
\ no-such-symbol boa
compiling-word get compiler-error ;
: check-dlsym ( symbols dll -- )
dup dll-valid? [
dupd [ dlsym ] curry contains?
[ drop ] [ no-such-symbol ] if
] [
dll-path no-such-library drop
] if ;
: stdcall-mangle ( symbol node -- symbol )
"@"
swap parameters>> parameter-sizes drop
number>string 3append ;
: alien-invoke-dlsym ( params -- symbols dll )
dup function>> dup pick stdcall-mangle 2array
swap library>> library dup [ dll>> ] when
2dup check-dlsym ;
M: #alien-invoke generate-node
params>>
dup alien-invoke-frame [
end-basic-block
%prepare-alien-invoke
dup objects>registers
%prepare-var-args
dup alien-invoke-dlsym %alien-invoke
dup %cleanup
box-return*
iterate-next
] with-stack-frame ;
! #alien-indirect
M: #alien-indirect generate-node
params>>
dup alien-invoke-frame [
! Flush registers
end-basic-block
! Save registers for GC
%prepare-alien-invoke
! Save alien at top of stack to temporary storage
%prepare-alien-indirect
dup objects>registers
%prepare-var-args
! Call alien in temporary storage
%alien-indirect
dup %cleanup
box-return*
iterate-next
] with-stack-frame ;
! #alien-callback
: box-parameters ( params -- )
alien-parameters [ box-parameter ] each-parameter ;
: registers>objects ( node -- )
[
dup \ %save-param-reg move-parameters
"nest_stacks" f %alien-invoke
box-parameters
] with-param-regs ;
TUPLE: callback-context ;
: current-callback 2 getenv ;
: wait-to-return ( token -- )
dup current-callback eq? [
drop
] [
yield wait-to-return
] if ;
: do-callback ( quot token -- )
init-catchstack
dup 2 setenv
slip
wait-to-return ; inline
: callback-return-quot ( ctype -- quot )
return>> {
{ [ dup "void" = ] [ drop [ ] ] }
{ [ dup large-struct? ] [ heap-size [ memcpy ] curry ] }
[ c-type c-type-unboxer-quot ]
} cond ;
: callback-prep-quot ( params -- quot )
parameters>> [ c-type c-type-boxer-quot ] map spread>quot ;
: wrap-callback-quot ( params -- quot )
[
[ callback-prep-quot ]
[ quot>> ]
[ callback-return-quot ] tri 3append ,
[ callback-context new do-callback ] %
] [ ] make ;
: %unnest-stacks ( -- ) "unnest_stacks" f %alien-invoke ;
: callback-unwind ( params -- n )
{
{ [ dup abi>> "stdcall" = ] [ alien-stack-frame ] }
{ [ dup return>> large-struct? ] [ drop 4 ] }
[ drop 0 ]
} cond ;
: %callback-return ( params -- )
#! All the extra book-keeping for %unwind is only for x86.
#! On other platforms its an alias for %return.
dup alien-return
[ %unnest-stacks ] [ %callback-value ] if-void
callback-unwind %unwind ;
: generate-callback ( params -- )
dup xt>> dup [
init-templates
%prologue-later
dup alien-stack-frame [
[ registers>objects ]
[ wrap-callback-quot %alien-callback ]
[ %callback-return ]
tri
] with-stack-frame
] with-generator ;
M: #alien-callback generate-node
end-basic-block
params>> generate-callback iterate-next ;

View File

@ -0,0 +1,41 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: namespaces sequences cursors kernel compiler.tree ;
IN: compiler.generator.iterator
SYMBOL: node-stack
: >node ( cursor -- ) node-stack get push ;
: node> ( -- cursor ) node-stack get pop ;
: node@ ( -- cursor ) node-stack get peek ;
: current-node ( -- node ) node@ value ;
: iterate-next ( -- cursor ) node@ next ;
: iterate-nodes ( cursor quot: ( -- ) -- )
over [
[ swap >node call node> drop ] keep iterate-nodes
] [
2drop
] if ; inline recursive
: with-node-iterator ( quot -- )
>r V{ } clone node-stack r> with-variable ; inline
DEFER: (tail-call?)
: tail-phi? ( cursor -- ? )
[ value #phi? ] [ next (tail-call?) ] bi and ;
: (tail-call?) ( cursor -- ? )
[ value [ #return? ] [ #terminate? ] bi or ]
[ tail-phi? ]
bi or ;
: tail-call? ( -- ? )
node-stack get [
next
[ (tail-call?) ]
[ value #terminate? not ]
bi and
] all? ;

View File

@ -0,0 +1 @@
Slava Pestov

View File

@ -0,0 +1,660 @@
! Copyright (C) 2006, 2007 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays assocs classes classes.private classes.algebra
combinators cpu.architecture generator.fixup hashtables kernel
layouts math namespaces quotations sequences system vectors
words effects alien byte-arrays
accessors sets math.order ;
IN: compiler.generator.registers
SYMBOL: +input+
SYMBOL: +output+
SYMBOL: +scratch+
SYMBOL: +clobber+
SYMBOL: known-tag
<PRIVATE
! Value protocol
GENERIC: set-operand-class ( class obj -- )
GENERIC: operand-class* ( operand -- class )
GENERIC: move-spec ( obj -- spec )
GENERIC: live-vregs* ( obj -- )
GENERIC: live-loc? ( actual current -- ? )
GENERIC# (lazy-load) 1 ( value spec -- value )
GENERIC: lazy-store ( dst src -- )
GENERIC: minimal-ds-loc* ( min obj -- min )
! This will be a multimethod soon
DEFER: %move
MIXIN: value
PRIVATE>
: operand-class ( operand -- class )
operand-class* object or ;
! Default implementation
M: value set-operand-class 2drop ;
M: value operand-class* drop f ;
M: value live-vregs* drop ;
M: value live-loc? 2drop f ;
M: value minimal-ds-loc* drop ;
M: value lazy-store 2drop ;
! A scratch register for computations
TUPLE: vreg n reg-class ;
C: <vreg> vreg ( n reg-class -- vreg )
M: vreg v>operand [ n>> ] [ reg-class>> ] bi vregs nth ;
M: vreg live-vregs* , ;
M: vreg move-spec reg-class>> move-spec ;
INSTANCE: vreg value
M: float-regs move-spec drop float ;
M: float-regs operand-class* drop float ;
! Temporary register for stack shuffling
SINGLETON: temp-reg
M: temp-reg move-spec drop f ;
INSTANCE: temp-reg value
! A data stack location.
TUPLE: ds-loc n class ;
: <ds-loc> ( n -- loc ) f ds-loc boa ;
M: ds-loc minimal-ds-loc* ds-loc-n min ;
M: ds-loc operand-class* ds-loc-class ;
M: ds-loc set-operand-class set-ds-loc-class ;
M: ds-loc live-loc?
over ds-loc? [ [ ds-loc-n ] bi@ = not ] [ 2drop t ] if ;
! A retain stack location.
TUPLE: rs-loc n class ;
: <rs-loc> ( n -- loc ) f rs-loc boa ;
M: rs-loc operand-class* rs-loc-class ;
M: rs-loc set-operand-class set-rs-loc-class ;
M: rs-loc live-loc?
over rs-loc? [ [ rs-loc-n ] bi@ = not ] [ 2drop t ] if ;
UNION: loc ds-loc rs-loc ;
M: loc move-spec drop loc ;
INSTANCE: loc value
M: f move-spec drop loc ;
M: f operand-class* ;
! A stack location which has been loaded into a register. To
! read the location, we just read the register, but when time
! comes to save it back to the stack, we know the register just
! contains a stack value so we don't have to redundantly write
! it back.
TUPLE: cached loc vreg ;
C: <cached> cached
M: cached set-operand-class cached-vreg set-operand-class ;
M: cached operand-class* cached-vreg operand-class* ;
M: cached move-spec drop cached ;
M: cached live-vregs* cached-vreg live-vregs* ;
M: cached live-loc? cached-loc live-loc? ;
M: cached (lazy-load) >r cached-vreg r> (lazy-load) ;
M: cached lazy-store
2dup cached-loc live-loc?
[ "live-locs" get at %move ] [ 2drop ] if ;
M: cached minimal-ds-loc* cached-loc minimal-ds-loc* ;
INSTANCE: cached value
! A tagged pointer
TUPLE: tagged vreg class ;
: <tagged> ( vreg -- tagged )
f tagged boa ;
M: tagged v>operand tagged-vreg v>operand ;
M: tagged set-operand-class set-tagged-class ;
M: tagged operand-class* tagged-class ;
M: tagged move-spec drop f ;
M: tagged live-vregs* tagged-vreg , ;
INSTANCE: tagged value
! Unboxed alien pointers
TUPLE: unboxed-alien vreg ;
C: <unboxed-alien> unboxed-alien
M: unboxed-alien v>operand unboxed-alien-vreg v>operand ;
M: unboxed-alien operand-class* drop simple-alien ;
M: unboxed-alien move-spec class ;
M: unboxed-alien live-vregs* unboxed-alien-vreg , ;
INSTANCE: unboxed-alien value
TUPLE: unboxed-byte-array vreg ;
C: <unboxed-byte-array> unboxed-byte-array
M: unboxed-byte-array v>operand unboxed-byte-array-vreg v>operand ;
M: unboxed-byte-array operand-class* drop c-ptr ;
M: unboxed-byte-array move-spec class ;
M: unboxed-byte-array live-vregs* unboxed-byte-array-vreg , ;
INSTANCE: unboxed-byte-array value
TUPLE: unboxed-f vreg ;
C: <unboxed-f> unboxed-f
M: unboxed-f v>operand unboxed-f-vreg v>operand ;
M: unboxed-f operand-class* drop \ f ;
M: unboxed-f move-spec class ;
M: unboxed-f live-vregs* unboxed-f-vreg , ;
INSTANCE: unboxed-f value
TUPLE: unboxed-c-ptr vreg ;
C: <unboxed-c-ptr> unboxed-c-ptr
M: unboxed-c-ptr v>operand unboxed-c-ptr-vreg v>operand ;
M: unboxed-c-ptr operand-class* drop c-ptr ;
M: unboxed-c-ptr move-spec class ;
M: unboxed-c-ptr live-vregs* unboxed-c-ptr-vreg , ;
INSTANCE: unboxed-c-ptr value
! A constant value
TUPLE: constant value ;
C: <constant> constant
M: constant operand-class* constant-value class ;
M: constant move-spec class ;
INSTANCE: constant value
<PRIVATE
! Moving values between locations and registers
: %move-bug ( -- * ) "Bug in generator.registers" throw ;
: %unbox-c-ptr ( dst src -- )
dup operand-class {
{ [ dup \ f class<= ] [ drop %unbox-f ] }
{ [ dup simple-alien class<= ] [ drop %unbox-alien ] }
{ [ dup byte-array class<= ] [ drop %unbox-byte-array ] }
[ drop %unbox-any-c-ptr ]
} cond ; inline
: %move-via-temp ( dst src -- )
#! For many transfers, such as loc to unboxed-alien, we
#! don't have an intrinsic, so we transfer the source to
#! temp then temp to the destination.
temp-reg over %move
operand-class temp-reg
tagged new
swap >>vreg
swap >>class
%move ;
: %move ( dst src -- )
2dup [ move-spec ] bi@ 2array {
{ { f f } [ %move-bug ] }
{ { f unboxed-c-ptr } [ %move-bug ] }
{ { f unboxed-byte-array } [ %move-bug ] }
{ { f constant } [ constant-value swap load-literal ] }
{ { f float } [ %box-float ] }
{ { f unboxed-alien } [ %box-alien ] }
{ { f loc } [ %peek ] }
{ { float f } [ %unbox-float ] }
{ { unboxed-alien f } [ %unbox-alien ] }
{ { unboxed-byte-array f } [ %unbox-byte-array ] }
{ { unboxed-f f } [ %unbox-f ] }
{ { unboxed-c-ptr f } [ %unbox-c-ptr ] }
{ { loc f } [ swap %replace ] }
[ drop %move-via-temp ]
} case ;
! A compile-time stack
TUPLE: phantom-stack height stack ;
M: phantom-stack clone
call-next-method [ clone ] change-stack ;
GENERIC: finalize-height ( stack -- )
: new-phantom-stack ( class -- stack )
>r 0 V{ } clone r> boa ; inline
: (loc) ( m stack -- n )
#! Utility for methods on <loc>
height>> - ;
: (finalize-height) ( stack word -- )
#! We consolidate multiple stack height changes until the
#! last moment, and we emit the final height changing
#! instruction here.
[
over zero? [ 2drop ] [ execute ] if 0
] curry change-height drop ; inline
GENERIC: <loc> ( n stack -- loc )
TUPLE: phantom-datastack < phantom-stack ;
: <phantom-datastack> ( -- stack )
phantom-datastack new-phantom-stack ;
M: phantom-datastack <loc> (loc) <ds-loc> ;
M: phantom-datastack finalize-height
\ %inc-d (finalize-height) ;
TUPLE: phantom-retainstack < phantom-stack ;
: <phantom-retainstack> ( -- stack )
phantom-retainstack new-phantom-stack ;
M: phantom-retainstack <loc> (loc) <rs-loc> ;
M: phantom-retainstack finalize-height
\ %inc-r (finalize-height) ;
: phantom-locs ( n phantom -- locs )
#! A sequence of n ds-locs or rs-locs indexing the stack.
>r <reversed> r> [ <loc> ] curry map ;
: phantom-locs* ( phantom -- locs )
[ stack>> length ] keep phantom-locs ;
: phantoms ( -- phantom phantom )
phantom-datastack get phantom-retainstack get ;
: (each-loc) ( phantom quot -- )
>r [ phantom-locs* ] [ stack>> ] bi r> 2each ; inline
: each-loc ( quot -- )
phantoms 2array swap [ (each-loc) ] curry each ; inline
: adjust-phantom ( n phantom -- )
swap [ + ] curry change-height drop ;
: cut-phantom ( n phantom -- seq )
swap [ cut* swap ] curry change-stack drop ;
: phantom-append ( seq stack -- )
over length over adjust-phantom stack>> push-all ;
: add-locs ( n phantom -- )
2dup stack>> length <= [
2drop
] [
[ phantom-locs ] keep
[ stack>> length head-slice* ] keep
[ append >vector ] change-stack drop
] if ;
: phantom-input ( n phantom -- seq )
2dup add-locs
2dup cut-phantom
>r >r neg r> adjust-phantom r> ;
: each-phantom ( quot -- ) phantoms rot bi@ ; inline
: finalize-heights ( -- ) [ finalize-height ] each-phantom ;
: live-vregs ( -- seq )
[ [ stack>> [ live-vregs* ] each ] each-phantom ] { } make ;
: (live-locs) ( phantom -- seq )
#! Discard locs which haven't moved
[ phantom-locs* ] [ stack>> ] bi zip
[ live-loc? ] assoc-filter
values ;
: live-locs ( -- seq )
[ (live-locs) ] each-phantom append prune ;
! Operands holding pointers to freshly-allocated objects which
! are guaranteed to be in the nursery
SYMBOL: fresh-objects
! Computing free registers and initializing allocator
: reg-spec>class ( spec -- class )
float eq? double-float-regs int-regs ? ;
: free-vregs ( reg-class -- seq )
#! Free vregs in a given register class
\ free-vregs get at ;
: alloc-vreg ( spec -- reg )
[ reg-spec>class free-vregs pop ] keep {
{ f [ <tagged> ] }
{ unboxed-alien [ <unboxed-alien> ] }
{ unboxed-byte-array [ <unboxed-byte-array> ] }
{ unboxed-f [ <unboxed-f> ] }
{ unboxed-c-ptr [ <unboxed-c-ptr> ] }
[ drop ]
} case ;
: compatible? ( value spec -- ? )
>r move-spec r> {
{ [ 2dup = ] [ t ] }
{ [ dup unboxed-c-ptr eq? ] [
over { unboxed-byte-array unboxed-alien } member?
] }
[ f ]
} cond 2nip ;
: allocation ( value spec -- reg-class )
{
{ [ dup quotation? ] [ 2drop f ] }
{ [ 2dup compatible? ] [ 2drop f ] }
[ nip reg-spec>class ]
} cond ;
: alloc-vreg-for ( value spec -- vreg )
alloc-vreg swap operand-class
over tagged? [ >>class ] [ drop ] if ;
M: value (lazy-load)
2dup allocation [
dupd alloc-vreg-for dup rot %move
] [
drop
] if ;
: (compute-free-vregs) ( used class -- vector )
#! Find all vregs in 'class' which are not in 'used'.
[ vregs length reverse ] keep
[ <vreg> ] curry map swap diff
>vector ;
: compute-free-vregs ( -- )
#! Create a new hashtable for thee free-vregs variable.
live-vregs
{ int-regs double-float-regs }
[ 2dup (compute-free-vregs) ] H{ } map>assoc
\ free-vregs set
drop ;
M: loc lazy-store
2dup live-loc? [ "live-locs" get at %move ] [ 2drop ] if ;
: do-shuffle ( hash -- )
dup assoc-empty? [
drop
] [
"live-locs" set
[ lazy-store ] each-loc
] if ;
: fast-shuffle ( locs -- )
#! We have enough free registers to load all shuffle inputs
#! at once
[ dup f (lazy-load) ] H{ } map>assoc do-shuffle ;
: minimal-ds-loc ( phantom -- n )
#! When shuffling more values than can fit in registers, we
#! need to find an area on the data stack which isn't in
#! use.
[ stack>> ] [ height>> neg ] bi [ minimal-ds-loc* ] reduce ;
: find-tmp-loc ( -- n )
#! Find an area of the data stack which is not referenced
#! from the phantom stacks. We can clobber there all we want
[ minimal-ds-loc ] each-phantom min 1- ;
: slow-shuffle-mapping ( locs tmp -- pairs )
>r dup length r>
[ swap - <ds-loc> ] curry map zip ;
: slow-shuffle ( locs -- )
#! We don't have enough free registers to load all shuffle
#! inputs, so we use a single temporary register, together
#! with the area of the data stack above the stack pointer
find-tmp-loc slow-shuffle-mapping [
[
swap dup cached? [ cached-vreg ] when %move
] assoc-each
] keep >hashtable do-shuffle ;
: fast-shuffle? ( live-locs -- ? )
#! Test if we have enough free registers to load all
#! shuffle inputs at once.
int-regs free-vregs [ length ] bi@ <= ;
: finalize-locs ( -- )
#! Perform any deferred stack shuffling.
[
\ free-vregs [ [ clone ] assoc-map ] change
live-locs dup fast-shuffle?
[ fast-shuffle ] [ slow-shuffle ] if
] with-scope ;
: finalize-vregs ( -- )
#! Store any vregs to their final stack locations.
[
dup loc? over cached? or [ 2drop ] [ %move ] if
] each-loc ;
: reset-phantom ( phantom -- )
#! Kill register assignments but preserve constants and
#! class information.
dup phantom-locs*
over stack>> [
dup constant? [ nip ] [
operand-class over set-operand-class
] if
] 2map
over stack>> delete-all
swap stack>> push-all ;
: reset-phantoms ( -- )
[ reset-phantom ] each-phantom ;
: finalize-contents ( -- )
finalize-locs finalize-vregs reset-phantoms ;
! Loading stacks to vregs
: free-vregs? ( int# float# -- ? )
double-float-regs free-vregs length <=
>r int-regs free-vregs length <= r> and ;
: phantom&spec ( phantom spec -- phantom' spec' )
>r stack>> r>
[ length f pad-left ] keep
[ <reversed> ] bi@ ; inline
: phantom&spec-agree? ( phantom spec quot -- ? )
>r phantom&spec r> 2all? ; inline
: vreg-substitution ( value vreg -- pair )
dupd <cached> 2array ;
: substitute-vreg? ( old new -- ? )
#! We don't substitute locs for float or alien vregs,
#! since in those cases the boxing overhead might kill us.
cached-vreg tagged? >r loc? r> and ;
: substitute-vregs ( values vregs -- )
[ vreg-substitution ] 2map
[ substitute-vreg? ] assoc-filter >hashtable
[ >r stack>> r> substitute-here ] curry each-phantom ;
: set-operand ( value var -- )
>r dup constant? [ constant-value ] when r> set ;
: lazy-load ( values template -- )
#! Set operand vars here.
2dup [ first (lazy-load) ] 2map
dup rot [ second set-operand ] 2each
substitute-vregs ;
: load-inputs ( -- )
+input+ get
[ length phantom-datastack get phantom-input ] keep
lazy-load ;
: output-vregs ( -- seq seq )
+output+ +clobber+ [ get [ get ] map ] bi@ ;
: clash? ( seq -- ? )
phantoms [ stack>> ] bi@ append [
dup cached? [ cached-vreg ] when swap member?
] with contains? ;
: outputs-clash? ( -- ? )
output-vregs append clash? ;
: count-vregs ( reg-classes -- ) [ [ inc ] when* ] each ;
: count-input-vregs ( phantom spec -- )
phantom&spec [
>r dup cached? [ cached-vreg ] when r> first allocation
] 2map count-vregs ;
: count-scratch-regs ( spec -- )
[ first reg-spec>class ] map count-vregs ;
: guess-vregs ( dinput rinput scratch -- int# float# )
[
0 int-regs set
0 double-float-regs set
count-scratch-regs
phantom-retainstack get swap count-input-vregs
phantom-datastack get swap count-input-vregs
int-regs get double-float-regs get
] with-scope ;
: alloc-scratch ( -- )
+scratch+ get [ >r alloc-vreg r> set ] assoc-each ;
: guess-template-vregs ( -- int# float# )
+input+ get { } +scratch+ get guess-vregs ;
: template-inputs ( -- )
! Load input values into registers
load-inputs
! Allocate scratch registers
alloc-scratch
! If outputs clash, we write values back to the stack
outputs-clash? [ finalize-contents ] when ;
: template-outputs ( -- )
+output+ get [ get ] map phantom-datastack get phantom-append ;
: value-matches? ( value spec -- ? )
#! If the spec is a quotation and the value is a literal
#! fixnum, see if the quotation yields true when applied
#! to the fixnum. Otherwise, the values don't match. If the
#! spec is not a quotation, its a reg-class, in which case
#! the value is always good.
dup quotation? [
over constant?
[ >r constant-value r> call ] [ 2drop f ] if
] [
2drop t
] if ;
: class-matches? ( actual expected -- ? )
{
{ f [ drop t ] }
{ known-tag [ dup [ class-tag >boolean ] when ] }
[ class<= ]
} case ;
: spec-matches? ( value spec -- ? )
2dup first value-matches?
>r >r operand-class 2 r> ?nth class-matches? r> and ;
: template-matches? ( spec -- ? )
phantom-datastack get +input+ rot at
[ spec-matches? ] phantom&spec-agree? ;
: ensure-template-vregs ( -- )
guess-template-vregs free-vregs? [
finalize-contents compute-free-vregs
] unless ;
: clear-phantoms ( -- )
[ stack>> delete-all ] each-phantom ;
PRIVATE>
: set-operand-classes ( classes -- )
phantom-datastack get
over length over add-locs
stack>> [ set-operand-class ] 2reverse-each ;
: end-basic-block ( -- )
#! Commit all deferred stacking shuffling, and ensure the
#! in-memory data and retain stacks are up to date with
#! respect to the compiler's current picture.
finalize-contents
clear-phantoms
finalize-heights
fresh-objects get [ empty? [ %gc ] unless ] [ delete-all ] bi ;
: with-template ( quot hash -- )
clone [
ensure-template-vregs
template-inputs call template-outputs
] bind
compute-free-vregs ; inline
: do-template ( pair -- )
#! Use with return value from find-template
first2 with-template ;
: fresh-object ( obj -- ) fresh-objects get push ;
: fresh-object? ( obj -- ? ) fresh-objects get memq? ;
: init-templates ( -- )
#! Initialize register allocator.
V{ } clone fresh-objects set
<phantom-datastack> phantom-datastack set
<phantom-retainstack> phantom-retainstack set
compute-free-vregs ;
: copy-templates ( -- )
#! Copies register allocator state, used when compiling
#! branches.
fresh-objects [ clone ] change
phantom-datastack [ clone ] change
phantom-retainstack [ clone ] change
compute-free-vregs ;
: find-template ( templates -- pair/f )
#! Pair has shape { quot hash }
[ second template-matches? ] find nip ;
: operand-tag ( operand -- tag/f )
operand-class dup [ class-tag ] when ;
UNION: immediate fixnum POSTPONE: f ;
: operand-immediate? ( operand -- ? )
operand-class immediate class<= ;
: phantom-push ( obj -- )
1 phantom-datastack get adjust-phantom
phantom-datastack get stack>> push ;
: phantom-shuffle ( shuffle -- )
[ effect-in length phantom-datastack get phantom-input ] keep
shuffle* phantom-datastack get phantom-append ;
: phantom->r ( n -- )
phantom-datastack get phantom-input
phantom-retainstack get phantom-append ;
: phantom-r> ( n -- )
phantom-retainstack get phantom-input
phantom-datastack get phantom-append ;

View File

@ -0,0 +1 @@
Register allocation and intrinsic selection

View File

@ -0,0 +1 @@
Final stage of compilation generates machine code from dataflow IR

View File

@ -0,0 +1 @@
compiler

View File

@ -1,12 +1,17 @@
! Copyright (C) 2008 Slava Pestov. ! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel namespaces sequences assocs io USING: accessors kernel namespaces sequences assocs io
prettyprint inference generator optimizer compiler.vops prettyprint inference generator optimizer
compiler.cfg.builder compiler.cfg.simplifier compiler.vops
compiler.machine.builder compiler.machine.simplifier ; compiler.tree.builder
IN: compiler.machine.debug compiler.tree.optimizer
compiler.cfg.builder
compiler.cfg.simplifier
compiler.machine.builder
compiler.machine.simplifier ;
IN: compiler.machine.debugger
: dataflow>linear ( dataflow word -- linear ) : tree>linear ( tree word -- linear )
[ [
init-counter init-counter
build-cfg build-cfg
@ -20,15 +25,16 @@ IN: compiler.machine.debug
] assoc-each ; ] assoc-each ;
: linearized-quot. ( quot -- ) : linearized-quot. ( quot -- )
dataflow optimize build-tree optimize-tree
"Anonymous quotation" dataflow>linear "Anonymous quotation" tree>linear
linear. ; linear. ;
: linearized-word. ( word -- ) : linearized-word. ( word -- )
dup word-dataflow nip optimize swap dataflow>linear linear. ; dup build-tree-from-word nip optimize-tree
dup word-dataflow nip optimize swap tree>linear linear. ;
: >basic-block ( quot -- basic-block ) : >basic-block ( quot -- basic-block )
dataflow optimize build-tree optimize-tree
[ [
init-counter init-counter
"Anonymous quotation" build-cfg "Anonymous quotation" build-cfg

View File

@ -35,6 +35,12 @@ M: #phi backward
[ [ out-r>> ] [ phi-in-r>> ] bi look-at-corresponding ] [ [ out-r>> ] [ phi-in-r>> ] bi look-at-corresponding ]
2bi ; 2bi ;
M: #alien-invoke backward
nip [ look-at-inputs ] [ look-at-outputs ] bi ;
M: #alien-indirect backward
nip [ look-at-inputs ] [ look-at-outputs ] bi ;
M: node backward 2drop ; M: node backward 2drop ;
: backward-dfa ( node quot -- assoc ) [ backward ] dfa ; inline : backward-dfa ( node quot -- assoc ) [ backward ] dfa ; inline

View File

@ -23,6 +23,12 @@ M: #call mark-live-values
dup word>> "flushable" word-prop dup word>> "flushable" word-prop
[ drop ] [ [ look-at-inputs ] [ look-at-outputs ] bi ] if ; [ drop ] [ [ look-at-inputs ] [ look-at-outputs ] bi ] if ;
M: #alien-invoke mark-live-values
[ look-at-inputs ] [ look-at-outputs ] bi ;
M: #alien-indirect mark-live-values
[ look-at-inputs ] [ look-at-outputs ] bi ;
M: #return mark-live-values M: #return mark-live-values
look-at-inputs ; look-at-inputs ;

View File

@ -0,0 +1,5 @@
IN: compiler.tree.debugger.tests
USING: compiler.tree.debugger tools.test ;
\ optimized. must-infer
\ optimizer-report. must-infer

View File

@ -0,0 +1,140 @@
! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel assocs fry match accessors namespaces effects
sequences sequences.private quotations generic macros arrays
prettyprint prettyprint.backend prettyprint.sections math words
combinators io sorting
compiler.tree
compiler.tree.builder
compiler.tree.optimizer
compiler.tree.combinators
compiler.tree.propagation.info ;
IN: compiler.tree.debugger
! A simple tool for turning tree IR into quotations and
! printing reports, for debugging purposes.
GENERIC: node>quot ( node -- )
MACRO: match-choose ( alist -- )
[ '[ , ] ] assoc-map '[ , match-cond ] ;
MATCH-VARS: ?a ?b ?c ;
: pretty-shuffle ( effect -- word/f )
[ in>> ] [ out>> ] bi 2array {
{ { { } { } } [ ] }
{ { { ?a } { ?a } } [ ] }
{ { { ?a ?b } { ?a ?b } } [ ] }
{ { { ?a ?b ?c } { ?a ?b ?c } } [ ] }
{ { { ?a } { } } [ drop ] }
{ { { ?a ?b } { } } [ 2drop ] }
{ { { ?a ?b ?c } { } } [ 3drop ] }
{ { { ?a } { ?a ?a } } [ dup ] }
{ { { ?a ?b } { ?a ?b ?a ?b } } [ 2dup ] }
{ { { ?a ?b ?c } { ?a ?b ?c ?a ?b ?c } } [ 3dup ] }
{ { { ?a ?b } { ?a ?b ?a } } [ over ] }
{ { { ?b ?a } { ?a ?b } } [ swap ] }
{ { { ?b ?a ?c } { ?a ?b ?c } } [ swapd ] }
{ { { ?a ?b } { ?a ?a ?b } } [ dupd ] }
{ { { ?a ?b } { ?b ?a ?b } } [ tuck ] }
{ { { ?a ?b ?c } { ?a ?b ?c ?a } } [ pick ] }
{ { { ?a ?b ?c } { ?c ?a ?b } } [ -rot ] }
{ { { ?a ?b ?c } { ?b ?c ?a } } [ rot ] }
{ { { ?a ?b } { ?b } } [ nip ] }
{ { { ?a ?b ?c } { ?c } } [ 2nip ] }
{ _ f }
} match-choose ;
TUPLE: shuffle effect ;
M: shuffle pprint* effect>> effect>string text ;
M: #shuffle node>quot
shuffle-effect dup pretty-shuffle
[ % ] [ shuffle boa , ] ?if ;
: pushed-literals ( node -- seq )
dup out-d>> [ node-value-info literal>> literalize ] with map ;
M: #push node>quot pushed-literals % ;
M: #call node>quot word>> , ;
M: #call-recursive node>quot label>> id>> , ;
DEFER: nodes>quot
DEFER: label
M: #recursive node>quot
[ label>> id>> literalize , ]
[ child>> nodes>quot , \ label , ]
bi ;
M: #if node>quot
children>> [ nodes>quot ] map % \ if , ;
M: #dispatch node>quot
children>> [ nodes>quot ] map , \ dispatch , ;
M: #>r node>quot in-d>> length \ >r <repetition> % ;
M: #r> node>quot out-d>> length \ r> <repetition> % ;
M: node node>quot drop ;
: nodes>quot ( node -- quot )
[ [ node>quot ] each ] [ ] make ;
: optimized. ( quot/word -- )
dup word? [ specialized-def ] when
build-tree optimize-tree nodes>quot . ;
SYMBOL: words-called
SYMBOL: generics-called
SYMBOL: methods-called
SYMBOL: intrinsics-called
SYMBOL: node-count
: make-report ( word/quot -- assoc )
[
dup word? [ build-tree-from-word nip ] [ build-tree ] if
optimize-tree
H{ } clone words-called set
H{ } clone generics-called set
H{ } clone methods-called set
H{ } clone intrinsics-called set
0 swap [
>r 1+ r>
dup #call? [
word>> {
{ [ dup "intrinsics" word-prop over "if-intrinsics" word-prop or ] [ intrinsics-called ] }
{ [ dup generic? ] [ generics-called ] }
{ [ dup method-body? ] [ methods-called ] }
[ words-called ]
} cond 1 -rot get at+
] [ drop ] if
] each-node
node-count set
] H{ } make-assoc ;
: report. ( report -- )
[
"==== Total number of IR nodes:" print
node-count get .
{
{ generics-called "==== Generic word calls:" }
{ words-called "==== Ordinary word calls:" }
{ methods-called "==== Non-inlined method calls:" }
{ intrinsics-called "==== Open-coded intrinsic calls:" }
} [
nl print get keys natural-sort stack.
] assoc-each
] bind ;
: optimizer-report. ( word -- )
make-report report. ;

View File

@ -80,3 +80,13 @@ M: #call escape-analysis*
M: #return escape-analysis* M: #return escape-analysis*
in-d>> add-escaping-values ; in-d>> add-escaping-values ;
M: #alien-invoke escape-analysis*
[ in-d>> add-escaping-values ]
[ out-d>> unknown-allocation ]
bi ;
M: #alien-indirect escape-analysis*
[ in-d>> add-escaping-values ]
[ out-d>> unknown-allocation ]
bi ;

View File

@ -0,0 +1,5 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
IN: compiler.tree.loop.inversion
: invert-loops ( nodes -- nodes' ) ;

View File

@ -0,0 +1,4 @@
USING: compiler.tree.optimizer tools.test ;
IN: compiler.tree.optimizer.tests
\ optimize-tree must-infer

View File

@ -9,6 +9,7 @@ compiler.tree.def-use
compiler.tree.dead-code compiler.tree.dead-code
compiler.tree.strength-reduction compiler.tree.strength-reduction
compiler.tree.loop.detection compiler.tree.loop.detection
compiler.tree.loop.inversion
compiler.tree.branch-fusion ; compiler.tree.branch-fusion ;
IN: compiler.tree.optimizer IN: compiler.tree.optimizer

View File

@ -115,3 +115,9 @@ M: #call propagate-before
M: #call propagate-after M: #call propagate-after
dup word>> "input-classes" word-prop dup dup word>> "input-classes" word-prop dup
[ propagate-input-classes ] [ 2drop ] if ; [ propagate-input-classes ] [ 2drop ] if ;
M: #alien-invoke propagate-before
out-d>> [ object-info swap set-value-info ] each ;
M: #alien-indirect propagate-before
out-d>> [ object-info swap set-value-info ] each ;

View File

@ -143,6 +143,30 @@ TUPLE: #copy < #renaming in-d out-d ;
swap >>out-d swap >>out-d
swap >>in-d ; swap >>in-d ;
TUPLE: #alien-node < node params ;
: new-alien-node ( params class -- node )
new
over in-d>> >>in-d
over out-d>> >>out-d
swap >>params ; inline
TUPLE: #alien-invoke < #alien-node in-d out-d ;
: #alien-invoke ( params -- node )
\ #alien-invoke new-alien-node ;
TUPLE: #alien-indirect < #alien-node in-d out-d ;
: #alien-indirect ( params -- node )
\ #alien-indirect new-alien-node ;
TUPLE: #alien-callback < #alien-node ;
: #alien-callback ( params -- node )
\ #alien-callback new
swap >>params ;
: node, ( node -- ) stack-visitor get push ; : node, ( node -- ) stack-visitor get push ;
GENERIC: inputs/outputs ( #renaming -- inputs outputs ) GENERIC: inputs/outputs ( #renaming -- inputs outputs )
@ -153,6 +177,11 @@ M: #r> inputs/outputs [ in-r>> ] [ out-d>> ] bi ;
M: #copy inputs/outputs [ in-d>> ] [ out-d>> ] bi ; M: #copy inputs/outputs [ in-d>> ] [ out-d>> ] bi ;
M: #return-recursive inputs/outputs [ in-d>> ] [ out-d>> ] bi ; M: #return-recursive inputs/outputs [ in-d>> ] [ out-d>> ] bi ;
: shuffle-effect ( #shuffle -- effect )
[ in-d>> ] [ out-d>> ] [ mapping>> ] tri
[ at ] curry map
<effect> ;
M: vector child-visitor V{ } clone ; M: vector child-visitor V{ } clone ;
M: vector #introduce, #introduce node, ; M: vector #introduce, #introduce node, ;
M: vector #call, #call node, ; M: vector #call, #call node, ;
@ -172,3 +201,6 @@ M: vector #phi, #phi node, ;
M: vector #declare, #declare node, ; M: vector #declare, #declare node, ;
M: vector #recursive, #recursive node, ; M: vector #recursive, #recursive node, ;
M: vector #copy, #copy node, ; M: vector #copy, #copy node, ;
M: vector #alien-invoke, #alien-invoke node, ;
M: vector #alien-indirect, #alien-indirect node, ;
M: vector #alien-callback, #alien-callback node, ;

View File

@ -128,4 +128,8 @@ M: #return unbox-tuples* dup in-d>> assert-not-unboxed ;
M: #introduce unbox-tuples* dup value>> assert-not-unboxed ; M: #introduce unbox-tuples* dup value>> assert-not-unboxed ;
M: #alien-invoke unbox-tuples* dup in-d>> assert-not-unboxed ;
M: #alien-indirect unbox-tuples* dup in-d>> assert-not-unboxed ;
: unbox-tuples ( nodes -- nodes ) [ unbox-tuples* ] map-nodes ; : unbox-tuples ( nodes -- nodes ) [ unbox-tuples* ] map-nodes ;

View File

@ -0,0 +1,84 @@
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences accessors combinators math namespaces
init sets words
alien alien.c-types
stack-checker.backend stack-checker.errors stack-checker.visitor ;
IN: stack-checker.alien
TUPLE: alien-node-params return parameters abi in-d out-d ;
TUPLE: alien-invoke-params < alien-node-params library function ;
TUPLE: alien-indirect-params < alien-node-params ;
TUPLE: alien-callback-params < alien-node-params quot xt ;
: pop-parameters ( -- seq )
pop-literal nip [ expand-constants ] map ;
: param-prep-quot ( node -- quot )
parameters>> [ c-type c-type-unboxer-quot ] map spread>quot ;
: alien-stack ( params extra -- )
over parameters>> length + consume-d >>in-d
dup return>> "void" = 0 1 ? produce-d >>out-d
drop ;
: return-prep-quot ( node -- quot )
return>> [ [ ] ] [ c-type c-type-boxer-quot ] if-void ;
: infer-alien-invoke ( -- )
alien-invoke-params new
! Compile-time parameters
pop-parameters >>parameters
pop-literal nip >>function
pop-literal nip >>library
pop-literal nip >>return
! Quotation which coerces parameters to required types
dup param-prep-quot recursive-state get infer-quot
! Set ABI
dup library>> library [ abi>> ] [ "cdecl" ] if* >>abi
! Magic #: consume exactly the number of inputs
dup 0 alien-stack
! Add node to IR
dup #alien-invoke,
! Quotation which coerces return value to required type
return-prep-quot recursive-state get infer-quot ;
: infer-alien-indirect ( -- )
alien-indirect-params new
! Compile-time parameters
pop-literal nip >>abi
pop-parameters >>parameters
pop-literal nip >>return
! Quotation which coerces parameters to required types
dup param-prep-quot [ dip ] curry recursive-state get infer-quot
! Magic #: consume the function pointer, too
dup 1 alien-stack
! Add node to IR
dup #alien-indirect,
! Quotation which coerces return value to required type
return-prep-quot recursive-state get infer-quot ;
! Callbacks are registered in a global hashtable. If you clear
! this hashtable, they will all be blown away by code GC, beware
SYMBOL: callbacks
[ H{ } clone callbacks set-global ] "alien.compiler" add-init-hook
: register-callback ( word -- ) callbacks get conjoin ;
: callback-bottom ( params -- )
xt>> [ [ register-callback ] [ word-xt drop <alien> ] bi ] curry
recursive-state get infer-quot ;
: infer-alien-callback ( -- )
alien-callback-params new
pop-literal nip >>quot
pop-literal nip >>abi
pop-parameters >>parameters
pop-literal nip >>return
gensym >>xt
dup callback-bottom
#alien-callback, ;

View File

@ -28,9 +28,11 @@ loop? ;
M: inline-recursive hashcode* id>> hashcode* ; M: inline-recursive hashcode* id>> hashcode* ;
: inlined-block? ( word -- ? ) "inlined-block" word-prop ;
: <inline-recursive> ( word -- label ) : <inline-recursive> ( word -- label )
inline-recursive new inline-recursive new
gensym >>id gensym dup t "inlined-block" set-word-prop >>id
swap >>word ; swap >>word ;
: quotation-param? ( obj -- ? ) : quotation-param? ( obj -- ? )

View File

@ -10,10 +10,14 @@ sequences sequences.private slots.private strings
strings.private system threads.private classes.tuple strings.private system threads.private classes.tuple
classes.tuple.private vectors vectors.private words definitions classes.tuple.private vectors vectors.private words definitions
words.private assocs summary compiler.units system.private words.private assocs summary compiler.units system.private
combinators locals.backend stack-checker.state combinators locals.backend
stack-checker.backend stack-checker.branches stack-checker.state
stack-checker.errors stack-checker.transforms stack-checker.backend
stack-checker.visitor ; stack-checker.branches
stack-checker.errors
stack-checker.transforms
stack-checker.visitor
stack-checker.alien ;
IN: stack-checker.known-words IN: stack-checker.known-words
: infer-primitive ( word -- ) : infer-primitive ( word -- )
@ -153,13 +157,15 @@ M: object infer-call*
{ \ get-local [ infer-get-local ] } { \ get-local [ infer-get-local ] }
{ \ drop-locals [ infer-drop-locals ] } { \ drop-locals [ infer-drop-locals ] }
{ \ do-primitive [ \ do-primitive cannot-infer-effect ] } { \ do-primitive [ \ do-primitive cannot-infer-effect ] }
{ \ alien-invoke [ infer-alien-invoke ] }
{ \ alien-indirect [ infer-alien-indirect ] }
{ \ alien-callback [ infer-alien-callback ] }
} case ; } case ;
{ {
>r r> declare call curry compose >r r> declare call curry compose execute if dispatch
execute if dispatch <tuple-boa> <tuple-boa> (throw) load-locals get-local drop-locals
(throw) load-locals get-local drop-locals do-primitive alien-invoke alien-indirect alien-callback
do-primitive
} [ t +special+ set-word-prop ] each } [ t +special+ set-word-prop ] each
{ call execute dispatch load-locals get-local drop-locals } { call execute dispatch load-locals get-local drop-locals }
@ -173,10 +179,10 @@ SYMBOL: +primitive+
{ [ dup +shuffle+ word-prop ] [ infer-shuffle-word ] } { [ dup +shuffle+ word-prop ] [ infer-shuffle-word ] }
{ [ dup +special+ word-prop ] [ infer-special ] } { [ dup +special+ word-prop ] [ infer-special ] }
{ [ dup +primitive+ word-prop ] [ infer-primitive ] } { [ dup +primitive+ word-prop ] [ infer-primitive ] }
{ [ dup +cannot-infer+ word-prop ] [ cannot-infer-effect ] }
{ [ dup +transform-quot+ word-prop ] [ apply-transform ] } { [ dup +transform-quot+ word-prop ] [ apply-transform ] }
{ [ dup +inferred-effect+ word-prop ] [ cached-infer ] }
{ [ dup "macro" word-prop ] [ apply-macro ] } { [ dup "macro" word-prop ] [ apply-macro ] }
{ [ dup +cannot-infer+ word-prop ] [ cannot-infer-effect ] }
{ [ dup +inferred-effect+ word-prop ] [ cached-infer ] }
{ [ dup recursive-label ] [ call-recursive-word ] } { [ dup recursive-label ] [ call-recursive-word ] }
[ dup infer-word apply-word/effect ] [ dup infer-word apply-word/effect ]
} cond ; } cond ;

View File

@ -23,10 +23,11 @@ SYMBOL: +transform-n+
inline inline
: (apply-transform) ( word quot n -- ) : (apply-transform) ( word quot n -- )
consume-d dup [ known literal? ] all? [ dup ensure-d [ known literal? ] all? [
dup empty? [ dup empty? [
drop recursive-state get 1array drop recursive-state get 1array
] [ ] [
consume-d
[ #drop, ] [ #drop, ]
[ [ literal value>> ] map ] [ [ literal value>> ] map ]
[ first literal recursion>> ] tri prefix [ first literal recursion>> ] tri prefix
@ -123,7 +124,6 @@ SYMBOL: +transform-n+
: bit-member-quot ( seq -- newquot ) : bit-member-quot ( seq -- newquot )
[ [
[ drop ] % ! drop the sequence itself; we don't use it at run time
bit-member-seq , bit-member-seq ,
[ [
{ {
@ -140,7 +140,7 @@ SYMBOL: +transform-n+
bit-member-quot bit-member-quot
] [ ] [
[ literalize [ t ] ] { } map>assoc [ literalize [ t ] ] { } map>assoc
[ drop f ] suffix [ nip case ] curry [ drop f ] suffix [ case ] curry
] if ; ] if ;
\ member? [ \ member? [

View File

@ -22,3 +22,6 @@ M: f #declare, drop ;
M: f #recursive, 2drop 2drop ; M: f #recursive, 2drop 2drop ;
M: f #copy, 2drop ; M: f #copy, 2drop ;
M: f #drop, drop ; M: f #drop, drop ;
M: f #alien-invoke, drop ;
M: f #alien-indirect, drop ;
M: f #alien-callback, drop ;

View File

@ -27,3 +27,6 @@ HOOK: #enter-recursive, stack-visitor ( label inputs outputs -- )
HOOK: #return-recursive, stack-visitor ( label inputs outputs -- ) HOOK: #return-recursive, stack-visitor ( label inputs outputs -- )
HOOK: #recursive, stack-visitor ( word label inputs visitor -- ) HOOK: #recursive, stack-visitor ( word label inputs visitor -- )
HOOK: #copy, stack-visitor ( inputs outputs -- ) HOOK: #copy, stack-visitor ( inputs outputs -- )
HOOK: #alien-invoke, stack-visitor ( params -- )
HOOK: #alien-indirect, stack-visitor ( params -- )
HOOK: #alien-callback, stack-visitor ( params -- )