]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge branch 'master' of git://factorcode.org/git/factor
authorDoug Coleman <doug.coleman@gmail.com>
Fri, 15 Aug 2008 20:16:54 +0000 (15:16 -0500)
committerDoug Coleman <doug.coleman@gmail.com>
Fri, 15 Aug 2008 20:16:54 +0000 (15:16 -0500)
101 files changed:
basis/alien/c-types/c-types-tests.factor
basis/alien/c-types/c-types.factor
basis/disjoint-sets/disjoint-sets.factor
basis/help/lint/lint.factor
basis/math/ranges/ranges-docs.factor
basis/prettyprint/sections/sections.factor
basis/ui/gadgets/tabs/tabs.factor
basis/unix/bsd/bsd.factor
basis/unix/linux/linux.factor
basis/unix/unix.factor
core/effects/effects.factor
extra/24-game/24-game-docs.factor
extra/24-game/24-game.factor
extra/animations/animations-docs.factor
extra/animations/animations.factor
extra/animations/authors.txt
extra/backtrack/backtrack.factor
extra/html/parser/analyzer/analyzer.factor
extra/html/parser/parser.factor
extra/html/parser/printer/printer.factor
extra/io/serial/authors.txt [new file with mode: 0644]
extra/io/serial/serial.factor [new file with mode: 0644]
extra/io/serial/summary.txt [new file with mode: 0644]
extra/io/serial/tags.txt [new file with mode: 0644]
extra/io/serial/unix/bsd/bsd.factor [new file with mode: 0644]
extra/io/serial/unix/bsd/tags.txt [new file with mode: 0644]
extra/io/serial/unix/linux/linux.factor [new file with mode: 0644]
extra/io/serial/unix/linux/tags.txt [new file with mode: 0644]
extra/io/serial/unix/tags.txt [new file with mode: 0644]
extra/io/serial/unix/termios/bsd/bsd.factor [new file with mode: 0644]
extra/io/serial/unix/termios/bsd/tags.txt [new file with mode: 0644]
extra/io/serial/unix/termios/linux/linux.factor [new file with mode: 0644]
extra/io/serial/unix/termios/linux/tags.txt [new file with mode: 0644]
extra/io/serial/unix/termios/tags.txt [new file with mode: 0644]
extra/io/serial/unix/termios/termios.factor [new file with mode: 0644]
extra/io/serial/unix/unix-tests.factor [new file with mode: 0644]
extra/io/serial/unix/unix.factor [new file with mode: 0644]
extra/irc/client/client-tests.factor
extra/irc/client/client.factor
extra/irc/messages/messages-tests.factor
extra/irc/messages/messages.factor [changed mode: 0644->0755]
extra/irc/ui/commands/commands.factor
extra/irc/ui/ui.factor
extra/math/combinatorics/combinatorics-tests.factor
extra/math/combinatorics/combinatorics.factor
extra/math/derivatives/authors.txt
extra/math/derivatives/derivatives-docs.factor
extra/math/derivatives/derivatives.factor
extra/math/function-tools/function-tools.factor
extra/sequences/lib/lib.factor
extra/serial/authors.txt [new file with mode: 0644]
extra/serial/serial.factor [new file with mode: 0644]
extra/serial/summary.txt [new file with mode: 0644]
extra/serial/tags.txt [new file with mode: 0644]
extra/serial/unix/bsd/bsd.factor [new file with mode: 0644]
extra/serial/unix/bsd/tags.txt [new file with mode: 0644]
extra/serial/unix/linux/linux.factor [new file with mode: 0644]
extra/serial/unix/linux/tags.txt [new file with mode: 0644]
extra/serial/unix/tags.txt [new file with mode: 0644]
extra/serial/unix/termios/bsd/bsd.factor [new file with mode: 0644]
extra/serial/unix/termios/bsd/tags.txt [new file with mode: 0644]
extra/serial/unix/termios/linux/linux.factor [new file with mode: 0644]
extra/serial/unix/termios/linux/tags.txt [new file with mode: 0644]
extra/serial/unix/termios/tags.txt [new file with mode: 0644]
extra/serial/unix/termios/termios.factor [new file with mode: 0644]
extra/serial/unix/unix-tests.factor [new file with mode: 0644]
extra/serial/unix/unix.factor [new file with mode: 0644]
unfinished/compiler/cfg/builder/builder-tests.factor [new file with mode: 0644]
unfinished/compiler/cfg/builder/builder.factor
unfinished/compiler/generator/authors.txt [new file with mode: 0644]
unfinished/compiler/generator/fixup/authors.txt [new file with mode: 0644]
unfinished/compiler/generator/fixup/fixup-docs.factor [new file with mode: 0644]
unfinished/compiler/generator/fixup/fixup.factor [new file with mode: 0755]
unfinished/compiler/generator/fixup/summary.txt [new file with mode: 0644]
unfinished/compiler/generator/generator-docs.factor [new file with mode: 0755]
unfinished/compiler/generator/generator.factor [new file with mode: 0755]
unfinished/compiler/generator/iterator/iterator.factor [new file with mode: 0644]
unfinished/compiler/generator/registers/authors.txt [new file with mode: 0644]
unfinished/compiler/generator/registers/registers.factor [new file with mode: 0755]
unfinished/compiler/generator/registers/summary.txt [new file with mode: 0644]
unfinished/compiler/generator/summary.txt [new file with mode: 0644]
unfinished/compiler/generator/tags.txt [new file with mode: 0644]
unfinished/compiler/machine/debug/debug.factor [deleted file]
unfinished/compiler/machine/debugger/debugger.factor [new file with mode: 0644]
unfinished/compiler/tree/dataflow-analysis/backward/backward.factor
unfinished/compiler/tree/dead-code/dead-code.factor
unfinished/compiler/tree/debugger/debugger-tests.factor [new file with mode: 0644]
unfinished/compiler/tree/debugger/debugger.factor [new file with mode: 0644]
unfinished/compiler/tree/escape-analysis/simple/simple.factor
unfinished/compiler/tree/loop/inversion/inversion.factor [new file with mode: 0644]
unfinished/compiler/tree/optimizer/optimizer-tests.factor [new file with mode: 0644]
unfinished/compiler/tree/optimizer/optimizer.factor
unfinished/compiler/tree/propagation/simple/simple.factor
unfinished/compiler/tree/tree.factor
unfinished/compiler/tree/tuple-unboxing/tuple-unboxing.factor
unfinished/stack-checker/alien/alien.factor [new file with mode: 0644]
unfinished/stack-checker/inlining/inlining.factor
unfinished/stack-checker/known-words/known-words.factor
unfinished/stack-checker/transforms/transforms.factor
unfinished/stack-checker/visitor/dummy/dummy.factor
unfinished/stack-checker/visitor/visitor.factor

index 276dd581c51dcd36de671d65965778fadb2ca6fa..edda9e7fdb4fa13a7a16c1336f6ce9bbf36edd09 100755 (executable)
@@ -2,6 +2,12 @@ IN: alien.c-types.tests
 USING: alien alien.syntax alien.c-types kernel tools.test
 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* ;
 
 [ 123 ] [ foo ] unit-test
index c553ca5cfb178398f1651f61420b703c25c60e8f..a9b39f80abe10c3c81e9b761269d89a83848846e 100755 (executable)
@@ -4,7 +4,7 @@ USING: byte-arrays arrays assocs kernel kernel.private libc math
 namespaces parser sequences strings words assocs splitting
 math.parser cpu.architecture alien alien.accessors quotations
 layouts system compiler.units io.files io.encodings.binary
-accessors combinators effects ;
+accessors combinators effects continuations ;
 IN: alien.c-types
 
 DEFER: <int>
@@ -239,15 +239,20 @@ M: long-long-type box-return ( type -- )
     } 2cleave ;
 
 : expand-constants ( c-type -- c-type' )
-    #! We use def>> call instead of execute to get around
-    #! staging violations
     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 ;
 
 : malloc-file-contents ( path -- alien len )
     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>
         [ alien-cell ] >>getter
index f48129fbd458733aa2367e0477720f5a67c797ae..77e4a53f7b1b33357f13e28b0b3acf93926214a0 100644 (file)
@@ -88,6 +88,14 @@ M:: disjoint-set equate ( a b disjoint-set -- )
         disjoint-set link-sets
     ] 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
     [ parents>> ] [ ranks>> ] [ counts>> ] tri [ clone ] tri@
     disjoint-set boa ;
index 9cbffe2d33a6747fda84adb9aecff4f47935fe25..c4f4a46710ccac2e854ecb68d3f8eebc9082aa60 100755 (executable)
@@ -3,9 +3,9 @@
 USING: accessors sequences parser kernel help help.markup
 help.topics words strings classes tools.vocabs namespaces io
 io.streams.string prettyprint definitions arrays vectors
-combinators splitting debugger hashtables sorting effects vocabs
-vocabs.loader assocs editors continuations classes.predicate
-macros math sets eval ;
+combinators combinators.short-circuit splitting debugger
+hashtables sorting effects vocabs vocabs.loader assocs editors
+continuations classes.predicate macros math sets eval ;
 IN: help.lint
 
 : check-example ( element -- )
