Merge branch 'master' of git://factorcode.org/git/factor
commit
e846d0d98e
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 ;
|
||||||
|
|
|
@ -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 [
|
||||||
|
|
|
@ -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) } ;
|
|
|
@ -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 ;
|
||||||
|
|
|
@ -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 ;
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
|
@ -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 } "." }
|
||||||
|
|
|
@ -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
|
|
@ -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"
|
|
@ -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
|
|
@ -1 +1 @@
|
||||||
Reginald Keith Ford II
|
Reginald Ford
|
|
@ -66,3 +66,5 @@ MACRO: amb-execute ( seq -- quot )
|
||||||
tri* if
|
tri* if
|
||||||
] with-scope ; inline
|
] with-scope ; inline
|
||||||
|
|
||||||
|
: cut-amb ( -- )
|
||||||
|
f failure set ;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 ;
|
||||||
|
|
|
@ -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 ;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Doug Coleman
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
Serial port library
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -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 ;
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -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
|
|
@ -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 ;
|
|
@ -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 ;
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 )
|
||||||
[
|
[
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
Reginald Ford
|
Reginald Ford
|
||||||
|
Eduardo Cavazos
|
|
@ -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"
|
||||||
|
|
|
@ -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 ;
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Doug Coleman
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
Serial port library
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -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 ;
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -0,0 +1 @@
|
||||||
|
unportable
|
|
@ -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
|
|
@ -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 ;
|
|
@ -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 ;
|
|
@ -0,0 +1,4 @@
|
||||||
|
IN: compiler.cfg.builder.tests
|
||||||
|
USING: compiler.cfg.builder tools.test ;
|
||||||
|
|
||||||
|
\ build-cfg must-infer
|
|
@ -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 ;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Slava Pestov
|
|
@ -0,0 +1 @@
|
||||||
|
Slava Pestov
|
|
@ -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."
|
||||||
|
} ;
|
|
@ -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 ;
|
|
@ -0,0 +1 @@
|
||||||
|
Support for generation of relocatable code
|
|
@ -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." } ;
|
|
@ -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 ;
|
|
@ -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? ;
|
|
@ -0,0 +1 @@
|
||||||
|
Slava Pestov
|
|
@ -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 ;
|
|
@ -0,0 +1 @@
|
||||||
|
Register allocation and intrinsic selection
|
|
@ -0,0 +1 @@
|
||||||
|
Final stage of compilation generates machine code from dataflow IR
|
|
@ -0,0 +1 @@
|
||||||
|
compiler
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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 ;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
IN: compiler.tree.debugger.tests
|
||||||
|
USING: compiler.tree.debugger tools.test ;
|
||||||
|
|
||||||
|
\ optimized. must-infer
|
||||||
|
\ optimizer-report. must-infer
|
|
@ -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. ;
|
|
@ -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 ;
|
||||||
|
|
|
@ -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' ) ;
|
|
@ -0,0 +1,4 @@
|
||||||
|
USING: compiler.tree.optimizer tools.test ;
|
||||||
|
IN: compiler.tree.optimizer.tests
|
||||||
|
|
||||||
|
\ optimize-tree must-infer
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 ;
|
||||||
|
|
|
@ -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, ;
|
||||||
|
|
|
@ -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 ;
|
||||||
|
|
|
@ -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, ;
|
|
@ -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 -- ? )
|
||||||
|
|
|
@ -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 ;
|
||||||
|
|
|
@ -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? [
|
||||||
|
|
|
@ -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 ;
|
||||||
|
|
|
@ -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 -- )
|
||||||
|
|
Loading…
Reference in New Issue