@@ -43,15 +43,15 @@ IN: help.lint
 
 : check-values ( word element -- )
     {
-        { [ over "declared-effect" word-prop ] [ 2drop ] }
-        { [ dup contains-funky-elements? not ] [ 2drop ] }
-        { [ over macro? not ] [ 2drop ] }
+        [ drop "declared-effect" word-prop not ]
+        [ nip contains-funky-elements? ]
+        [ drop macro? ]
         [
             [ effect-values >array ]
             [ extract-values >array ]
-            bi* assert=
+            bi* =
         ]
-    } cond ;
+    } 2|| [ "$values don't match stack effect" throw ] unless ;
 
 : check-see-also ( word element -- )
     nip \ $see-also swap elements [
index 714fc67c9f9789241f0c0d0a9d16d7e539ca9f17..f3c65e51a458b19d6a08556c1a1358acaf24760a 100644 (file)
@@ -1,21 +1,27 @@
-USING: help.syntax help.markup ;
+USING: help.syntax help.markup arrays sequences ;
 
 IN: math.ranges
 
 ARTICLE: "ranges" "Ranges"
-
-  "A " { $emphasis "range" } " is a virtual sequence with real elements "
-  "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)   } ;
\ No newline at end of file
+"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 } "." ;
+  
+ABOUT: "ranges"
\ No newline at end of file
index 23a50700b30078268cd64e635f294dbc4e7a9c60..168e118d4b3c8f29b6e92e24b6eec90b04bf05e4 100644 (file)
@@ -171,10 +171,11 @@ M: block section-fits? ( section -- ? )
     line-limit? [ drop t ] [ call-next-method ] if ;
 
 : pprint-sections ( block advancer -- )
-    swap sections>> [ line-break? not ] filter
-    unclip pprint-section [
-        dup rot call pprint-section
-    ] with each ; inline
+    [
+        sections>> [ line-break? not ] filter
+        unclip-slice pprint-section
+    ] dip
+    [ [ pprint-section ] bi ] curry each ; inline
 
 M: block short-section ( block -- )
     [ advance ] pprint-sections ;
index 12031e5911124594b083eb3fa205d25de286fc66..50e2df2e9e3ec90696702325d026f6d672fa5af8 100755 (executable)
@@ -48,8 +48,8 @@ DEFER: (del-page)
 : del-page ( name tabbed -- )\r
     [ names>> index ] 2keep (del-page) ;\r
 \r
-: <tabbed> ( assoc -- tabbed )\r
-  tabbed new-frame\r
+: new-tabbed ( assoc class -- tabbed )\r
+    new-frame\r
     0 <model> >>model\r
     <pile> 1 >>fill >>toggler\r
     dup toggler>> @left grid-add\r
@@ -59,3 +59,4 @@ DEFER: (del-page)
     bi\r
     dup redo-toggler ;\r
     \r
+: <tabbed> ( assoc -- tabbed ) tabbed new-tabbed ;\r
index 0c669d225826d1cfe3552b584fd746c439e6b06b..6934d5b8dc49dbdac342fcfb69f2d110a0109109 100755 (executable)
@@ -7,13 +7,16 @@ IN: unix
 
 : MAXPATHLEN 1024 ; inline
 
-: O_RDONLY  HEX: 0000 ; inline
-: O_WRONLY  HEX: 0001 ; inline
-: O_RDWR    HEX: 0002 ; inline
-: O_APPEND  HEX: 0008 ; inline
-: O_CREAT   HEX: 0200 ; inline
-: O_TRUNC   HEX: 0400 ; inline
-: O_EXCL    HEX: 0800 ; inline
+: O_RDONLY   HEX: 0000 ; inline
+: O_WRONLY   HEX: 0001 ; inline
+: O_RDWR     HEX: 0002 ; inline
+: O_NONBLOCK HEX: 0004 ; inline
+: O_APPEND   HEX: 0008 ; inline
+: O_CREAT    HEX: 0200 ; 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
 : SO_REUSEADDR HEX: 4 ; inline
@@ -24,7 +27,6 @@ IN: unix
 : F_SETFD 2 ; inline
 : F_SETFL 4 ; inline
 : FD_CLOEXEC 1 ; inline
-: O_NONBLOCK 4 ; inline
 
 C-STRUCT: sockaddr-in
     { "uchar" "len" }
index 0efacee2946ba9db82a647afb53945e6fb7ff937..0c08cf0f2b73f49b4b72ca8a9cfb3a407f3847a4 100755 (executable)
@@ -7,13 +7,16 @@ USING: alien.syntax ;
 
 : MAXPATHLEN 1024 ; inline
 
-: O_RDONLY  HEX: 0000 ; inline
-: O_WRONLY  HEX: 0001 ; inline
-: O_RDWR    HEX: 0002 ; inline
-: O_CREAT   HEX: 0040 ; inline
-: O_EXCL    HEX: 0080 ; inline
-: O_TRUNC   HEX: 0200 ; inline
-: O_APPEND  HEX: 0400 ; inline
+: O_RDONLY   HEX: 0000 ; inline
+: O_WRONLY   HEX: 0001 ; inline
+: O_RDWR     HEX: 0002 ; inline
+: O_CREAT    HEX: 0040 ; inline
+: O_EXCL     HEX: 0080 ; inline
+: O_NOCTTY   HEX: 0100 ; 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
 
@@ -28,7 +31,6 @@ USING: alien.syntax ;
 : FD_CLOEXEC 1 ; inline
 
 : F_SETFL 4 ; inline
-: O_NONBLOCK HEX: 800 ; inline
 
 C-STRUCT: addrinfo
     { "int" "flags" }
index 083700493d02702f2fde96c1c2973b28541b6511..4ae74f8267f4cbba28bc0567cede076c8ec5082f 100755 (executable)
@@ -192,4 +192,3 @@ FUNCTION: ssize_t write ( int fd, void* buf, size_t nbytes ) ;
     { [ os bsd? ] [ "unix.bsd" require ] }
     { [ os solaris? ] [ "unix.solaris" require ] }
 } cond
-
index c221ad073b27418649b40d17bf860494658b338f..2e0aa4c2796753f9db8513d87e5b75670a8da115 100755 (executable)
@@ -1,7 +1,7 @@
 ! Copyright (C) 2006, 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: kernel math namespaces sequences strings words assocs
-combinators accessors arrays ;
+USING: kernel math math.parser namespaces sequences strings
+words assocs combinators accessors arrays ;
 IN: effects
 
 TUPLE: effect in out terminated? ;
@@ -25,10 +25,11 @@ TUPLE: effect in out terminated? ;
 GENERIC: effect>string ( obj -- str )
 M: string effect>string ;
 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 ;
 
 : stack-picture ( seq -- string )
+    dup integer? [ "object" <repetition> ] when
     [ [ effect>string % CHAR: \s , ] each ] "" make ;
 
 M: effect effect>string ( effect -- string )
index 12a558b2d206ea5ceb2352c1e914f91fb91e4b1b..cd82f335d88318844f969802b790c7cdf97c2e39 100644 (file)
@@ -31,12 +31,12 @@ HELP: 24-able ( -- vector )
     "just using the provided commands and the 4 numbers. The Following are the "
     "provided commands: "
     { $link + } ", " { $link - } ", " { $link * } ", "
-    { $link / } ", and " { $link swap } "."
+    { $link / } ", " { $link swap } ", and " { $link rot } "."
 }
 { $examples
     { $example
         "USE: 24-game"
-        "24-able vector-24-able?"
+        "24-able vector-24-able? ."
         "t"
     }
     { $notes { $link 24-able? } " is used in " { $link 24-able } "." }
index 52f0cd683345e56b6cda2570a567b81043d936e6..126215ab131945eca73631e24ba7a2b2b4a0d851 100644 (file)
@@ -59,4 +59,5 @@ DEFER: check-status
 : 24-able? ( vector -- t/f ) [ makes-24? ] with-datastack first ;
 : 24-able ( -- vector ) build-quad dup 24-able? [ drop build-quad ] unless ;
 : set-commands ( -- ) { + - * / rot swap q } commands set ;
-: play-game ( -- ) set-commands 24-able repeat ;
\ No newline at end of file
+: play-game ( -- ) set-commands 24-able repeat ;
+MAIN: play-game
\ No newline at end of file
index 6a1e89a28edb5f25880b4368ce28b7f46f358758..000c0ce4cca8ca909357b8ba6331ba5f1f91287e 100644 (file)
@@ -1,34 +1,65 @@
 USING: help.markup help.syntax ;
-IN: extra.animations
+IN: animations
 
 HELP: animate ( quot duration -- )
+
 { $values
     { "quot" "a quot which uses " { $link progress } }
     { "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."  }
-{ $example 
-    "USING: extra.animations calendar threads prettyprint ;"
-    "[ 1 sleep progress unparse write \" ms elapsed\" print ] 1/20 seconds animate ;"
-    "46 ms elapsed\n17 ms elapsed"
+{ $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."
+}
+{ $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 ( -- )
-{ $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 )
 { $values { "time" "an integer" } }
-{ $description "Gives the time elapsed since the last time this word was called, in milliseconds." }
-{ $example
-    "USING: extra.animations threads prettyprint ;"
-    "reset-progress 3 [ 1 sleep progress unparse write \"ms elapsed\" print ] times ;"
-    "31 ms elapsed\n18 ms elapsed\n16 ms elapsed"
+{ $description
+    "Gives the time elapsed since the last time"
+    " this word was called, in milliseconds." 
+}
+{ $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"
-"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!"
+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!"
 { $subsection animate }
 { $subsection reset-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." ;
-ABOUT: "extra.animations"
\ No newline at end of file
+! A little talk about when to use progress and when to use animate
+    { $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"
\ No newline at end of file
index 7efd618bbf212f306ce1e66cd19eeb016c255a80..803536a51c0d5598863ce2e790be3a89ae2db777 100644 (file)
@@ -2,11 +2,16 @@
 
 USING: kernel shuffle system locals
 prettyprint math io namespaces threads calendar ;
-IN: extra.animations
+IN: animations
 
 SYMBOL: last-loop
+SYMBOL: sleep-period
+
 : reset-progress ( -- ) millis last-loop set ;
+! : my-progress ( -- progress ) millis 
 : progress ( -- progress ) millis last-loop get - reset-progress ;
+: progress-peek ( -- progress ) millis last-loop get - ;
 : set-end ( duration -- end-time ) dt>milliseconds millis + ;
-: loop ( quot end -- ) dup millis > [ [ dup call ] dip loop ] [ 2drop ] if ;
-: animate ( quot duration -- ) reset-progress set-end loop ;
\ No newline at end of file
+: loop ( quot end -- ) dup millis > [ [ dup call ] dip loop ] [ 2drop ] if ; inline
+: animate ( quot duration -- ) reset-progress set-end loop ; inline
+: sample ( revs quot -- avg ) reset-progress dupd times progress swap / ; inline
\ No newline at end of file
index dac0cb42fea0c4598ac93411d56337d0f91e2d3d..137b1605da7b6c7df3ed131494311010febb0897 100644 (file)
@@ -1 +1 @@
-Reginald Keith Ford II
\ No newline at end of file
+Reginald Ford
\ No newline at end of file
index 3c1a79412118bd5891a2fab0b58da82e0c3e2b0a..db2c50173c9f8c85c7585fb448d4e9e5bf4bb9f9 100755 (executable)
@@ -66,3 +66,5 @@ MACRO: amb-execute ( seq -- quot )
         tri* if\r
     ] with-scope ; inline\r
 \r
+: cut-amb ( -- )\r
+    f failure set ;\r
index dca727b9dc5857a221ffc8cc8bb5a5f36645c07a..f167feba069aa4f57e6a925f846a30ca1dd19694 100755 (executable)
@@ -140,6 +140,12 @@ TUPLE: link attributes clickable ;
 : href-contains? ( str tag -- ? )
     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' )
     "form" over find-opening-tags-by-name
index c8aa9aa9e6c38b3c68ba9bf88c4fcf71f219804a..dbf6c52a0d496566c07967cf1960e77120e41b07 100644 (file)
@@ -1,4 +1,4 @@
-USING: arrays html.parser.utils hashtables io kernel
+USING: accessors arrays html.parser.utils hashtables io kernel
 namespaces prettyprint quotations
 sequences splitting state-parser strings unicode.categories unicode.case ;
 IN: html.parser
@@ -23,8 +23,10 @@ SYMBOL: tagstack
     ] if ;
 
 : <tag> ( name attributes closing? -- tag )
-    { set-tag-name set-tag-attributes set-tag-closing? }
-    tag construct ;
+    tag new
+        swap >>closing?
+        swap >>attributes
+        swap >>name ;
 
 : make-tag ( str attribs -- tag )
     >r [ closing-tag? ] keep "/" trim1 r> rot <tag> ;
@@ -75,7 +77,7 @@ SYMBOL: tagstack
         read-quote
     ] [
         read-token
-    ] if ;
+    ] if [ blank? ] trim ;
 
 : read-comment ( -- )
     "-->" take-string* make-comment-tag push-tag ;
index d352a97688e80d4b1928bda2c4b38786d04ffd25..27cb21a927574b54349510250c96762a4088bc96 100644 (file)
@@ -83,13 +83,6 @@ M: src-printer print-closing-named-tag ( tag -- )
 SYMBOL: tab-width
 SYMBOL: #indentations
 
-: html-pp ( vector -- )
-    [
-        0 #indentations set
-        2 tab-width set
-        
-    ] with-scope ;
-
 : print-tabs ( -- )
     tab-width get #indentations get * CHAR: \s <repetition> write ; 
 
@@ -125,3 +118,6 @@ M: printer print-tag ( tag -- )
 ! H{ { table-gap { 10 10 } } } [
     ! [ [ [ [ . ] with-cell ] each ] with-row ] each
 ! ] tabular-output
+
+! : html-pp ( vector -- )
+    ! [ 0 #indentations set 2 tab-width set ] with-scope ; 
diff --git a/extra/io/serial/authors.txt b/extra/io/serial/authors.txt
new file mode 100644 (file)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/extra/io/serial/serial.factor b/extra/io/serial/serial.factor
new file mode 100644 (file)
index 0000000..c24f089
--- /dev/null
@@ -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
diff --git a/extra/io/serial/summary.txt b/extra/io/serial/summary.txt
new file mode 100644 (file)
index 0000000..5ccd99d
--- /dev/null
@@ -0,0 +1 @@
+Serial port library
diff --git a/extra/io/serial/tags.txt b/extra/io/serial/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/io/serial/unix/bsd/bsd.factor b/extra/io/serial/unix/bsd/bsd.factor
new file mode 100644 (file)
index 0000000..3c5ce62
--- /dev/null
@@ -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
diff --git a/extra/io/serial/unix/bsd/tags.txt b/extra/io/serial/unix/bsd/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/io/serial/unix/linux/linux.factor b/extra/io/serial/unix/linux/linux.factor
new file mode 100644 (file)
index 0000000..342ff44
--- /dev/null
@@ -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 ;
diff --git a/extra/io/serial/unix/linux/tags.txt b/extra/io/serial/unix/linux/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/io/serial/unix/tags.txt b/extra/io/serial/unix/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/io/serial/unix/termios/bsd/bsd.factor b/extra/io/serial/unix/termios/bsd/bsd.factor
new file mode 100644 (file)
index 0000000..414ec98
--- /dev/null
@@ -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
diff --git a/extra/io/serial/unix/termios/bsd/tags.txt b/extra/io/serial/unix/termios/bsd/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/io/serial/unix/termios/linux/linux.factor b/extra/io/serial/unix/termios/linux/linux.factor
new file mode 100644 (file)
index 0000000..c7da10a
--- /dev/null
@@ -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
diff --git a/extra/io/serial/unix/termios/linux/tags.txt b/extra/io/serial/unix/termios/linux/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/io/serial/unix/termios/tags.txt b/extra/io/serial/unix/termios/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/io/serial/unix/termios/termios.factor b/extra/io/serial/unix/termios/termios.factor
new file mode 100644 (file)
index 0000000..e5ccd37
--- /dev/null
@@ -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
diff --git a/extra/io/serial/unix/unix-tests.factor b/extra/io/serial/unix/unix-tests.factor
new file mode 100644 (file)
index 0000000..bbfd10b
--- /dev/null
@@ -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 ;
diff --git a/extra/io/serial/unix/unix.factor b/extra/io/serial/unix/unix.factor
new file mode 100644 (file)
index 0000000..ed60d94
--- /dev/null
@@ -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 ;
index 1b338df4429cc9cbca5cfd503269b17f8ffececb..932bdda472e0cb55a327ec6f49bdc0dd274509bb 100644 (file)
 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
        concurrency.mailboxes classes assocs combinators ;
 EXCLUDE: irc.messages => join ;
 RENAME: join irc.messages => join_
 IN: irc.client.tests
 
-! Utilities
-: <test-stream> ( lines -- stream )
-  "\n" join <string-reader> <string-writer> <duplex-stream> ;
+! Streams for testing
+TUPLE: mb-writer lines last-line disposed ;
+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 )
-    "someserver" irc-port "factorbot" f <irc-profile> <irc-client>
-    swap [ 2nip <test-stream> f ] curry >>connect ;
+: spawn-client ( lines listeners -- irc-client )
+    "someserver" irc-port "factorbot" f <irc-profile>
+    <irc-client>
+        t >>is-running
+        <test-stream> >>stream
+    dup [ spawn-irc yield ] with-irc-client ;
 
-: set-nick ( irc-client nickname -- )
-    swap profile>> (>>nickname) ;
+! to be used inside with-irc-client quotations
+: %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 -- )
-    [ current-irc-client ] dip with-variable ; inline
+: read-matching-message ( listener quot: ( msg -- ? ) -- irc-message )
+    [ in-messages>> 0.1 seconds ] dip mailbox-get-timeout? ;
 
-{ "" } make-client dup "factorbot" set-nick [
-    { t } [ irc> profile>> nickname>> me? ] unit-test
+: with-irc ( quot: ( -- ) -- )
+    [ 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"
-                        parse-irc-line irc-message-origin ] unit-test
+  { "factorbot" } [ irc> profile>> nickname>> ] unit-test
 
-    { "someuser" } [ ":someuser!n=user@some.where PRIVMSG factorbot :hi"
-                     parse-irc-line irc-message-origin ] unit-test
-] with-dummy-client
+  { "someuser" } [ "someuser!n=user@some.where" parse-name ] unit-test
+
+  { "#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
-{ "factorbot" } [
-    { "NOTICE AUTH :*** Looking up your hostname..."
-      "NOTICE AUTH :*** Checking ident"
-      "NOTICE AUTH :*** Found your hostname"
-      "NOTICE AUTH :*** No identd (auth) response"
-      ":some.where 001 factorbot :Welcome factorbot"
-    } make-client
-    { [ connect-irc ]
-      [ drop 0.1 seconds sleep ]
-      [ profile>> nickname>> ]
-      [ terminate-irc ]
-    } cleave ] unit-test
-
-{ join_ "#factortest" } [
-    { ":factorbot!n=factorbo@some.where JOIN :#factortest"
-      ":ircserver.net MODE #factortest +ns"
-      ":ircserver.net 353 factorbot @ #factortest :@factorbot "
-      ":ircserver.net 366 factorbot #factortest :End of /NAMES list."
-      ":ircserver.net 477 factorbot #factortest :[ircserver-info] blah blah"
-    } make-client
-    { [ "factorbot" set-nick ]
-      [ connect-irc ]
-      [ drop 0.1 seconds sleep ]
-      [ join-messages>> 0.1 seconds mailbox-get-timeout ]
-      [ terminate-irc ]
-    } cleave
-    [ class ] [ trailing>> ] bi ] unit-test
-
-{ +join+ "somebody" } [
-    { ":somebody!n=somebody@some.where JOIN :#factortest" } make-client
-    { [ "factorbot" set-nick ]
-      [ listeners>>
-        [ "#factortest" [ <irc-channel-listener> ] keep ] dip set-at ]
-      [ connect-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" } [
-    { ":somebody!n=somebody@some.where PRIVMSG #factortest :hello" } make-client
-    { [ "factorbot" set-nick ]
-      [ listeners>>
-        [ "#factortest" [ <irc-channel-listener> ] keep ] dip set-at ]
-      [ connect-irc ]
-      [ listeners>> [ "#factortest" ] dip at
-        [ read-message drop ] [ read-message ] bi ]
-      [ terminate-irc ]
-    } cleave
-    [ class ] [ name>> ] [ trailing>> ] tri
-    ] unit-test
-
-{ privmsg "factorbot" "hello" } [
-    { ":somedude!n=user@isp.net PRIVMSG factorbot :hello" } make-client
-    { [ "factorbot" set-nick ]
-      [ listeners>>
-        [ "somedude" [ <irc-nick-listener> ] keep ] dip set-at ]
-      [ connect-irc ]
-      [ listeners>> [ "somedude" ] dip at
-        [ read-message drop ] [ read-message ] bi ]
-      [ terminate-irc ]
-    } cleave
-    [ class ] [ name>> ] [ trailing>> ] tri
-    ] unit-test
-
-! Participants lists tests
-{ H{ { "somedude" +normal+ } } } [
-    { ":somedude!n=user@isp.net JOIN :#factortest" } make-client
-    { [ "factorbot" set-nick ]
-      [ listeners>>
-        [ "#factortest" [ <irc-channel-listener> ] keep ] dip set-at ]
-      [ connect-irc ]
-      [ drop 0.1 seconds sleep ]
-      [ listeners>> [ "#factortest" ] dip at participants>> ]
-      [ terminate-irc ]
-    } cleave
-    ] unit-test
-
-{ H{ { "somedude2" +normal+ } } } [
-    { ":somedude!n=user@isp.net PART #factortest" } make-client
-    { [ "factorbot" set-nick ]
-      [ listeners>>
-        [ "#factortest" [ <irc-channel-listener>
-                          H{ { "somedude2" +normal+ }
-                             { "somedude" +normal+ } } clone >>participants ] keep
-        ] dip set-at ]
-      [ connect-irc ]
-      [ drop 0.1 seconds sleep ]
-      [ listeners>> [ "#factortest" ] dip at participants>> ]
-      [ terminate-irc ]
-    } cleave
-    ] unit-test
-
-{ H{ { "somedude2" +normal+ } } } [
-    { ":somedude!n=user@isp.net QUIT" } make-client
-    { [ "factorbot" set-nick ]
-      [ listeners>>
-        [ "#factortest" [ <irc-channel-listener>
-                          H{ { "somedude2" +normal+ }
-                             { "somedude" +normal+ } } clone >>participants ] keep
-        ] dip set-at ]
-      [ connect-irc ]
-      [ drop 0.1 seconds sleep ]
-      [ listeners>> [ "#factortest" ] dip at participants>> ]
-      [ terminate-irc ]
-    } cleave
-    ] unit-test
-
-{ H{ { "somedude2" +normal+ } } } [
-    { ":somedude2!n=user2@isp.net KICK #factortest somedude" } make-client
-    { [ "factorbot" set-nick ]
-      [ listeners>>
-        [ "#factortest" [ <irc-channel-listener>
-                          H{ { "somedude2" +normal+ }
-                             { "somedude" +normal+ } } clone >>participants ] keep
-        ] dip set-at ]
-      [ connect-irc ]
-      [ drop 0.1 seconds sleep ]
-      [ listeners>> [ "#factortest" ] dip at participants>> ]
-      [ terminate-irc ]
-    } cleave
-    ] unit-test
+[ { "factorbot2" } [
+     ":some.where 001 factorbot2 :Welcome factorbot2" %push-line
+      irc> profile>> nickname>>
+  ] unit-test
+] with-irc
+
+[ { join_ "#factortest" } [
+      { ":factorbot!n=factorbo@some.where JOIN :#factortest"
+        ":ircserver.net 353 factorbot @ #factortest :@factorbot "
+        ":ircserver.net 366 factorbot #factortest :End of /NAMES list."
+        ":ircserver.net 477 factorbot #factortest :[ircserver-info] blah blah"
+      } [ %push-line ] each
+      irc> join-messages>> 0.1 seconds mailbox-get-timeout
+      [ class ] [ trailing>> ] bi
+  ] unit-test
+] with-irc
+
+[ { T{ participant-changed f "somebody" +join+ } } [
+      "#factortest" <irc-channel-listener> [ %add-named-listener ] keep
+      ":somebody!n=somebody@some.where JOIN :#factortest" %push-line
+      [ participant-changed? ] read-matching-message
+  ] unit-test
+] with-irc
+
+[ { privmsg "#factortest" "hello" } [
+      "#factortest" <irc-channel-listener> [ %add-named-listener ] keep
+      ":somebody!n=somebody@some.where PRIVMSG #factortest :hello" %push-line
+      [ privmsg? ] read-matching-message
+      [ class ] [ name>> ] [ trailing>> ] tri
+  ] unit-test
+] with-irc
+
+[ { privmsg "factorbot" "hello" } [
+      "somedude" <irc-nick-listener>  [ %add-named-listener ] keep
+      ":somedude!n=user@isp.net PRIVMSG factorbot :hello" %push-line
+      [ privmsg? ] read-matching-message
+      [ class ] [ name>> ] [ trailing>> ] tri
+  ] unit-test
+] with-irc
+
+[ { mode } [
+      "#factortest" <irc-channel-listener>  [ %add-named-listener ] keep
+      ":ircserver.net MODE #factortest +ns" %push-line
+      [ mode? ] read-matching-message class
+  ] unit-test
+] with-irc
+
+! Participant lists tests
+[ { H{ { "somedude" +normal+ } } } [
+      "#factortest" <irc-channel-listener> [ %add-named-listener ] keep
+      ":somedude!n=user@isp.net JOIN :#factortest" %push-line
+      participants>>
+  ] unit-test
+] with-irc
+
+[ { H{ { "somedude2" +normal+ } } } [
+      "#factortest" <irc-channel-listener>
+          H{ { "somedude2" +normal+ }
+             { "somedude" +normal+ } } clone >>participants
+      [ %add-named-listener ] keep
+      ":somedude!n=user@isp.net PART #factortest" %push-line
+      participants>>
+  ] unit-test
+] with-irc
+
+[ { H{ { "somedude2" +normal+ } } } [
+      "#factortest" <irc-channel-listener>
+          H{ { "somedude2" +normal+ }
+             { "somedude" +normal+ } } clone >>participants
+      [ %add-named-listener ] keep
+      ":somedude!n=user@isp.net QUIT" %push-line
+      participants>>
+  ] unit-test
+] with-irc
+
+[ { H{ { "somedude2" +normal+ } } } [
+      "#factortest" <irc-channel-listener>
+          H{ { "somedude2" +normal+ }
+             { "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
-{ T{ participant-changed f f f } } [
-    { ":ircserver.net 353 factorbot @ #factortest :@factorbot "
-      ":ircserver.net 366 factorbot #factortest :End of /NAMES list." } make-client
-    { [ "factorbot" set-nick ]
-      [ listeners>>
-        [ "#factortest" [ <irc-channel-listener> ] keep ] dip set-at ]
-      [ connect-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+ } } [
-    { ":somedude!n=user@isp.net QUIT" } make-client
-    { [ "factorbot" set-nick ]
-      [ listeners>>
-        [ "#factortest" [ <irc-channel-listener>
-                          H{ { "somedude" +normal+ } } clone >>participants ] keep
-        ] dip set-at ]
-      [ connect-irc ]
-      [ drop 0.1 seconds sleep ]
-      [ listeners>> [ "#factortest" ] dip at
-        [ read-message drop ] [ read-message drop ] [ read-message ] tri ]
-      [ terminate-irc ]
-    } cleave
-    ] unit-test
\ No newline at end of file
+[ { T{ participant-changed f f f f } } [
+      "#factortest" <irc-channel-listener> [ %add-named-listener ] keep
+      ":ircserver.net 353 factorbot @ #factortest :@factorbot " %push-line
+      ":ircserver.net 366 factorbot #factortest :End of /NAMES list." %push-line
+      [ participant-changed? ] read-matching-message
+  ] unit-test
+] with-irc
+
+[ { T{ participant-changed f "somedude" +part+ f } } [
+      "#factortest" <irc-channel-listener>
+          H{ { "somedude" +normal+ } } clone >>participants
+      [ %add-named-listener ] keep
+      ":somedude!n=user@isp.net QUIT" %push-line
+      [ participant-changed? ] read-matching-message
+  ] unit-test
+] with-irc
+
+[ { T{ participant-changed f "somedude" +nick+ "somedude2" } } [
+      "#factortest" <irc-channel-listener>
+          H{ { "somedude" +normal+ } } clone >>participants
+      [ %add-named-listener ] keep
+      ":somedude!n=user2@isp.net NICK :somedude2" %push-line
+      [ participant-changed? ] read-matching-message
+  ] unit-test
+] with-irc
index 99922b1fb5f175dd56174c8b748e6de67e918ff6..575c26972f39c8ec9661fa2b2a371d702fd9882a 100644 (file)
@@ -3,7 +3,7 @@
 USING: concurrency.mailboxes kernel io.sockets io.encodings.8-bit calendar
        accessors destructors namespaces io assocs arrays qualified fry
        continuations threads strings classes combinators splitting hashtables
-       ascii irc.messages irc.messages.private ;
+       ascii irc.messages ;
 RENAME: join sequences => sjoin
 EXCLUDE: sequences => join ;
 IN: irc.client
@@ -41,6 +41,7 @@ SYMBOL: +normal+
 SYMBOL: +join+
 SYMBOL: +part+
 SYMBOL: +mode+
+SYMBOL: +nick+
 
 ! listener objects
 : <irc-listener> ( -- irc-listener ) <mailbox> <mailbox> irc-listener boa ;
@@ -59,14 +60,13 @@ SYMBOL: +mode+
 ! Message objects
 ! ======================================
 
-TUPLE: participant-changed nick action ;
+TUPLE: participant-changed nick action parameter ;
 C: <participant-changed> participant-changed
 
 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-disconnected ! sent when connection is lost
 SINGLETON: irc-connected    ! sent when connection is established
-UNION: irc-broadcasted-message irc-end irc-disconnected irc-connected ;
 
 : terminate-irc ( irc-client -- )
     [ is-running>> ] keep and [
@@ -100,33 +100,54 @@ M: string to-listener ( message string -- )
     listener> [ +server-listener+ listener> ] unless*
     [ to-listener ] [ drop ] if* ;
 
+M: irc-listener to-listener ( message irc-listener -- )
+    in-messages>> mailbox-put ;
+
 : unregister-listener ( name -- )
     irc> listeners>>
         [ at [ irc-listener-end ] dip to-listener ]
         [ delete-at ]
     2bi ;
 
-M: irc-listener to-listener ( message irc-listener -- )
-    in-messages>> mailbox-put ;
+: (remove-participant) ( nick listener -- )
+    [ participants>> delete-at ]
+    [ [ +part+ f <participant-changed> ] dip to-listener ] 2bi ;
 
 : remove-participant ( nick channel -- )
-    listener> [ participants>> delete-at ] [ drop ] if* ;
+    listener> [ (remove-participant) ] [ drop ] if* ;
 
 : listeners-with-participant ( nick -- seq )
     irc> listeners>> values
     [ dup irc-channel-listener? [ participants>> key? ] [ 2drop f ] if ]
     with filter ;
 
+: to-listeners-with-participant ( message nickname -- )
+    listeners-with-participant [ to-listener ] with each ;
+
 : 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 -- )
-    listener> [ participants>> set-at ] [ 2drop ] if* ;
+    listener> [
+        [ participants>> set-at ]
+        [ [ +join+ f <participant-changed> ] dip to-listener ] 2bi
+    ] [ 2drop ] if* ;
 
 DEFER: me?
 
 : maybe-forward-join ( join -- )
-    [ prefix>> parse-name me? ] keep and
+    [ irc-message-sender me? ] keep and
     [ irc> join-messages>> mailbox-put ] when* ;
 
 ! ======================================
@@ -158,78 +179,64 @@ DEFER: me?
 : me? ( string -- ? )
     irc> profile>> nickname>> = ;
 
-: irc-message-origin ( irc-message -- name )
-    dup name>> me? [ prefix>> parse-name ] [ name>> ] if ;
+GENERIC: forward-name ( irc-message -- name )
+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 -- )
-    irc> listeners>> values [ to-listener ] with each ;
-
-GENERIC: handle-participant-change ( irc-message -- )
+UNION: single-forward join part kick mode privmsg ;
+UNION: multiple-forward nick quit ;
+UNION: broadcast-forward irc-end irc-disconnected irc-connected ;
+GENERIC: forward-message ( irc-message -- )
 
-M: join handle-participant-change ( join -- )
-    [ prefix>> parse-name +join+ <participant-changed> ]
-    [ trailing>> ] bi to-listener ;
+M: irc-message forward-message ( irc-message -- )
+    +server-listener+ listener> [ to-listener ] [ drop ] if* ;
 
-M: part handle-participant-change ( part -- )
-    [ prefix>> parse-name +part+ <participant-changed> ]
-    [ channel>> ] bi to-listener ;
+M: single-forward forward-message ( forward-single -- )
+    dup forward-name to-listener ;
 
-M: kick handle-participant-change ( kick -- )
-    [ who>> +part+ <participant-changed> ]
-    [ channel>> ] bi to-listener ;
+M: multiple-forward forward-message ( multiple-forward -- )
+    dup irc-message-sender to-listeners-with-participant ;
 
-M: quit handle-participant-change ( quit -- )
-    prefix>> parse-name
-    [ +part+ <participant-changed> ] [ listeners-with-participant ] bi
-    [ to-listener ] with each ;
+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: handle-incoming-irc ( irc-message -- )
+GENERIC: process-message ( irc-message -- )
 
-M: irc-message handle-incoming-irc ( irc-message -- )
-    +server-listener+ listener> [ to-listener ] [ drop ] if* ;
-
-M: logged-in handle-incoming-irc ( logged-in -- )
+M: object process-message ( object -- )
+    drop ;
+    
+M: logged-in process-message ( logged-in -- )
     name>> irc> profile>> (>>nickname) ;
 
-M: ping handle-incoming-irc ( ping -- )
+M: ping process-message ( ping -- )
     trailing>> /PONG ;
 
-M: nick-in-use handle-incoming-irc ( nick-in-use -- )
+M: nick-in-use process-message ( nick-in-use -- )
     name>> "_" append /NICK ;
 
-M: privmsg handle-incoming-irc ( privmsg -- )
-    dup irc-message-origin to-listener ;
+M: join process-message ( join -- )
+    [ drop +normal+ ] [ irc-message-sender ] [ trailing>> ] tri add-participant ;
 
-M: join handle-incoming-irc ( join -- )
-    { [ maybe-forward-join ]
-      [ dup trailing>> to-listener ]
-      [ [ drop +normal+ ] [ prefix>> parse-name ] [ trailing>> ] tri add-participant ]
-      [ handle-participant-change ]
-    } cleave ;
+M: part process-message ( part -- )
+    [ irc-message-sender ] [ channel>> ] bi remove-participant ;
 
-M: part handle-incoming-irc ( part -- )
-    [ dup channel>> to-listener ]
-    [ [ prefix>> parse-name ] [ channel>> ] bi remove-participant ]
-    [ handle-participant-change ]
-    tri ;
+M: kick process-message ( kick -- )
+    [ [ who>> ] [ channel>> ] bi remove-participant ]
+    [ dup who>> me? [ unregister-listener ] [ drop ] if ]
+    bi ;
 
-M: kick handle-incoming-irc ( kick -- )
-    { [ dup channel>> to-listener ]
-      [ [ who>> ] [ channel>> ] bi remove-participant ]
-      [ handle-participant-change ]
-      [ dup who>> me? [ unregister-listener ] [ drop ] if ]
-    } cleave ;
-
-M: quit handle-incoming-irc ( quit -- )
-    [ dup prefix>> parse-name listeners-with-participant
-      [ to-listener ] with each ]
-    [ handle-participant-change ]
-    [ prefix>> parse-name remove-participant-from-all ]
-    tri ;
+M: quit process-message ( quit -- )
+    irc-message-sender remove-participant-from-all ;
 
-! FIXME: implement this
-! M: mode handle-incoming-irc ( mode -- ) call-next-method ;
-! M: nick handle-incoming-irc ( nick -- ) call-next-method ;
+M: nick process-message ( nick -- )
+    [ irc-message-sender ] [ trailing>> ] bi rename-participant-in-all ;
 
 : >nick/mode ( string -- nick mode )
     dup first "+@" member? [ unclip ] [ 0 ] if participant-mode ;
@@ -238,22 +245,20 @@ M: quit handle-incoming-irc ( quit -- )
     trailing>> [ blank? ] trim " " split
     [ >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 [
         [ (>>participants) ]
-        [ [ f f <participant-changed> ] dip name>> to-listener ] bi
+        [ [ f f <participant-changed> ] dip name>> to-listener ] bi
     ] [ drop ] if* ;
 
-M: irc-broadcasted-message handle-incoming-irc ( irc-broadcasted-message -- )
-    broadcast-message-to-listeners ;
+: handle-incoming-irc ( irc-message -- )
+    [ forward-message ] [ process-message ] bi ;
 
 ! ======================================
 ! Client message handling
 ! ======================================
 
-GENERIC: handle-outgoing-irc ( obj -- )
-
-M: irc-message handle-outgoing-irc ( irc-message -- )
+: handle-outgoing-irc ( irc-message -- )
     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 ;
 
 : with-irc-client ( irc-client quot: ( -- ) -- )
-    [ current-irc-client ] dip with-variable ; inline
+    [ current-irc-client ] dip with-variable ; inline
 
 PRIVATE>
 
index 7ee0f41ab050813ada8d72ef3a3606399660b7f2..20f4f1b2772189bb669bf3ea3f7c7ce97670e466 100644 (file)
@@ -3,7 +3,9 @@ USING: kernel tools.test accessors arrays qualified
 EXCLUDE: sequences => join ;
 IN: irc.messages.tests
 
-! Parsing tests
+
+{ "someuser" } [ "someuser!n=user@some.where" parse-name ] unit-test
+
 irc-message new
     ":someuser!n=user@some.where PRIVMSG #factortest :hi" >>line
     "someuser!n=user@some.where" >>prefix
old mode 100644 (file)
new mode 100755 (executable)
index 3b9cf0a..201e8de
@@ -46,7 +46,7 @@ GENERIC: irc-command-parameters ( irc-message -- seq )
 M: irc-message irc-command-parameters ( irc-message -- seq ) parameters>> ;
 M: ping        irc-command-parameters ( ping -- 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: nick        irc-command-parameters ( nick -- seq )    drop { } ;
 M: privmsg     irc-command-parameters ( privmsg -- seq ) name>> 1array ;
@@ -98,6 +98,11 @@ M: irc-message irc-message>server-line ( irc-message -- string )
 
 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 )
     dup split-prefix split-trailing
     [ [ blank? ] trim " " split unclip swap ] dip
index 59f4526d23b05c712cbf81d2a86245eb0e13ca36..184a2b4de8fb75d1fe45b42f4bfe4572dba1b444 100755 (executable)
@@ -1,13 +1,24 @@
 ! Copyright (C) 2008 William Schlieper\r
 ! See http://factorcode.org/license.txt for BSD license.\r
 \r
-USING: accessors kernel irc.client irc.messages irc.ui namespaces ;\r
+USING: accessors kernel arrays irc.client irc.messages irc.ui namespaces ;\r
 \r
 IN: irc.ui.commands\r
 \r
 : say ( string -- )\r
-    [ client get profile>> nickname>> <own-message> print-irc ]\r
-    [ listener get write-message ] bi ;\r
+    irc-tab get\r
+    [ window>> client>> profile>> nickname>> <own-message> print-irc ]\r
+    [ listener>> write-message ] 2bi ;\r
+\r
+: join ( string -- )\r
+    irc-tab get window>> join-channel ;\r
+\r
+: query ( string -- )\r
+    irc-tab get window>> query-nick ;\r
+\r
+: whois ( string -- )\r
+    "WHOIS" swap { } clone swap  <irc-client-message>\r
+    irc-tab get listener>> write-message ;\r
 \r
 : quote ( string -- )\r
     drop ; ! THIS WILL CHANGE\r
index a524168d54111984d71dd0dc6e5f554391fbdadf..1aebfcbfcb684b0fe76d4d942703723070fefbe4 100755 (executable)
@@ -8,7 +8,7 @@ USING: accessors kernel threads combinators concurrency.mailboxes
        ui.gadgets.scrollers ui.commands ui.gadgets.frames ui.gestures\r
        ui.gadgets.tabs ui.gadgets.grids ui.gadgets.packs ui.gadgets.labels\r
        io io.styles namespaces calendar calendar.format models continuations\r
-       irc.client irc.client.private irc.messages irc.messages.private\r
+       irc.client irc.client.private irc.messages\r
        irc.ui.commandparser irc.ui.load ;\r
 \r
 RENAME: join sequences => sjoin\r
@@ -19,9 +19,12 @@ SYMBOL: listener
 \r
 SYMBOL: client\r
 \r
-TUPLE: ui-window client tabs ;\r
+TUPLE: ui-window < tabbed client ;\r
 \r
-TUPLE: irc-tab < frame listener client userlist ;\r
+M: ui-window ungraft*\r
+    client>> terminate-irc ;\r
+\r
+TUPLE: irc-tab < frame listener client window ;\r
 \r
 : write-color ( str color -- )\r
     foreground associate format ;\r
@@ -39,7 +42,7 @@ M: ping write-irc
 \r
 M: privmsg write-irc\r
     "<" blue write-color\r
-    [ prefix>> parse-name write ] keep\r
+    [ irc-message-sender write ] keep\r
     "> " blue write-color\r
     trailing>> write ;\r
 \r
@@ -61,24 +64,24 @@ M: own-message write-irc
 \r
 M: join write-irc\r
     "* " dark-green write-color\r
-    prefix>> parse-name write\r
+    irc-message-sender write\r
     " has entered the channel." dark-green write-color ;\r
 \r
 M: part write-irc\r
     "* " dark-red write-color\r
-    [ prefix>> parse-name write ] keep\r
+    [ irc-message-sender write ] keep\r
     " has left the channel" dark-red write-color\r
     trailing>> dot-or-parens dark-red write-color ;\r
 \r
 M: quit write-irc\r
     "* " dark-red write-color\r
-    [ prefix>> parse-name write ] keep\r
+    [ irc-message-sender write ] keep\r
     " has left IRC" dark-red write-color\r
     trailing>> dot-or-parens dark-red write-color ;\r
 \r
 M: kick write-irc\r
     "* " dark-red write-color\r
-    [ prefix>> parse-name write ] keep\r
+    [ irc-message-sender write ] keep\r
     " has kicked " dark-red write-color\r
     [ who>> write ] keep\r
     " from the channel" dark-red write-color\r
@@ -89,7 +92,7 @@ M: kick write-irc
 \r
 M: mode write-irc\r
     "* " blue write-color\r
-    [ prefix>> parse-name write ] keep\r
+    [ irc-message-sender write ] keep\r
     " has applied mode " blue write-color\r
     [ full-mode write ] keep\r
     " to " blue write-color\r
@@ -97,7 +100,7 @@ M: mode write-irc
 \r
 M: nick write-irc\r
     "* " blue write-color\r
-    [ prefix>> parse-name write ] keep\r
+    [ irc-message-sender write ] keep\r
     " is now known as " blue write-color\r
     trailing>> write ;\r
 \r
@@ -120,8 +123,11 @@ M: irc-listener-end write-irc
 M: irc-message write-irc\r
     drop ; ! catch all unimplemented writes, THIS WILL CHANGE    \r
 \r
-: time-happened ( irc-message -- timestamp )\r
-    [ timestamp>> ] [ 2drop now ] recover ;\r
+GENERIC: time-happened ( message -- timestamp )\r
+\r
+M: irc-message time-happened timestamp>> ;\r
+\r
+M: object time-happened drop now ;\r
 \r
 : print-irc ( irc-message -- )\r
     [ time-happened timestamp>hms write " " write ]\r
@@ -139,16 +145,6 @@ GENERIC: handle-inbox ( tab message -- )
 : add-gadget-color ( pack seq color -- pack )\r
     '[ , >>color add-gadget ] each ;\r
 \r
-: update-participants ( tab -- )\r
-    [ userlist>> [ clear-gadget ] keep ]\r
-    [ listener>> participants>> ] bi\r
-    [ +operator+ value-labels dark-green add-gadget-color ]\r
-    [ +voice+ value-labels blue add-gadget-color ]\r
-    [ +normal+ value-labels black add-gadget-color ] tri drop ;\r
-\r
-M: participant-changed handle-inbox\r
-    drop update-participants ;\r
-\r
 M: object handle-inbox\r
     nip print-irc ;\r
 \r
@@ -161,44 +157,60 @@ M: object handle-inbox
     <scrolling-pane>\r
     [ <pane-stream> swap display ] 2keep ;\r
 \r
-TUPLE: irc-editor < editor outstream listener client ;\r
+TUPLE: irc-editor < editor outstream tab ;\r
 \r
 : <irc-editor> ( tab pane -- tab editor )\r
-    over irc-editor new-editor\r
-    swap listener>> >>listener swap <pane-stream> >>outstream\r
-    over client>> >>client ;\r
+    irc-editor new-editor\r
+    swap <pane-stream> >>outstream ;\r
 \r
 : editor-send ( irc-editor -- )\r
     { [ outstream>> ]\r
-      [ listener>> ]\r
-      [ client>> ]\r
+      [ [ irc-tab? ] find-parent ]\r
       [ editor-string ]\r
       [ "" swap set-editor-string ] } cleave\r
-     '[ , listener set , client set , parse-message ] with-output-stream ;\r
+     '[ , irc-tab set , parse-message ] with-output-stream ;\r
 \r
 irc-editor "general" f {\r
     { T{ key-down f f "RET" } editor-send }\r
     { T{ key-down f f "ENTER" } editor-send }\r
 } define-command-map\r
 \r
-: <irc-tab> ( listener client -- irc-tab )\r
-    irc-tab new-frame\r
-    swap client>> >>client swap >>listener\r
+: new-irc-tab ( listener ui-window class -- irc-tab )\r
+    new-frame\r
+    swap >>window\r
+    swap >>listener\r
     <irc-pane> [ <scroller> @center grid-add ] keep\r
     <irc-editor> <scroller> @bottom grid-add ;\r
 \r
-: <irc-channel-tab> ( listener client -- irc-tab )\r
-    <irc-tab>\r
+M: irc-tab graft*\r
+    [ listener>> ] [ window>> client>> ] bi add-listener ;\r
+\r
+M: irc-tab ungraft*\r
+    [ listener>> ] [ window>> client>> ] bi remove-listener ;\r
+\r
+TUPLE: irc-channel-tab < irc-tab userlist ;\r
+\r
+: <irc-channel-tab> ( listener ui-window -- irc-tab )\r
+    irc-channel-tab new-irc-tab\r
     <pile> [ <scroller> @right grid-add ] keep >>userlist ;\r
 \r
-: <irc-server-tab> ( listener client -- irc-tab )\r
-    <irc-tab> ;\r
+: update-participants ( tab -- )\r
+    [ userlist>> [ clear-gadget ] keep ]\r
+    [ listener>> participants>> ] bi\r
+    [ +operator+ value-labels dark-green add-gadget-color ]\r
+    [ +voice+ value-labels blue add-gadget-color ]\r
+    [ +normal+ value-labels black add-gadget-color ] tri drop ;\r
 \r
-M: irc-tab graft*\r
-    [ listener>> ] [ client>> ] bi add-listener ;\r
+M: participant-changed handle-inbox\r
+    drop update-participants ;\r
 \r
-M: irc-tab ungraft*\r
-    [ listener>> ] [ client>> ] bi remove-listener ;\r
+TUPLE: irc-server-tab < irc-tab ;\r
+\r
+: <irc-server-tab> ( listener -- irc-tab )\r
+    f irc-server-tab new-irc-tab ;\r
+\r
+: <irc-nick-tab> ( listener ui-window -- irc-tab )\r
+    irc-tab new-irc-tab ;\r
 \r
 M: irc-tab pref-dim*\r
     drop { 480 480 } ;\r
@@ -206,19 +218,25 @@ M: irc-tab pref-dim*
 : join-channel ( name ui-window -- )\r
     [ dup <irc-channel-listener> ] dip\r
     [ <irc-channel-tab> swap ] keep\r
-    tabs>> add-page ;\r
+    add-page ;\r
+\r
+: query-nick ( nick ui-window -- )\r
+    [ dup <irc-nick-listener> ] dip\r
+    [ <irc-nick-tab> swap ] keep\r
+    add-page ;\r
 \r
 : irc-window ( ui-window -- )\r
-    [ tabs>> ]\r
+    [ ]\r
     [ client>> profile>> server>> ] bi\r
     open-window ;\r
 \r
 : ui-connect ( profile -- ui-window )\r
-    <irc-client> ui-window new over >>client swap\r
-    [ connect-irc ]\r
-    [ [ <irc-server-listener> ] dip add-listener ]\r
-    [ listeners>> +server-listener+ swap at over <irc-tab>\r
-      "Server" associate <tabbed> >>tabs ] tri ;\r
+    <irc-client>\r
+    { [ [ <irc-server-listener> ] dip add-listener ]\r
+      [ listeners>> +server-listener+ swap at <irc-server-tab> dup\r
+        "Server" associate ui-window new-tabbed [ swap (>>window) ] keep ]\r
+      [ >>client ]\r
+      [ connect-irc ] } cleave ;\r
 \r
 : server-open ( server port nick password channels -- )\r
     [ <irc-profile> ui-connect [ irc-window ] keep ] dip\r
index e6a2824433c3efab2da62cf0053b6d1809944652..5ef435a4e0a0ae427634d8ea847570299021134d 100644 (file)
@@ -13,11 +13,6 @@ IN: math.combinatorics.tests
 [ { 0 1 3 2 } ] [ 1 4 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 ] [ 1 factorial ] unit-test
 [ 3628800 ] [ 10 factorial ] unit-test
index f7d7b76fa4fe7656a28a543f2a3b5ade6ff4ffd6..6193edfb915d7cae6171e2a65682933c02804933 100644 (file)
@@ -1,7 +1,7 @@
 ! Copyright (c) 2007, 2008 Slava Pestov, Doug Coleman, Aaron Schaefer.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: assocs kernel math math.order math.ranges mirrors
-namespaces sequences sorting ;
+namespaces sequences sequences.lib sorting ;
 IN: math.combinatorics
 
 <PRIVATE
@@ -27,9 +27,6 @@ IN: math.combinatorics
 : permutation-indices ( n seq -- permutation )
     length [ factoradic ] dip 0 pad-left >permutation ;
 
-: reorder ( seq indices -- seq )
-    [ [ over nth , ] each drop ] { } make ;
-
 PRIVATE>
 
 : factorial ( n -- n! )
@@ -42,7 +39,7 @@ PRIVATE>
     twiddle [ nPk ] keep factorial / ;
 
 : permutation ( n seq -- seq )
-    tuck permutation-indices reorder ;
+    tuck permutation-indices nths ;
 
 : all-permutations ( seq -- seq )
     [
index 137b1605da7b6c7df3ed131494311010febb0897..3be8a6d4d3e06c81a3ccce6d04dadb9ad5f91386 100644 (file)
@@ -1 +1,2 @@
-Reginald Ford
\ No newline at end of file
+Reginald Ford
+Eduardo Cavazos
\ No newline at end of file
index 23847e82f7510471589aa0d90b9eb9cbf1cd39aa..15dd954b1c42d58cb20289c0dc86dc09d7912901 100644 (file)
@@ -1,9 +1,101 @@
-USING: help.markup help.syntax ;
-
+USING: help.markup help.syntax math.functions ;
 IN: math.derivatives
 
 HELP: derivative ( x function -- m )
-{ $values { "x" "the x-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." } ;
+{ $values { "x" "a position on the function" } { "function" "a differentiable 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. "
+    }
+} ;
+
+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"
+            
+        }
+    }
+} ;
 
-{ derivative-func } related-words
+ARTICLE: "derivatives" "The Derivative Toolkit"
+"A toolkit for computing the derivative of functions."
+{ $subsection derivative }
+{ $subsection derivative-func }
+{ $subsection (derivative) } ;
+ABOUT: "derivatives"
index d92066efaf3feb047dc24de20da995a75151c8fc..ad8d944bfe4f34b38fc7a6e158efdb24b76c04b6 100644 (file)
-! Copyright Â© 2008 Reginald Keith Ford II
-! Tool for computing the derivative of a function at a point 
-USING: kernel math math.points math.function-tools ;
+
+USING: kernel continuations combinators sequences math
+      math.order math.ranges accessors float-arrays ;
+
 IN: math.derivatives
 
-: small-amount ( -- n ) 1.0e-14 ;
-: some-more ( x -- y ) small-amount + ;
-: some-less ( x -- y ) small-amount - ;
-: derivative ( x function -- m ) [ [ some-more ] dip eval ] [ [ some-less ] dip eval ] 2bi slope ;
-: derivative-func ( function -- function ) [ derivative ] curry ;
\ No newline at end of file
+TUPLE: state x func h err i j errt fac hh ans a done ;
+
+: largest-float ( -- x ) HEX: 7fefffffffffffff bits>double ; foldable
+: ntab ( -- val ) 8 ;
+: 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 ;
\ No newline at end of file
index 802bf9e14ee8a0ad17b6a97101fc54a64fe35c15..ec93a0891a5e6b7f2b3a7b121cd995817e6dab22 100644 (file)
@@ -3,7 +3,7 @@
 
 USING: kernel math arrays sequences sequences.lib ;
 IN: math.function-tools 
-: difference-func ( func func -- func ) [ bi - ] 2curry ;
-: eval ( x func -- pt ) dupd call 2array ;
-: eval-inverse ( y func -- pt ) dupd call swap 2array ;
-: eval3d ( x y func -- pt ) [ 2dup ] dip call 3array ;
+: difference-func ( func func -- func ) [ bi - ] 2curry ; inline
+: eval ( x func -- pt ) dupd call 2array ; inline
+: eval-inverse ( y func -- pt ) dupd call swap 2array ; inline
+: eval3d ( x y func -- pt ) [ 2dup ] dip call 3array ; inline
index 1167a3b7b4e165af7b242c0abee7d23ac0467489..17f855c26417e380ebff8b2701ba3e029e8a29c2 100755 (executable)
@@ -211,8 +211,11 @@ PRIVATE>
 : insert-nth ( elt n seq -- seq' )
     swap cut-slice [ swap 1array ] dip 3append ;
 
-: if-seq ( seq quot1 quot2 -- )
-    [ f like ] 2dip if* ; inline
+: if-seq ( seq quot1 quot2 -- ) [ 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
diff --git a/extra/serial/authors.txt b/extra/serial/authors.txt
new file mode 100644 (file)
index 0000000..7c1b2f2
--- /dev/null
@@ -0,0 +1 @@
+Doug Coleman
diff --git a/extra/serial/serial.factor b/extra/serial/serial.factor
new file mode 100644 (file)
index 0000000..39a6392
--- /dev/null
@@ -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
diff --git a/extra/serial/summary.txt b/extra/serial/summary.txt
new file mode 100644 (file)
index 0000000..5ccd99d
--- /dev/null
@@ -0,0 +1 @@
+Serial port library
diff --git a/extra/serial/tags.txt b/extra/serial/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/serial/unix/bsd/bsd.factor b/extra/serial/unix/bsd/bsd.factor
new file mode 100644 (file)
index 0000000..feed853
--- /dev/null
@@ -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
diff --git a/extra/serial/unix/bsd/tags.txt b/extra/serial/unix/bsd/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/serial/unix/linux/linux.factor b/extra/serial/unix/linux/linux.factor
new file mode 100644 (file)
index 0000000..3ad5088
--- /dev/null
@@ -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 ;
diff --git a/extra/serial/unix/linux/tags.txt b/extra/serial/unix/linux/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/serial/unix/tags.txt b/extra/serial/unix/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/serial/unix/termios/bsd/bsd.factor b/extra/serial/unix/termios/bsd/bsd.factor
new file mode 100644 (file)
index 0000000..5fbc571
--- /dev/null
@@ -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
diff --git a/extra/serial/unix/termios/bsd/tags.txt b/extra/serial/unix/termios/bsd/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/serial/unix/termios/linux/linux.factor b/extra/serial/unix/termios/linux/linux.factor
new file mode 100644 (file)
index 0000000..de9906e
--- /dev/null
@@ -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
diff --git a/extra/serial/unix/termios/linux/tags.txt b/extra/serial/unix/termios/linux/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/serial/unix/termios/tags.txt b/extra/serial/unix/termios/tags.txt
new file mode 100644 (file)
index 0000000..6bf6830
--- /dev/null
@@ -0,0 +1 @@
+unportable
diff --git a/extra/serial/unix/termios/termios.factor b/extra/serial/unix/termios/termios.factor
new file mode 100644 (file)
index 0000000..901416d
--- /dev/null
@@ -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
diff --git a/extra/serial/unix/unix-tests.factor b/extra/serial/unix/unix-tests.factor
new file mode 100644 (file)
index 0000000..bab6c3f
--- /dev/null
@@ -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 ;
diff --git a/extra/serial/unix/unix.factor b/extra/serial/unix/unix.factor
new file mode 100644 (file)
index 0000000..7ed5bce
--- /dev/null
@@ -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 ;
diff --git a/unfinished/compiler/cfg/builder/builder-tests.factor b/unfinished/compiler/cfg/builder/builder-tests.factor
new file mode 100644 (file)
index 0000000..098919c
--- /dev/null
@@ -0,0 +1,4 @@
+IN: compiler.cfg.builder.tests
+USING: compiler.cfg.builder tools.test ;
+
+\ build-cfg must-infer
index 2f68864e81d47ba26ecec35bc312fe26cf5a4882..76a1b67dd2319622deae62a1cea16fa93f2fdb14 100644 (file)
@@ -1,29 +1,33 @@
 ! Copyright (C) 2008 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: arrays kernel assocs sequences sequences.lib fry accessors
-compiler.cfg compiler.vops compiler.vops.builder
-namespaces math inference.dataflow optimizer.allot combinators
-math.order ;
+namespaces math combinators math.order
+compiler.tree
+compiler.tree.combinators
+compiler.tree.propagation.info
+compiler.cfg
+compiler.vops
+compiler.vops.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
 ! set predecessors in a separate pass. This simplifies the
 ! logic.
 
 SYMBOL: procedures
 
-SYMBOL: values>vregs
-
 SYMBOL: loop-nesting
 
-GENERIC: convert* ( node -- )
+SYMBOL: values>vregs
 
 GENERIC: convert ( node -- )
 
+M: #introduce convert drop ;
+
 : init-builder ( -- )
-    H{ } clone values>vregs set
-    V{ } clone loop-nesting set ;
+    H{ } clone values>vregs set ;
 
 : end-basic-block ( -- )
     basic-block get [ %b emit ] when ;
@@ -40,15 +44,12 @@ GENERIC: convert ( node -- )
     set-basic-block ;
 
 : convert-nodes ( node -- )
-    dup basic-block get and [
-        [ convert ] [ successor>> convert-nodes ] bi
-    ] [ drop ] if ;
+    [ convert ] each ;
 
 : (build-cfg) ( node word -- )
     init-builder
     begin-basic-block
     basic-block get swap procedures get set-at
-    %prolog emit
     convert-nodes ;
 
 : build-cfg ( node word -- procedures )
@@ -73,10 +74,9 @@ GENERIC: convert ( node -- )
         2bi
     ] if ;
 
-: load-inputs ( node -- )
-    [ in-d>> %data (load-inputs) ]
-    [ in-r>> %retain (load-inputs) ]
-    bi ;
+: load-in-d ( node -- ) in-d>> %data (load-inputs) ;
+
+: load-in-r ( node -- ) in-r>> %retain (load-inputs) ;
 
 : (store-outputs) ( seq stack -- )
     over empty? [ 2drop ] [
@@ -86,40 +86,21 @@ GENERIC: convert ( node -- )
         2bi
     ] if ;
 
-: store-outputs ( node -- )
-    [ out-d>> %data (store-outputs) ]
-    [ out-r>> %retain (store-outputs) ]
-    bi ;
-
-M: #push convert*
-    out-d>> [
-        [ produce-vreg ] [ value-literal ] bi
-        emit-literal
-    ] each ;
+: store-out-d ( node -- ) out-d>> %data (store-outputs) ;
 
-M: #shuffle convert* drop ;
-
-M: #>r convert* drop ;
-
-M: #r> convert* drop ;
-
-M: node convert
-    [ load-inputs ]
-    [ convert* ]
-    [ store-outputs ]
-    tri ;
+: store-out-r ( node -- ) out-r>> %retain (store-outputs) ;
 
 : (emit-call) ( word -- )
     begin-basic-block %call emit begin-basic-block ;
 
 : intrinsic-inputs ( node -- )
-    [ load-inputs ]
+    [ load-in-d ]
     [ in-d>> { #1 #2 #3 #4 } [ [ value>vreg ] dip set ] 2each ]
     bi ;
 
 : intrinsic-outputs ( node -- )
     [ out-d>> { ^1 ^2 ^3 ^4 } [ get output-vreg ] 2each ]
-    [ store-outputs ]
+    [ store-out-d ]
     bi ;
 
 : intrinsic ( node quot -- )
@@ -132,19 +113,17 @@ M: node convert
         tri
     ] with-scope ; inline
 
-USING: kernel.private math.private slots.private
-optimizer.allot ;
+USING: kernel.private math.private slots.private ;
 
 : maybe-emit-fixnum-shift-fast ( node -- node )
-    dup dup in-d>> second node-literal? [
-        dup dup in-d>> second node-literal
+    dup dup in-d>> second node-value-info literal>> dup fixnum? [
         '[ , emit-fixnum-shift-fast ] intrinsic
     ] [
-        dup param>> (emit-call)
+        drop dup word>> (emit-call)
     ] if ;
 
 : emit-call ( node -- )
-    dup param>> {
+    dup word>> {
         { \ tag [ [ emit-tag ] intrinsic ] }
 
         { \ slot [ [ dup emit-slot ] intrinsic ] }
@@ -175,24 +154,43 @@ optimizer.allot ;
         { \ float> [ [ emit-float> ] intrinsic ] }
         { \ float? [ [ emit-float= ] intrinsic ] }
 
-        { \ (tuple) [ dup first-input '[ , emit-(tuple) ] intrinsic ] }
-        { \ (array) [ dup first-input '[ , emit-(array) ] intrinsic ] }
-        { \ (byte-array) [ dup first-input '[ , emit-(byte-array) ] intrinsic ] }
+        { \ (tuple) [ dup first-input '[ , emit-(tuple) ] intrinsic ] }
+        { \ (array) [ dup first-input '[ , emit-(array) ] intrinsic ] }
+        { \ (byte-array) [ dup first-input '[ , emit-(byte-array) ] intrinsic ] }
 
         [ (emit-call) ]
     } case drop ;
 
 M: #call convert emit-call ;
 
-M: #call-label convert
-    dup param>> loop-nesting get at [
-        basic-block get successors>> push
-        end-basic-block
-        basic-block off
-        drop
-    ] [
-        (emit-call)
-    ] if* ;
+: emit-call-loop ( #recursive -- )
+    dup label>> loop-nesting get at basic-block get successors>> push
+    end-basic-block
+    basic-block off
+    drop ;
+
+: emit-call-recursive ( #recursive -- )
+    label>> id>> (emit-call) ;
+
+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 -- )
     [ [ next-vreg dup ] 2dip %icmp emit ] dip %bi emit ; inline
@@ -221,50 +219,38 @@ M: #call-label convert
     [ set-basic-block ]
     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
-    {
-        [ load-inputs ]
-        [ emit-if ]
-        [ convert-if-children ]
-        [ emit-phi ]
-    } cleave ;
+    [ load-in-d ] [ emit-if ] [ convert-if-children ] tri ;
 
-M: #values convert drop ;
+M: #dispatch convert
+    "Unimplemented" throw ;
 
-M: #merge convert drop ;
-
-M: #entry convert drop ;
+M: #phi convert drop ;
 
 M: #declare convert drop ;
 
-M: #terminate convert drop ;
+M: #return convert drop %return emit ;
 
-M: #label convert
-    #! Labels create a new procedure.
-    [ [ param>> ] [ node-child ] bi (build-cfg) ] [ (emit-call) ] bi ;
+: convert-recursive ( #recursive -- )
+    [ [ label>> id>> ] [ child>> ] bi (build-cfg) ]
+    [ (emit-call) ]
+    bi ;
 
-M: #loop convert
-    #! Loops become part of the current CFG.
-    begin-basic-block
-    [ param>> basic-block get 2array loop-nesting get push ]
-    [ node-child convert-nodes ]
-    bi
+: begin-loop ( #recursive -- )
+    label>> basic-block get 2array loop-nesting get push ;
+
+: end-loop ( -- )
     loop-nesting get pop* ;
 
-M: #return convert
-    param>> loop-nesting get key? [
-        %epilog emit
-        %return emit
-    ] unless ;
+: convert-loop ( #recursive -- )
+    begin-basic-block
+    [ begin-loop ]
+    [ child>> convert-nodes ]
+    [ drop end-loop ]
+    tri ;
+
+M: #recursive convert
+    dup label>> loop?>>
+    [ convert-loop ] [ convert-recursive ] if ;
+
+M: #copy convert drop ;
diff --git a/unfinished/compiler/generator/authors.txt b/unfinished/compiler/generator/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/unfinished/compiler/generator/fixup/authors.txt b/unfinished/compiler/generator/fixup/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/unfinished/compiler/generator/fixup/fixup-docs.factor b/unfinished/compiler/generator/fixup/fixup-docs.factor
new file mode 100644 (file)
index 0000000..a4ff549
--- /dev/null
@@ -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."
+} ;
diff --git a/unfinished/compiler/generator/fixup/fixup.factor b/unfinished/compiler/generator/fixup/fixup.factor
new file mode 100755 (executable)
index 0000000..e1b4e42
--- /dev/null
@@ -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 ;
diff --git a/unfinished/compiler/generator/fixup/summary.txt b/unfinished/compiler/generator/fixup/summary.txt
new file mode 100644 (file)
index 0000000..ce83e6d
--- /dev/null
@@ -0,0 +1 @@
+Support for generation of relocatable code
diff --git a/unfinished/compiler/generator/generator-docs.factor b/unfinished/compiler/generator/generator-docs.factor
new file mode 100755 (executable)
index 0000000..e00b8d5
--- /dev/null
@@ -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." } ;
diff --git a/unfinished/compiler/generator/generator.factor b/unfinished/compiler/generator/generator.factor
new file mode 100755 (executable)
index 0000000..a4a7815
--- /dev/null
@@ -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 ;
diff --git a/unfinished/compiler/generator/iterator/iterator.factor b/unfinished/compiler/generator/iterator/iterator.factor
new file mode 100644 (file)
index 0000000..6888199
--- /dev/null
@@ -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? ;
diff --git a/unfinished/compiler/generator/registers/authors.txt b/unfinished/compiler/generator/registers/authors.txt
new file mode 100644 (file)
index 0000000..1901f27
--- /dev/null
@@ -0,0 +1 @@
+Slava Pestov
diff --git a/unfinished/compiler/generator/registers/registers.factor b/unfinished/compiler/generator/registers/registers.factor
new file mode 100755 (executable)
index 0000000..dc32afb
--- /dev/null
@@ -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 ;
diff --git a/unfinished/compiler/generator/registers/summary.txt b/unfinished/compiler/generator/registers/summary.txt
new file mode 100644 (file)
index 0000000..89a46af
--- /dev/null
@@ -0,0 +1 @@
+Register allocation and intrinsic selection
diff --git a/unfinished/compiler/generator/summary.txt b/unfinished/compiler/generator/summary.txt
new file mode 100644 (file)
index 0000000..cf857ad
--- /dev/null
@@ -0,0 +1 @@
+Final stage of compilation generates machine code from dataflow IR
diff --git a/unfinished/compiler/generator/tags.txt b/unfinished/compiler/generator/tags.txt
new file mode 100644 (file)
index 0000000..86a7c8e
--- /dev/null
@@ -0,0 +1 @@
+compiler
diff --git a/unfinished/compiler/machine/debug/debug.factor b/unfinished/compiler/machine/debug/debug.factor
deleted file mode 100644 (file)
index f83dada..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-! Copyright (C) 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel namespaces sequences assocs io
-prettyprint inference generator optimizer compiler.vops
-compiler.cfg.builder compiler.cfg.simplifier
-compiler.machine.builder compiler.machine.simplifier ;
-IN: compiler.machine.debug
-
-: dataflow>linear ( dataflow word -- linear )
-    [
-        init-counter
-        build-cfg
-        [ simplify-cfg build-mr simplify-mr ] assoc-map
-    ] with-scope ;
-
-: linear. ( linear -- )
-    [
-        "==== " write swap .
-        [ . ] each
-    ] assoc-each ;
-
-: linearized-quot. ( quot -- )
-    dataflow optimize
-    "Anonymous quotation" dataflow>linear
-    linear. ;
-
-: linearized-word. ( word -- )
-    dup word-dataflow nip optimize swap dataflow>linear linear. ;
-
-: >basic-block ( quot -- basic-block )
-    dataflow optimize
-    [
-        init-counter
-        "Anonymous quotation" build-cfg
-        >alist first second simplify-cfg
-    ] with-scope ;
-
-: basic-block. ( basic-block -- )
-    instructions>> [ . ] each ;
diff --git a/unfinished/compiler/machine/debugger/debugger.factor b/unfinished/compiler/machine/debugger/debugger.factor
new file mode 100644 (file)
index 0000000..adc84d7
--- /dev/null
@@ -0,0 +1,45 @@
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel namespaces sequences assocs io
+prettyprint inference generator optimizer
+compiler.vops
+compiler.tree.builder
+compiler.tree.optimizer
+compiler.cfg.builder
+compiler.cfg.simplifier
+compiler.machine.builder
+compiler.machine.simplifier ;
+IN: compiler.machine.debugger
+
+: tree>linear ( tree word -- linear )
+    [
+        init-counter
+        build-cfg
+        [ simplify-cfg build-mr simplify-mr ] assoc-map
+    ] with-scope ;
+
+: linear. ( linear -- )
+    [
+        "==== " write swap .
+        [ . ] each
+    ] assoc-each ;
+
+: linearized-quot. ( quot -- )
+    build-tree optimize-tree
+    "Anonymous quotation" tree>linear
+    linear. ;
+
+: linearized-word. ( word -- )
+    dup build-tree-from-word nip optimize-tree
+    dup word-dataflow nip optimize swap tree>linear linear. ;
+
+: >basic-block ( quot -- basic-block )
+    build-tree optimize-tree
+    [
+        init-counter
+        "Anonymous quotation" build-cfg
+        >alist first second simplify-cfg
+    ] with-scope ;
+
+: basic-block. ( basic-block -- )
+    instructions>> [ . ] each ;
index c9caeb864b8ba6208576ebabfc9fbce04f021a4a..d69202c7ad0f7708162da7b4e095e332ca0414da 100644 (file)
@@ -35,6 +35,12 @@ M: #phi backward
     [ [ out-r>> ] [ phi-in-r>> ] bi look-at-corresponding ]
     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 ;
 
 : backward-dfa ( node quot -- assoc ) [ backward ] dfa ; inline
index 6703f924fd511ccdeb607d51823ac5516d679554..652fa19af330cbbb7854ea0345d9bc2688a5f236 100644 (file)
@@ -23,6 +23,12 @@ M: #call mark-live-values
     dup word>> "flushable" word-prop
     [ 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
     look-at-inputs ;
 
diff --git a/unfinished/compiler/tree/debugger/debugger-tests.factor b/unfinished/compiler/tree/debugger/debugger-tests.factor
new file mode 100644 (file)
index 0000000..eb0bbd5
--- /dev/null
@@ -0,0 +1,5 @@
+IN: compiler.tree.debugger.tests
+USING: compiler.tree.debugger tools.test ;
+
+\ optimized. must-infer
+\ optimizer-report. must-infer
diff --git a/unfinished/compiler/tree/debugger/debugger.factor b/unfinished/compiler/tree/debugger/debugger.factor
new file mode 100644 (file)
index 0000000..c541311
--- /dev/null
@@ -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. ;
index c6c407b048d663fe7b1c46541cc2ca05a83bb0e1..af42dc5145433e84f86af8e796483ca2d70fcb68 100644 (file)
@@ -80,3 +80,13 @@ M: #call escape-analysis*
 
 M: #return escape-analysis*
     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 ;
diff --git a/unfinished/compiler/tree/loop/inversion/inversion.factor b/unfinished/compiler/tree/loop/inversion/inversion.factor
new file mode 100644 (file)
index 0000000..719fc4a
--- /dev/null
@@ -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' ) ;
diff --git a/unfinished/compiler/tree/optimizer/optimizer-tests.factor b/unfinished/compiler/tree/optimizer/optimizer-tests.factor
new file mode 100644 (file)
index 0000000..1075e44
--- /dev/null
@@ -0,0 +1,4 @@
+USING: compiler.tree.optimizer tools.test ;
+IN: compiler.tree.optimizer.tests
+
+\ optimize-tree must-infer
index 24df9b5af341f85475c2889640991d102b165fb8..2d2a376bc0ed6091da22117b04a74ff8be9a3a18 100644 (file)
@@ -9,6 +9,7 @@ compiler.tree.def-use
 compiler.tree.dead-code
 compiler.tree.strength-reduction
 compiler.tree.loop.detection
+compiler.tree.loop.inversion
 compiler.tree.branch-fusion ;
 IN: compiler.tree.optimizer
 
index 42377386256f1a06496fbea37cb6ea293c1b116b..45bbbf19db3df7b48112443346d4ccd0821d579f 100644 (file)
@@ -115,3 +115,9 @@ M: #call propagate-before
 M: #call propagate-after
     dup word>> "input-classes" word-prop dup
     [ 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 ;
index 016afc3e89934e6fa6b754a9753088cb6cd07c04..175c1ddfdda29bea03d5f2eb3d4a338131784baf 100755 (executable)
@@ -143,6 +143,30 @@ TUPLE: #copy < #renaming in-d out-d ;
         swap >>out-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 ;
 
 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: #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 #introduce, #introduce node, ;
 M: vector #call, #call node, ;
@@ -172,3 +201,6 @@ M: vector #phi, #phi node, ;
 M: vector #declare, #declare node, ;
 M: vector #recursive, #recursive 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, ;
index 3b832917d8219274ef9eb4941dbfc854a37568b6..1b92d66db4b0bd5414f2b6ff8982b2fb0cbb660e 100644 (file)
@@ -128,4 +128,8 @@ M: #return unbox-tuples* dup in-d>> assert-not-unboxed ;
 
 M: #introduce unbox-tuples* dup value>> assert-not-unboxed ;
 
+M: #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 ;
diff --git a/unfinished/stack-checker/alien/alien.factor b/unfinished/stack-checker/alien/alien.factor
new file mode 100644 (file)
index 0000000..f81b7fd
--- /dev/null
@@ -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, ;
index 6442bc5740212adc5ee55eae2fb4e248ec5e5d31..3be2e21b7ecbc023da52297d484b1d3ef26c2488 100644 (file)
@@ -28,9 +28,11 @@ loop? ;
 
 M: inline-recursive hashcode* id>> hashcode* ;
 
+: inlined-block? ( word -- ? ) "inlined-block" word-prop ;
+
 : <inline-recursive> ( word -- label )
     inline-recursive new
-        gensym >>id
+        gensym dup t "inlined-block" set-word-prop >>id
         swap >>word ;
 
 : quotation-param? ( obj -- ? )
index 2e0c979f98c596717eddb6e44b9159d85d528529..a0c91f679bb24498376b627373f50c8ec80d4755 100755 (executable)
@@ -10,10 +10,14 @@ sequences sequences.private slots.private strings
 strings.private system threads.private classes.tuple
 classes.tuple.private vectors vectors.private words definitions
 words.private assocs summary compiler.units system.private
-combinators locals.backend stack-checker.state
-stack-checker.backend stack-checker.branches
-stack-checker.errors stack-checker.transforms
-stack-checker.visitor ;
+combinators locals.backend
+stack-checker.state
+stack-checker.backend
+stack-checker.branches
+stack-checker.errors
+stack-checker.transforms
+stack-checker.visitor
+stack-checker.alien ;
 IN: stack-checker.known-words
 
 : infer-primitive ( word -- )
@@ -153,13 +157,15 @@ M: object infer-call*
         { \ get-local [ infer-get-local ] }
         { \ drop-locals [ infer-drop-locals ] }
         { \ do-primitive [ \ do-primitive cannot-infer-effect ] }
+        { \ alien-invoke [ infer-alien-invoke ] }
+        { \ alien-indirect [ infer-alien-indirect ] }
+        { \ alien-callback [ infer-alien-callback ] }
     } case ;
 
 {
-    >r r> declare call curry compose
-    execute if dispatch <tuple-boa>
-    (throw) load-locals get-local drop-locals
-    do-primitive
+    >r r> declare call curry compose execute if dispatch
+    <tuple-boa> (throw) load-locals get-local drop-locals
+    do-primitive alien-invoke alien-indirect alien-callback
 } [ t +special+ set-word-prop ] each
 
 { call execute dispatch load-locals get-local drop-locals }
@@ -173,10 +179,10 @@ SYMBOL: +primitive+
         { [ dup +shuffle+ word-prop ] [ infer-shuffle-word ] }
         { [ dup +special+ word-prop ] [ infer-special ] }
         { [ dup +primitive+ word-prop ] [ infer-primitive ] }
-        { [ dup +cannot-infer+ word-prop ] [ cannot-infer-effect ] }
         { [ dup +transform-quot+ word-prop ] [ apply-transform ] }
-        { [ dup +inferred-effect+ word-prop ] [ cached-infer ] }
         { [ 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 infer-word apply-word/effect ]
     } cond ;
index d9e889f1880e7c0c86921efb9c3cb5b68037ffa8..f22960dd39dc01dd6b4441ccfa565b0f554f9f1c 100755 (executable)
@@ -23,10 +23,11 @@ SYMBOL: +transform-n+
     inline
 
 : (apply-transform) ( word quot n -- )
-    consume-d dup [ known literal? ] all? [
+    dup ensure-d [ known literal? ] all? [
         dup empty? [
             drop recursive-state get 1array
         ] [
+            consume-d
             [ #drop, ]
             [ [ literal value>> ] map ]
             [ first literal recursion>> ] tri prefix
@@ -123,7 +124,6 @@ SYMBOL: +transform-n+
 
 : bit-member-quot ( seq -- newquot )
     [
-        [ drop ] % ! drop the sequence itself; we don't use it at run time
         bit-member-seq ,
         [
             {
@@ -140,7 +140,7 @@ SYMBOL: +transform-n+
         bit-member-quot
     ] [
         [ literalize [ t ] ] { } map>assoc
-        [ drop f ] suffix [ nip case ] curry
+        [ drop f ] suffix [ case ] curry
     ] if ;
 
 \ member? [
index a1ed5c83a1a9b2cb9efe7a94f4d91d2ac0b2594d..381405bd3174ac181d80efd0bb20bffa8d8dc13e 100644 (file)
@@ -22,3 +22,6 @@ M: f #declare, drop ;
 M: f #recursive, 2drop 2drop ;
 M: f #copy, 2drop ;
 M: f #drop, drop ;
+M: f #alien-invoke, drop ;
+M: f #alien-indirect, drop ;
+M: f #alien-callback, drop ;
index 3afc8f752d766722b1bfa54532467f4806201bf0..25775ca3f09802cd590fe1b39d970ec8ed69e6db 100644 (file)
@@ -27,3 +27,6 @@ HOOK: #enter-recursive, stack-visitor ( label inputs outputs -- )
 HOOK: #return-recursive, stack-visitor ( label inputs outputs -- )
 HOOK: #recursive, stack-visitor ( word label inputs visitor -- )
 HOOK: #copy, stack-visitor ( inputs outputs -- )
+HOOK: #alien-invoke, stack-visitor ( params -- )
+HOOK: #alien-indirect, stack-visitor ( params -- )
+HOOK: #alien-callback, stack-visitor ( params -- )