Merge branch 'master' of git://factorcode.org/git/factor
						commit
						0df70f72bd
					
				| 
						 | 
				
			
			@ -6,7 +6,7 @@ math.parser math.order layouts words sequences sequences.private
 | 
			
		|||
arrays assocs classes classes.algebra combinators generic.math
 | 
			
		||||
splitting fry locals classes.tuple alien.accessors
 | 
			
		||||
classes.tuple.private slots.private definitions strings.private
 | 
			
		||||
vectors hashtables
 | 
			
		||||
vectors hashtables generic
 | 
			
		||||
stack-checker.state
 | 
			
		||||
compiler.tree.comparisons
 | 
			
		||||
compiler.tree.propagation.info
 | 
			
		||||
| 
						 | 
				
			
			@ -337,3 +337,12 @@ generic-comparison-ops [
 | 
			
		|||
        bi
 | 
			
		||||
    ] [ 2drop object-info ] if
 | 
			
		||||
] "outputs" set-word-prop
 | 
			
		||||
 | 
			
		||||
\ equal? [
 | 
			
		||||
    ! If first input has a known type and second input is an
 | 
			
		||||
    ! object, we convert this to [ swap equal? ].
 | 
			
		||||
    in-d>> first2 value-info class>> object class= [
 | 
			
		||||
        value-info class>> \ equal? specific-method
 | 
			
		||||
        [ swap equal? ] f ?
 | 
			
		||||
    ] [ drop f ] if
 | 
			
		||||
] "custom-inlining" set-word-prop
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -640,6 +640,10 @@ MIXIN: empty-mixin
 | 
			
		|||
    [ { fixnum } declare log2 0 >= ] final-classes
 | 
			
		||||
] unit-test
 | 
			
		||||
 | 
			
		||||
[ V{ POSTPONE: f } ] [
 | 
			
		||||
    [ { word object } declare eq? ] final-classes
 | 
			
		||||
] unit-test
 | 
			
		||||
 | 
			
		||||
! [ V{ string } ] [
 | 
			
		||||
!     [ dup string? t xor [ "A" throw ] [ ] if ] final-classes
 | 
			
		||||
! ] unit-test
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,8 @@
 | 
			
		|||
USING: parser words definitions kernel sequences assocs arrays
 | 
			
		||||
kernel.private fry combinators accessors vectors strings sbufs
 | 
			
		||||
byte-arrays byte-vectors io.binary io.streams.string splitting
 | 
			
		||||
math generic generic.standard generic.standard.engines classes ;
 | 
			
		||||
math generic generic.standard generic.standard.engines classes
 | 
			
		||||
hashtables ;
 | 
			
		||||
IN: hints
 | 
			
		||||
 | 
			
		||||
GENERIC: specializer-predicate ( spec -- quot )
 | 
			
		||||
| 
						 | 
				
			
			@ -50,14 +51,10 @@ M: object specializer-declaration class ;
 | 
			
		|||
    ] [ drop f ] if ;
 | 
			
		||||
 | 
			
		||||
: specialized-def ( word -- quot )
 | 
			
		||||
    dup def>> swap {
 | 
			
		||||
        {
 | 
			
		||||
            [ dup "specializer" word-prop ]
 | 
			
		||||
            [ "specializer" word-prop specialize-quot ]
 | 
			
		||||
        }
 | 
			
		||||
        { [ dup standard-method? ] [ specialize-method ] }
 | 
			
		||||
        [ drop ]
 | 
			
		||||
    } cond ;
 | 
			
		||||
    [ def>> ] keep
 | 
			
		||||
    [ dup standard-method? [ specialize-method ] [ drop ] if ]
 | 
			
		||||
    [ "specializer" word-prop [ specialize-quot ] when* ]
 | 
			
		||||
    bi ;
 | 
			
		||||
 | 
			
		||||
: specialized-length ( specializer -- n )
 | 
			
		||||
    dup [ array? ] all? [ first ] when length ;
 | 
			
		||||
| 
						 | 
				
			
			@ -120,3 +117,7 @@ M: object specializer-declaration class ;
 | 
			
		|||
\ >le { { fixnum fixnum } { bignum fixnum } } "specializer" set-word-prop
 | 
			
		||||
 | 
			
		||||
\ >be { { bignum fixnum } { fixnum fixnum } } "specializer" set-word-prop
 | 
			
		||||
 | 
			
		||||
\ hashtable \ at* method { { fixnum hashtable } { word hashtable } } "specializer" set-word-prop
 | 
			
		||||
 | 
			
		||||
\ hashtable \ set-at method { { object fixnum object } { object word object } } "specializer" set-word-prop
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ io.backend.windows io.files.windows io.encodings.utf16n windows
 | 
			
		|||
windows.kernel32 kernel libc math threads system environment
 | 
			
		||||
alien.c-types alien.arrays alien.strings sequences combinators
 | 
			
		||||
combinators.short-circuit ascii splitting alien strings assocs
 | 
			
		||||
namespaces make accessors tr ;
 | 
			
		||||
namespaces make accessors tr windows.time ;
 | 
			
		||||
IN: io.files.windows.nt
 | 
			
		||||
 | 
			
		||||
M: winnt cwd
 | 
			
		||||
| 
						 | 
				
			
			@ -44,8 +44,18 @@ M: winnt normalize-path ( string -- string' )
 | 
			
		|||
M: winnt CreateFile-flags ( DWORD -- DWORD )
 | 
			
		||||
    FILE_FLAG_OVERLAPPED bitor ;
 | 
			
		||||
 | 
			
		||||
<PRIVATE
 | 
			
		||||
 | 
			
		||||
: windows-file-size ( path -- size )
 | 
			
		||||
    normalize-path 0 "WIN32_FILE_ATTRIBUTE_DATA" <c-object>
 | 
			
		||||
    [ GetFileAttributesEx win32-error=0/f ] keep
 | 
			
		||||
    [ WIN32_FILE_ATTRIBUTE_DATA-nFileSizeLow ]
 | 
			
		||||
    [ WIN32_FILE_ATTRIBUTE_DATA-nFileSizeHigh ] bi >64bit ;
 | 
			
		||||
 | 
			
		||||
PRIVATE>
 | 
			
		||||
 | 
			
		||||
M: winnt open-append
 | 
			
		||||
    0 ! [ dup file-info size>> ] [ drop 0 ] recover
 | 
			
		||||
    [ dup windows-file-size ] [ drop 0 ] recover
 | 
			
		||||
    [ (open-append) ] dip >>ptr ;
 | 
			
		||||
 | 
			
		||||
M: winnt home "USERPROFILE" os-env ;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,8 +41,11 @@ IN: io.launcher.windows.nt.tests
 | 
			
		|||
    try-process
 | 
			
		||||
] unit-test
 | 
			
		||||
 | 
			
		||||
: launcher-test-path ( -- str )
 | 
			
		||||
    "resource:basis/io/launcher/windows/nt/test" ;
 | 
			
		||||
 | 
			
		||||
[ ] [
 | 
			
		||||
    "resource:basis/io/windows/nt/launcher/test" [
 | 
			
		||||
    launcher-test-path [
 | 
			
		||||
        <process>
 | 
			
		||||
            vm "-script" "stderr.factor" 3array >>command
 | 
			
		||||
            "out.txt" temp-file >>stdout
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +63,7 @@ IN: io.launcher.windows.nt.tests
 | 
			
		|||
] unit-test
 | 
			
		||||
 | 
			
		||||
[ ] [
 | 
			
		||||
    "resource:basis/io/windows/nt/launcher/test" [
 | 
			
		||||
    launcher-test-path [
 | 
			
		||||
        <process>
 | 
			
		||||
            vm "-script" "stderr.factor" 3array >>command
 | 
			
		||||
            "out.txt" temp-file >>stdout
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +77,7 @@ IN: io.launcher.windows.nt.tests
 | 
			
		|||
] unit-test
 | 
			
		||||
 | 
			
		||||
[ "output" ] [
 | 
			
		||||
    "resource:basis/io/windows/nt/launcher/test" [
 | 
			
		||||
    launcher-test-path [
 | 
			
		||||
        <process>
 | 
			
		||||
            vm "-script" "stderr.factor" 3array >>command
 | 
			
		||||
            "err2.txt" temp-file >>stderr
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +90,7 @@ IN: io.launcher.windows.nt.tests
 | 
			
		|||
] unit-test
 | 
			
		||||
 | 
			
		||||
[ t ] [
 | 
			
		||||
    "resource:basis/io/windows/nt/launcher/test" [
 | 
			
		||||
    launcher-test-path [
 | 
			
		||||
        <process>
 | 
			
		||||
            vm "-script" "env.factor" 3array >>command
 | 
			
		||||
        ascii <process-reader> contents
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +100,7 @@ IN: io.launcher.windows.nt.tests
 | 
			
		|||
] unit-test
 | 
			
		||||
 | 
			
		||||
[ t ] [
 | 
			
		||||
    "resource:basis/io/windows/nt/launcher/test" [
 | 
			
		||||
    launcher-test-path [
 | 
			
		||||
        <process>
 | 
			
		||||
            vm "-script" "env.factor" 3array >>command
 | 
			
		||||
            +replace-environment+ >>environment-mode
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +112,7 @@ IN: io.launcher.windows.nt.tests
 | 
			
		|||
] unit-test
 | 
			
		||||
 | 
			
		||||
[ "B" ] [
 | 
			
		||||
    "resource:basis/io/windows/nt/launcher/test" [
 | 
			
		||||
    launcher-test-path [
 | 
			
		||||
        <process>
 | 
			
		||||
            vm "-script" "env.factor" 3array >>command
 | 
			
		||||
            { { "A" "B" } } >>environment
 | 
			
		||||
| 
						 | 
				
			
			@ -120,7 +123,7 @@ IN: io.launcher.windows.nt.tests
 | 
			
		|||
] unit-test
 | 
			
		||||
 | 
			
		||||
[ f ] [
 | 
			
		||||
    "resource:basis/io/windows/nt/launcher/test" [
 | 
			
		||||
    launcher-test-path [
 | 
			
		||||
        <process>
 | 
			
		||||
            vm "-script" "env.factor" 3array >>command
 | 
			
		||||
            { { "USERPROFILE" "XXX" } } >>environment
 | 
			
		||||
| 
						 | 
				
			
			@ -146,7 +149,7 @@ IN: io.launcher.windows.nt.tests
 | 
			
		|||
 | 
			
		||||
[ "Hello appender\r\nHello appender\r\n" ] [
 | 
			
		||||
    2 [
 | 
			
		||||
        "resource:basis/io/windows/nt/launcher/test" [
 | 
			
		||||
        launcher-test-path [
 | 
			
		||||
            <process>
 | 
			
		||||
                vm "-script" "append.factor" 3array >>command
 | 
			
		||||
                "append-test" temp-file <appender> >>stdout
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,74 +15,74 @@ TYPEDEF: void* SOCKET
 | 
			
		|||
: <wsadata> ( -- byte-array )
 | 
			
		||||
    HEX: 190 <byte-array> ;
 | 
			
		||||
 | 
			
		||||
: SOCK_STREAM    1 ; inline
 | 
			
		||||
: SOCK_DGRAM     2 ; inline
 | 
			
		||||
: SOCK_RAW       3 ; inline
 | 
			
		||||
: SOCK_RDM       4 ; inline
 | 
			
		||||
: SOCK_SEQPACKET 5 ; inline
 | 
			
		||||
CONSTANT: SOCK_STREAM    1
 | 
			
		||||
CONSTANT: SOCK_DGRAM     2
 | 
			
		||||
CONSTANT: SOCK_RAW       3
 | 
			
		||||
CONSTANT: SOCK_RDM       4
 | 
			
		||||
CONSTANT: SOCK_SEQPACKET 5
 | 
			
		||||
 | 
			
		||||
: SO_DEBUG       HEX:   1 ; inline
 | 
			
		||||
: SO_ACCEPTCONN  HEX:   2 ; inline
 | 
			
		||||
: SO_REUSEADDR   HEX:   4 ; inline
 | 
			
		||||
: SO_KEEPALIVE   HEX:   8 ; inline
 | 
			
		||||
: SO_DONTROUTE   HEX:  10 ; inline
 | 
			
		||||
: SO_BROADCAST   HEX:  20 ; inline
 | 
			
		||||
: SO_USELOOPBACK HEX:  40 ; inline
 | 
			
		||||
: SO_LINGER      HEX:  80 ; inline
 | 
			
		||||
: SO_OOBINLINE   HEX: 100 ; inline
 | 
			
		||||
CONSTANT: SO_DEBUG       HEX:   1
 | 
			
		||||
CONSTANT: SO_ACCEPTCONN  HEX:   2
 | 
			
		||||
CONSTANT: SO_REUSEADDR   HEX:   4
 | 
			
		||||
CONSTANT: SO_KEEPALIVE   HEX:   8
 | 
			
		||||
CONSTANT: SO_DONTROUTE   HEX:  10
 | 
			
		||||
CONSTANT: SO_BROADCAST   HEX:  20
 | 
			
		||||
CONSTANT: SO_USELOOPBACK HEX:  40
 | 
			
		||||
CONSTANT: SO_LINGER      HEX:  80
 | 
			
		||||
CONSTANT: SO_OOBINLINE   HEX: 100
 | 
			
		||||
: SO_DONTLINGER ( -- n ) SO_LINGER bitnot ; inline
 | 
			
		||||
 | 
			
		||||
: SO_SNDBUF     HEX: 1001 ; inline
 | 
			
		||||
: SO_RCVBUF     HEX: 1002 ; inline
 | 
			
		||||
: SO_SNDLOWAT   HEX: 1003 ; inline
 | 
			
		||||
: SO_RCVLOWAT   HEX: 1004 ; inline
 | 
			
		||||
: SO_SNDTIMEO   HEX: 1005 ; inline
 | 
			
		||||
: SO_RCVTIMEO   HEX: 1006 ; inline
 | 
			
		||||
: SO_ERROR      HEX: 1007 ; inline
 | 
			
		||||
: SO_TYPE       HEX: 1008 ; inline
 | 
			
		||||
CONSTANT: SO_SNDBUF     HEX: 1001
 | 
			
		||||
CONSTANT: SO_RCVBUF     HEX: 1002
 | 
			
		||||
CONSTANT: SO_SNDLOWAT   HEX: 1003
 | 
			
		||||
CONSTANT: SO_RCVLOWAT   HEX: 1004
 | 
			
		||||
CONSTANT: SO_SNDTIMEO   HEX: 1005
 | 
			
		||||
CONSTANT: SO_RCVTIMEO   HEX: 1006
 | 
			
		||||
CONSTANT: SO_ERROR      HEX: 1007
 | 
			
		||||
CONSTANT: SO_TYPE       HEX: 1008
 | 
			
		||||
 | 
			
		||||
: TCP_NODELAY   HEX:    1 ; inline
 | 
			
		||||
CONSTANT: TCP_NODELAY   HEX:    1
 | 
			
		||||
 | 
			
		||||
: AF_UNSPEC      0 ; inline
 | 
			
		||||
: AF_UNIX        1 ; inline
 | 
			
		||||
: AF_INET        2 ; inline
 | 
			
		||||
: AF_IMPLINK     3 ; inline
 | 
			
		||||
: AF_PUP         4 ; inline
 | 
			
		||||
: AF_CHAOS       5 ; inline
 | 
			
		||||
: AF_NS          6 ; inline
 | 
			
		||||
: AF_ISO         7 ; inline
 | 
			
		||||
CONSTANT: AF_UNSPEC      0
 | 
			
		||||
CONSTANT: AF_UNIX        1
 | 
			
		||||
CONSTANT: AF_INET        2
 | 
			
		||||
CONSTANT: AF_IMPLINK     3
 | 
			
		||||
CONSTANT: AF_PUP         4
 | 
			
		||||
CONSTANT: AF_CHAOS       5
 | 
			
		||||
CONSTANT: AF_NS          6
 | 
			
		||||
CONSTANT: AF_ISO         7
 | 
			
		||||
ALIAS: AF_OSI    AF_ISO
 | 
			
		||||
: AF_ECMA        8 ; inline
 | 
			
		||||
: AF_DATAKIT     9 ; inline
 | 
			
		||||
: AF_CCITT      10 ; inline
 | 
			
		||||
: AF_SNA        11 ; inline
 | 
			
		||||
: AF_DECnet     12 ; inline
 | 
			
		||||
: AF_DLI        13 ; inline
 | 
			
		||||
: AF_LAT        14 ; inline
 | 
			
		||||
: AF_HYLINK     15 ; inline
 | 
			
		||||
: AF_APPLETALK  16 ; inline
 | 
			
		||||
: AF_NETBIOS    17 ; inline
 | 
			
		||||
: AF_MAX        18 ; inline
 | 
			
		||||
: AF_INET6      23 ; inline
 | 
			
		||||
: AF_IRDA       26 ; inline
 | 
			
		||||
: AF_BTM        32 ; inline
 | 
			
		||||
CONSTANT: AF_ECMA        8
 | 
			
		||||
CONSTANT: AF_DATAKIT     9
 | 
			
		||||
CONSTANT: AF_CCITT      10
 | 
			
		||||
CONSTANT: AF_SNA        11
 | 
			
		||||
CONSTANT: AF_DECnet     12
 | 
			
		||||
CONSTANT: AF_DLI        13
 | 
			
		||||
CONSTANT: AF_LAT        14
 | 
			
		||||
CONSTANT: AF_HYLINK     15
 | 
			
		||||
CONSTANT: AF_APPLETALK  16
 | 
			
		||||
CONSTANT: AF_NETBIOS    17
 | 
			
		||||
CONSTANT: AF_MAX        18
 | 
			
		||||
CONSTANT: AF_INET6      23
 | 
			
		||||
CONSTANT: AF_IRDA       26
 | 
			
		||||
CONSTANT: AF_BTM        32
 | 
			
		||||
 | 
			
		||||
: PF_UNSPEC      0 ; inline
 | 
			
		||||
: PF_LOCAL       1 ; inline
 | 
			
		||||
: PF_INET        2 ; inline
 | 
			
		||||
: PF_INET6      23 ; inline
 | 
			
		||||
CONSTANT: PF_UNSPEC      0
 | 
			
		||||
CONSTANT: PF_LOCAL       1
 | 
			
		||||
CONSTANT: PF_INET        2
 | 
			
		||||
CONSTANT: PF_INET6      23
 | 
			
		||||
 | 
			
		||||
: AI_PASSIVE     1 ; inline
 | 
			
		||||
: AI_CANONNAME   2 ; inline
 | 
			
		||||
: AI_NUMERICHOST 4 ; inline
 | 
			
		||||
CONSTANT: AI_PASSIVE     1
 | 
			
		||||
CONSTANT: AI_CANONNAME   2
 | 
			
		||||
CONSTANT: AI_NUMERICHOST 4
 | 
			
		||||
: AI_MASK ( -- n ) { AI_PASSIVE AI_CANONNAME AI_NUMERICHOST } flags ;
 | 
			
		||||
 | 
			
		||||
: NI_NUMERICHOST 1 ;
 | 
			
		||||
: NI_NUMERICSERV 2 ;
 | 
			
		||||
CONSTANT: NI_NUMERICHOST 1
 | 
			
		||||
CONSTANT: NI_NUMERICSERV 2
 | 
			
		||||
 | 
			
		||||
: IPPROTO_TCP    6 ; inline
 | 
			
		||||
: IPPROTO_UDP   17 ; inline
 | 
			
		||||
: IPPROTO_RM   113 ; inline
 | 
			
		||||
CONSTANT: IPPROTO_TCP    6
 | 
			
		||||
CONSTANT: IPPROTO_UDP   17
 | 
			
		||||
CONSTANT: IPPROTO_RM   113
 | 
			
		||||
 | 
			
		||||
CONSTANT: WSA_FLAG_OVERLAPPED 1
 | 
			
		||||
ALIAS: WSA_WAIT_EVENT_0 WAIT_OBJECT_0
 | 
			
		||||
| 
						 | 
				
			
			@ -94,16 +94,16 @@ ALIAS: WSA_WAIT_TIMEOUT WAIT_TIMEOUT
 | 
			
		|||
ALIAS: WSA_INFINITE INFINITE
 | 
			
		||||
ALIAS: WSA_IO_PENDING ERROR_IO_PENDING
 | 
			
		||||
 | 
			
		||||
: INADDR_ANY 0 ; inline
 | 
			
		||||
CONSTANT: INADDR_ANY 0
 | 
			
		||||
 | 
			
		||||
: INVALID_SOCKET ( -- alien ) -1 <alien> ; inline
 | 
			
		||||
: SOCKET_ERROR -1 ; inline
 | 
			
		||||
CONSTANT: SOCKET_ERROR -1
 | 
			
		||||
 | 
			
		||||
: SD_RECV 0 ; inline
 | 
			
		||||
: SD_SEND 1 ; inline
 | 
			
		||||
: SD_BOTH 2 ; inline
 | 
			
		||||
CONSTANT: SD_RECV 0
 | 
			
		||||
CONSTANT: SD_SEND 1
 | 
			
		||||
CONSTANT: SD_BOTH 2
 | 
			
		||||
 | 
			
		||||
: SOL_SOCKET HEX: ffff ; inline
 | 
			
		||||
CONSTANT: SOL_SOCKET HEX: ffff
 | 
			
		||||
 | 
			
		||||
! TYPEDEF: uint in_addr_t
 | 
			
		||||
! C-STRUCT: in_addr
 | 
			
		||||
| 
						 | 
				
			
			@ -207,7 +207,7 @@ C-STRUCT: QOS
 | 
			
		|||
    { "WSABUF" "ProviderSpecific" } ;
 | 
			
		||||
TYPEDEF: QOS* LPQOS
 | 
			
		||||
 | 
			
		||||
: MAX_PROTOCOL_CHAIN 7 ; inline
 | 
			
		||||
CONSTANT: MAX_PROTOCOL_CHAIN 7
 | 
			
		||||
 | 
			
		||||
C-STRUCT: WSAPROTOCOLCHAIN
 | 
			
		||||
    { "int" "ChainLen" }
 | 
			
		||||
| 
						 | 
				
			
			@ -215,7 +215,7 @@ C-STRUCT: WSAPROTOCOLCHAIN
 | 
			
		|||
    { { "DWORD" 7 } "ChainEntries" } ;
 | 
			
		||||
TYPEDEF: WSAPROTOCOLCHAIN* LPWSAPROTOCOLCHAIN
 | 
			
		||||
 | 
			
		||||
: WSAPROTOCOL_LEN 255 ; inline
 | 
			
		||||
CONSTANT: WSAPROTOCOL_LEN 255
 | 
			
		||||
 | 
			
		||||
C-STRUCT: WSAPROTOCOL_INFOW
 | 
			
		||||
    { "DWORD" "dwServiceFlags1" }
 | 
			
		||||
| 
						 | 
				
			
			@ -387,7 +387,7 @@ LIBRARY: mswsock
 | 
			
		|||
FUNCTION: int AcceptEx ( void* listen, void* accept, void* out-buf, int recv-len, int addr-len, int remote-len, void* out-len, void* overlapped ) ;
 | 
			
		||||
FUNCTION: void GetAcceptExSockaddrs ( void* a, int b, int c, int d, void* e, void* f, void* g, void* h ) ;
 | 
			
		||||
 | 
			
		||||
: SIO_GET_EXTENSION_FUNCTION_POINTER -939524090 ; inline
 | 
			
		||||
CONSTANT: SIO_GET_EXTENSION_FUNCTION_POINTER -939524090
 | 
			
		||||
 | 
			
		||||
: WSAID_CONNECTEX ( -- GUID )
 | 
			
		||||
    "GUID" <c-object>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,7 @@ ARTICLE: "symbols" "Symbols"
 | 
			
		|||
"Symbols are just compound definitions in disguise. The following two lines are equivalent:"
 | 
			
		||||
{ $code
 | 
			
		||||
    "SYMBOL: foo"
 | 
			
		||||
    ": foo \\ foo ;"
 | 
			
		||||
    ": foo ( -- value ) \\ foo ;"
 | 
			
		||||
} ;
 | 
			
		||||
 | 
			
		||||
ARTICLE: "primitives" "Primitives"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -112,7 +112,7 @@ M: source-file fuel-pprint path>> fuel-pprint ;
 | 
			
		|||
    error get
 | 
			
		||||
    fuel-eval-result get-global
 | 
			
		||||
    fuel-eval-output get-global
 | 
			
		||||
    3array fuel-pprint ;
 | 
			
		||||
    3array fuel-pprint flush nl "EOT:" write ;
 | 
			
		||||
 | 
			
		||||
: fuel-forget-error ( -- ) f error set-global ; inline
 | 
			
		||||
: fuel-forget-result ( -- ) f fuel-eval-result set-global ; inline
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 6.6 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 7.5 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 6.3 KiB  | 
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
Slava Pestov
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 4.7 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 4.6 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 4.3 KiB  | 
| 
						 | 
				
			
			@ -0,0 +1,368 @@
 | 
			
		|||
! Copyright (C) 2008 Slava Pestov.
 | 
			
		||||
! See http://factorcode.org/license.txt for BSD license.
 | 
			
		||||
USING: slides help.markup math arrays hashtables namespaces
 | 
			
		||||
sequences kernel sequences parser memoize io.encodings.binary
 | 
			
		||||
locals kernel.private tools.vocabs.browser assocs quotations
 | 
			
		||||
 tools.vocabs tools.annotations tools.crossref
 | 
			
		||||
help.topics math.functions compiler.tree.optimizer
 | 
			
		||||
compiler.cfg.optimizer fry graphics.bitmap graphics.viewer
 | 
			
		||||
ui.gadgets.panes tetris tetris.game combinators generalizations
 | 
			
		||||
multiline sequences.private ;
 | 
			
		||||
IN: otug-talk
 | 
			
		||||
 | 
			
		||||
USING: cairo cairo.samples cairo.ffi cairo.gadgets accessors
 | 
			
		||||
io.backend ui.gadgets ;
 | 
			
		||||
 | 
			
		||||
TUPLE: png-gadget < cairo-gadget surface ;
 | 
			
		||||
 | 
			
		||||
: <png-gadget> ( file -- gadget )
 | 
			
		||||
    png-gadget new-gadget
 | 
			
		||||
    swap normalize-path
 | 
			
		||||
    cairo_image_surface_create_from_png >>surface ; inline
 | 
			
		||||
 | 
			
		||||
M: png-gadget pref-dim* ( gadget -- )
 | 
			
		||||
    surface>>
 | 
			
		||||
    [ cairo_image_surface_get_width ]
 | 
			
		||||
    [ cairo_image_surface_get_height ]
 | 
			
		||||
    bi 2array ;
 | 
			
		||||
 | 
			
		||||
M: png-gadget render-cairo* ( gadget -- )
 | 
			
		||||
    cr swap surface>> 0 0 cairo_set_source_surface
 | 
			
		||||
    cr cairo_paint ;
 | 
			
		||||
 | 
			
		||||
M: png-gadget ungraft* ( gadget -- )
 | 
			
		||||
    surface>> cairo_surface_destroy ;
 | 
			
		||||
 | 
			
		||||
: $bitmap ( element -- )
 | 
			
		||||
    [ first <png-gadget> gadget. ] ($block) ;
 | 
			
		||||
 | 
			
		||||
: $tetris ( element -- )
 | 
			
		||||
    drop [ <default-tetris> <tetris-gadget> gadget. ] ($block) ;
 | 
			
		||||
 | 
			
		||||
: otug-slides
 | 
			
		||||
{
 | 
			
		||||
    { $slide "Factor!"
 | 
			
		||||
        { $url "http://factorcode.org" }
 | 
			
		||||
        "Development started in 2003"
 | 
			
		||||
        "Open source (BSD license)"
 | 
			
		||||
        "Influenced by Forth, Lisp, and Smalltalk"
 | 
			
		||||
        "Blurs the line between language and library"
 | 
			
		||||
        "Interactive development"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Part 1: the language" }
 | 
			
		||||
    { $slide "Basics"
 | 
			
		||||
        "Stack based, dynamically typed"
 | 
			
		||||
        { "A " { $emphasis "word" } " is a named piece of code" }
 | 
			
		||||
        { "Values are passed between words on a " { $emphasis "stack" } }
 | 
			
		||||
        "Code evaluates left to right"
 | 
			
		||||
        "Example:"
 | 
			
		||||
        { $code "2 3 + ." }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Quotations"
 | 
			
		||||
        { "A " { $emphasis "quotation" } " is a block of code pushed on the stack" }
 | 
			
		||||
        { "Syntax: " { $snippet "[ ... ]" } }
 | 
			
		||||
        "Example:"
 | 
			
		||||
        { $code
 | 
			
		||||
            "\"/etc/passwd\" ascii file-lines"
 | 
			
		||||
            "[ \"#\" head? not ] filter"
 | 
			
		||||
            "[ \":\" split first ] map"
 | 
			
		||||
            "."
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Words"
 | 
			
		||||
        { "We can define new words with " { $snippet ": name ... ;" } " syntax" }
 | 
			
		||||
        { $code ": remove-comments ( lines -- lines' )" "    [ \"#\" head? not ] filter ;" }
 | 
			
		||||
        { "Words are grouped into " { $emphasis "vocabularies" } }
 | 
			
		||||
        { $link "vocab-index" }
 | 
			
		||||
        "Libraries and applications are vocabularies"
 | 
			
		||||
        { $vocab-link "spheres" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Constructing quotations"
 | 
			
		||||
        { "Suppose we want a " { $snippet "remove-comments*" } " word" }
 | 
			
		||||
        { $code ": remove-comments* ( lines string -- lines' )" "    [ ??? head? not ] filter ;" }
 | 
			
		||||
        { "We use " { $link POSTPONE: '[ } " instead of " { $link POSTPONE: [ } }
 | 
			
		||||
        { "Create “holes” with " { $link _ } }
 | 
			
		||||
        "Holes filled in left to right when quotation pushed on the stack"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Constructing quotations"
 | 
			
		||||
        { $code ": remove-comments* ( lines string -- lines' )" "    '[ _ head? not ] filter ;" "" ": remove-comments ( lines -- lines' )" "    \"#\" remove-comments* ;" }
 | 
			
		||||
        { { $link @ } " inserts a quotation" }
 | 
			
		||||
        { $code ": replicate ( n quot -- seq )" "    '[ drop @ ] map ;" }
 | 
			
		||||
        { $code "10 [ 1 10 [a,b] random ] replicate ." }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Combinators"
 | 
			
		||||
        { "A " { $emphasis "combinator" } " is a word taking quotations as input" }
 | 
			
		||||
        { "Used for control flow, data flow, iteration" }
 | 
			
		||||
        { $code "100 [ 5 mod 3 = [ \"Fizz!\" print ] when ] each" }
 | 
			
		||||
        { "Control flow: " { $link if } ", " { $link when } ", " { $link unless } ", " { $link cond } }
 | 
			
		||||
        { "Iteration: " { $link map } ", " { $link filter } ", " { $link all? } ", ..." }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Data flow combinators - simple example"
 | 
			
		||||
        "All examples so far used “pipeline style”"
 | 
			
		||||
        "What about using a value more than once, or operating on values not at top of stack?"
 | 
			
		||||
        { $code "{ 10 70 54 } [ sum ] [ length ] bi / ." }
 | 
			
		||||
        { $code "5 [ 1 + ] [ sqrt ] [ 1 - ] tri 3array ." }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Data flow combinators - cleave family"
 | 
			
		||||
        { { $link bi } ", " { $link tri } ", " { $link cleave } }
 | 
			
		||||
        { $bitmap "resource:extra/otug-talk/bi.png" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Data flow combinators - cleave family"
 | 
			
		||||
        { { $link 2bi } ", " { $link 2tri } ", " { $link 2cleave } }
 | 
			
		||||
        { $bitmap "resource:extra/otug-talk/2bi.png" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Data flow combinators"
 | 
			
		||||
        "First, let's define a data type:"
 | 
			
		||||
        { $code "TUPLE: person first-name last-name ;" }
 | 
			
		||||
        "Make an instance:"
 | 
			
		||||
        { $code "person new" "    \"Joe\" >>first-name" "    \"Sixpack\" >>last-name" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Data flow combinators"
 | 
			
		||||
        "Let's do stuff with it:"
 | 
			
		||||
        { $code
 | 
			
		||||
            "[ first-name>> ] [ last-name>> ] bi"
 | 
			
		||||
            "[ 2 head ] [ 5 head ] bi*"
 | 
			
		||||
            "[ >upper ] bi@"
 | 
			
		||||
            "\".\" glue ."
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Data flow combinators - spread family"
 | 
			
		||||
        { { $link bi* } ", " { $link tri* } ", " { $link spread } }
 | 
			
		||||
        { $bitmap "resource:extra/otug-talk/bi_star.png" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Data flow combinators - spread family"
 | 
			
		||||
        { { $link 2bi* } }
 | 
			
		||||
        { $bitmap "resource:extra/otug-talk/2bi_star.png" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Data flow combinators - apply family"
 | 
			
		||||
        { { $link bi@ } ", " { $link tri@ } ", " { $link napply } }
 | 
			
		||||
        { $bitmap "resource:extra/otug-talk/bi_at.png" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Data flow combinators - apply family"
 | 
			
		||||
        { { $link 2bi@ } }
 | 
			
		||||
        { $bitmap "resource:extra/otug-talk/2bi_at.png" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Shuffle words"
 | 
			
		||||
        "When data flow combinators are not enough"
 | 
			
		||||
        { $link "shuffle-words" }
 | 
			
		||||
        "Lower-level, Forth/PostScript-style stack manipulation"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Locals"
 | 
			
		||||
        "When data flow combinators and shuffle words are not enough"
 | 
			
		||||
        "Name your input parameters"
 | 
			
		||||
        "Used in about 1% of all words"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Locals example"
 | 
			
		||||
        "Area of a triangle using Heron's formula"
 | 
			
		||||
        { $code
 | 
			
		||||
            <" :: area ( a b c -- x )
 | 
			
		||||
    a b c + + 2 / :> p
 | 
			
		||||
    p
 | 
			
		||||
    p a - *
 | 
			
		||||
    p b - *
 | 
			
		||||
    p c - * sqrt ;">
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Previous example without locals"
 | 
			
		||||
        "A bit unwieldy..."
 | 
			
		||||
        { $code
 | 
			
		||||
            <" : area ( a b c -- x )
 | 
			
		||||
    [ ] [ + + 2 / ] 3bi
 | 
			
		||||
    [ '[ _ - ] tri@ ] [ neg ] bi
 | 
			
		||||
    * * * sqrt ;"> }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "More idiomatic version"
 | 
			
		||||
        "But there's a trick: put the points in an array"
 | 
			
		||||
        { $code <" : v-n ( v n -- w ) '[ _ - ] map ;
 | 
			
		||||
 | 
			
		||||
: area ( points -- x )
 | 
			
		||||
    [ 0 suffix ] [ sum 2 / ] bi
 | 
			
		||||
    v-n product sqrt ;"> }
 | 
			
		||||
    }
 | 
			
		||||
    ! { $slide "The parser"
 | 
			
		||||
    !     "All data types have a literal syntax"
 | 
			
		||||
    !     "Literal hashtables and arrays are very useful in data-driven code"
 | 
			
		||||
    !     { $code "H{ { \"cookies\" 12 } { \"milk\" 10 } }" }
 | 
			
		||||
    !     "Libraries can define new parsing words"
 | 
			
		||||
    ! }
 | 
			
		||||
    { $slide "Programming without named values"
 | 
			
		||||
        "Minimal glue between words"
 | 
			
		||||
        "Easy multiple return values"
 | 
			
		||||
        { "Avoid useless variable names: " { $snippet "x" } ", " { $snippet "n" } ", " { $snippet "a" } ", ..." }
 | 
			
		||||
        { { $link at } " and " { $link at* } }
 | 
			
		||||
        { $code "at* [ ... ] [ ... ] if" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Stack language idioms"
 | 
			
		||||
        "Enables new idioms not possible before"
 | 
			
		||||
        "We get the effect of “keyword parameters” for free"
 | 
			
		||||
        { $vocab-link "smtp-example" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "“Perfect” factoring"
 | 
			
		||||
        { $table
 | 
			
		||||
            { { $link head } { $link head-slice } }
 | 
			
		||||
            { { $link tail } { $link tail-slice } }
 | 
			
		||||
        }
 | 
			
		||||
        { "Modifier: " { $link from-end } }
 | 
			
		||||
        { "Modifier: " { $link short } }
 | 
			
		||||
        "4*2*2=16 operations, 6 words!"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Modifiers"
 | 
			
		||||
        "“Modifiers” can express MN combinations using M+N words"
 | 
			
		||||
        { $code
 | 
			
		||||
            "\"Hello, Joe\" 4 head ."
 | 
			
		||||
            "\"Hello, Joe\" 3 tail ."
 | 
			
		||||
            "\"Hello, Joe\" 3 from-end tail ."
 | 
			
		||||
        }
 | 
			
		||||
        { $code
 | 
			
		||||
            "\"Hello world\" 5 short head ."
 | 
			
		||||
            "\"Hi\" 5 short tail ."
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Modifiers"
 | 
			
		||||
        { "C-style " { $snippet "while" } " and " { $snippet "do while" } " loops" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Modifiers"
 | 
			
		||||
        { $code ": bank ( n -- n )" "    readln string>number +" "    dup \"Balance: $\" write . ;" }
 | 
			
		||||
        { $code "0 [ dup 0 > ] [ bank ] [ ] while" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Modifiers"
 | 
			
		||||
        { $code "0 [ dup 0 > ] [ bank ] [ ] do while" }
 | 
			
		||||
        { { $link do } " executes one iteration of a " { $link while } " loop" }
 | 
			
		||||
        { { $link while } " calls " { $link do } }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "More “pipeline style” code"
 | 
			
		||||
        { "Suppose we want to get the price of the customer's first order, but any one of the steps along the way could be a nil value (" { $link f } " in Factor):" }
 | 
			
		||||
        { $code
 | 
			
		||||
            "dup [ orders>> ] when"
 | 
			
		||||
            "dup [ first ] when"
 | 
			
		||||
            "dup [ price>> ] when"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "This is hard with mainstream syntax!"
 | 
			
		||||
        { $code
 | 
			
		||||
            <" var customer = ...;
 | 
			
		||||
var orders = (customer == null ? null : customer.orders);
 | 
			
		||||
var order = (orders == null ? null : orders[0]);
 | 
			
		||||
var price = (order == null ? null : order.price);"> }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "An ad-hoc solution"
 | 
			
		||||
        "Something like..."
 | 
			
		||||
        { $code "var price = customer.?orders.?[0].?price;" }
 | 
			
		||||
    }
 | 
			
		||||
    ! { $slide "Stack languages are fundamental"
 | 
			
		||||
    !     "Very simple semantics"
 | 
			
		||||
    !     "Easy to generate stack code programatically"
 | 
			
		||||
    !     "Everything is almost entirely library code in Factor"
 | 
			
		||||
    !     "Factor is easy to extend"
 | 
			
		||||
    ! }
 | 
			
		||||
    { $slide "Part 2: the implementation" }
 | 
			
		||||
    { $slide "Interactive development"
 | 
			
		||||
        { $tetris }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Application deployment"
 | 
			
		||||
        { $vocab-link "webkit-demo" }
 | 
			
		||||
        "Demonstrates Cocoa binding"
 | 
			
		||||
        "Let's deploy a stand-alone binary with the deploy tool"
 | 
			
		||||
        "Deploy tool generates binaries with no external dependencies"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "The UI"
 | 
			
		||||
        "Renders with OpenGL"
 | 
			
		||||
        "Backends for Cocoa, Windows, X11: managing windows, input events, clipboard"
 | 
			
		||||
        "Cross-platform API"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "UI example"
 | 
			
		||||
        { $code
 | 
			
		||||
    <" <pile>
 | 
			
		||||
    { 5 5 } >>gap
 | 
			
		||||
    1 >>fill
 | 
			
		||||
    "Hello world!" <label> add-gadget
 | 
			
		||||
    "Click me!" [ drop beep ]
 | 
			
		||||
    <bevel-button> add-gadget
 | 
			
		||||
    <editor> <scroller> add-gadget
 | 
			
		||||
"UI test" open-window "> }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Help system"
 | 
			
		||||
        "Help markup is just literal data"
 | 
			
		||||
        { "Look at the help for " { $link T{ link f + } } }
 | 
			
		||||
        "These slides are built with the help system and a custom style sheet"
 | 
			
		||||
        { $vocab-link "otug-talk" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "The VM"
 | 
			
		||||
        "Lowest level is the VM: ~12,000 lines of C"
 | 
			
		||||
        "Generational garbage collection"
 | 
			
		||||
        "Non-optimizing compiler"
 | 
			
		||||
        "Loads an image file and runs it"
 | 
			
		||||
        "Initial image generated from another Factor instance:"
 | 
			
		||||
        { $code "\"x86.32\" make-image" }
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "The core library"
 | 
			
		||||
        "Core library, ~9,000 lines of Factor"
 | 
			
		||||
        "Source parser, arrays, strings, math, hashtables, basic I/O, ..."
 | 
			
		||||
        "Packaged into boot image because VM doesn't have a parser"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "The basis library"
 | 
			
		||||
        "Basis library, ~80,000 lines of Factor"
 | 
			
		||||
        "Bootstrap process loads code from basis, runs compiler, saves image"
 | 
			
		||||
        "Loaded by default: optimizing compiler, tools, help system, UI, ..."
 | 
			
		||||
        "Optional: HTTP server, XML, database access, ..."
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Non-optimizing compiler"
 | 
			
		||||
        "Glues together chunks of machine code"
 | 
			
		||||
        "Most words compiled as calls, some inlined"
 | 
			
		||||
        "Used for listener interactions, and bootstrap"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Optimizing compiler"
 | 
			
		||||
        "Converts Factor code into high-level SSA form"
 | 
			
		||||
        "Performs global optimizations"
 | 
			
		||||
        "Converts high-level SSA into low-level SSA"
 | 
			
		||||
        "Performs local optimizations"
 | 
			
		||||
        "Register allocation"
 | 
			
		||||
        "Machine code generation: x86, x86-64, PowerPC"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Optimizing compiler"
 | 
			
		||||
        "Makes high-level language features cheap to use"
 | 
			
		||||
        "Eliminate redundant method dispatch by inferring types"
 | 
			
		||||
        "Eliminate redundant integer overflow checks by inferring ranges"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Optimizing compiler"
 | 
			
		||||
        "Eliminate redundant memory allocation (escape analysis)"
 | 
			
		||||
        "Eliminate redundant loads/stores (alias analysis)"
 | 
			
		||||
        "Eliminate redundant computations (value numbering)"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Project infrastructure"
 | 
			
		||||
        { $url "http://factorcode.org" }
 | 
			
		||||
        { $url "http://concatenative.org" }
 | 
			
		||||
        { $url "http://docs.factorcode.org" }
 | 
			
		||||
        { $url "http://planet.factorcode.org" }
 | 
			
		||||
        "Uses our HTTP server, SSL, DB, Atom libraries..."
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Project infrastructure"
 | 
			
		||||
        "Build farm, written in Factor"
 | 
			
		||||
        "12 platforms"
 | 
			
		||||
        "Builds Factor and all libraries, runs tests, makes binaries"
 | 
			
		||||
        "Good for increasing stability"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Community"
 | 
			
		||||
        "#concatenative irc.freenode.net: 60-70 users"
 | 
			
		||||
        "factor-talk@lists.sf.net: 189 subscribers"
 | 
			
		||||
        "About 30 people have code in the Factor repository"
 | 
			
		||||
        "Easy to get started: binaries, lots of docs, friendly community..."
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "Selling points"
 | 
			
		||||
        "Expressive language"
 | 
			
		||||
        "Comprehensive library"
 | 
			
		||||
        "Efficient implementation"
 | 
			
		||||
        "Powerful interactive tools"
 | 
			
		||||
        "Stand-alone application deployment"
 | 
			
		||||
        "Moving fast"
 | 
			
		||||
    }
 | 
			
		||||
    { $slide "That's all, folks"
 | 
			
		||||
        "It is hard to cover everything in a single talk"
 | 
			
		||||
        "Factor has many cool things that I didn't talk about"
 | 
			
		||||
        "Questions?"
 | 
			
		||||
    }
 | 
			
		||||
} ;
 | 
			
		||||
 | 
			
		||||
: otug-talk ( -- ) otug-slides slides-window ;
 | 
			
		||||
 | 
			
		||||
MAIN: otug-talk
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
Slides from a talk at OTUG by Slava Pestov, December 2008
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
demos
 | 
			
		||||
| 
						 | 
				
			
			@ -47,8 +47,8 @@ M-x customize-group fuel will show you how many.
 | 
			
		|||
Quick key reference
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
(Chords ending in a single letter <x> accept also C-<x> (e.g. C-cC-z is
 | 
			
		||||
the same as C-cz)).
 | 
			
		||||
(Triple chords ending in a single letter <x> accept also C-<x> (e.g.
 | 
			
		||||
C-cC-eC-r is the same as C-cC-er)).
 | 
			
		||||
 | 
			
		||||
* In factor source files:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +57,8 @@ the same as C-cz)).
 | 
			
		|||
 | 
			
		||||
 - M-. : edit word at point in Emacs
 | 
			
		||||
 - M-TAB : complete word at point
 | 
			
		||||
 - C-cC-ev : edit vocabulary
 | 
			
		||||
 - C-cC-ev : edit vocabulary (M-x fuel-edit-vocabulary)
 | 
			
		||||
 - C-cC-ew : edit word (M-x fuel-edit-word)
 | 
			
		||||
 | 
			
		||||
 - C-cr, C-cC-er : eval region
 | 
			
		||||
 - C-M-r, C-cC-ee : eval region, extending it to definition boundaries
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -143,6 +143,15 @@ terminates a current completion."
 | 
			
		|||
         (vs (and cv `("syntax" ,cv ,@(fuel-syntax--usings)))))
 | 
			
		||||
    (fuel-completion--words prefix vs)))
 | 
			
		||||
 | 
			
		||||
(defsubst fuel-completion--all-words-list (prefix)
 | 
			
		||||
  (fuel-completion--words prefix nil))
 | 
			
		||||
 | 
			
		||||
(defvar fuel-completion--word-list-func
 | 
			
		||||
  (completion-table-dynamic 'fuel-completion--word-list))
 | 
			
		||||
 | 
			
		||||
(defvar fuel-completion--all-words-list-func
 | 
			
		||||
  (completion-table-dynamic 'fuel-completion--all-words-list))
 | 
			
		||||
 | 
			
		||||
(defun fuel-completion--complete (prefix)
 | 
			
		||||
  (let* ((words (fuel-completion--word-list prefix))
 | 
			
		||||
         (completions (all-completions prefix words))
 | 
			
		||||
| 
						 | 
				
			
			@ -150,6 +159,14 @@ terminates a current completion."
 | 
			
		|||
         (partial (if (eq partial t) prefix partial)))
 | 
			
		||||
    (cons completions partial)))
 | 
			
		||||
 | 
			
		||||
(defsubst fuel-completion--read-word (prompt &optional default history all)
 | 
			
		||||
  (completing-read prompt
 | 
			
		||||
                   (if all fuel-completion--all-words-list-func
 | 
			
		||||
                     fuel-completion--word-list-func)
 | 
			
		||||
                   nil nil nil
 | 
			
		||||
                   history
 | 
			
		||||
                   (or default (fuel-syntax-symbol-at-point))))
 | 
			
		||||
 | 
			
		||||
(defun fuel-completion--complete-symbol ()
 | 
			
		||||
  "Complete the symbol at point.
 | 
			
		||||
Perform completion similar to Emacs' complete-symbol."
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,8 +14,11 @@
 | 
			
		|||
 | 
			
		||||
;;; Code:
 | 
			
		||||
 | 
			
		||||
(require 'fuel-base)
 | 
			
		||||
(require 'fuel-log)
 | 
			
		||||
(require 'fuel-base)
 | 
			
		||||
 | 
			
		||||
(require 'comint)
 | 
			
		||||
(require 'advice)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
;;; Default connection:
 | 
			
		||||
| 
						 | 
				
			
			@ -123,19 +126,34 @@
 | 
			
		|||
 | 
			
		||||
;;; Connection setup:
 | 
			
		||||
 | 
			
		||||
(defun fuel-con--cleanup-connection (c)
 | 
			
		||||
  (fuel-con--connection-cancel-timer c))
 | 
			
		||||
 | 
			
		||||
(defun fuel-con--setup-connection (buffer)
 | 
			
		||||
  (set-buffer buffer)
 | 
			
		||||
  (fuel-con--cleanup-connection fuel-con--connection)
 | 
			
		||||
  (let ((conn (fuel-con--make-connection buffer)))
 | 
			
		||||
    (fuel-con--setup-comint)
 | 
			
		||||
    (prog1
 | 
			
		||||
        (setq fuel-con--connection conn)
 | 
			
		||||
      (fuel-con--connection-start-timer conn))))
 | 
			
		||||
 | 
			
		||||
(defconst fuel-con--prompt-regex "( .+ ) ")
 | 
			
		||||
(defconst fuel-con--eot-marker "EOT:")
 | 
			
		||||
(defconst fuel-con--init-stanza (format "USE: fuel %S write" fuel-con--eot-marker))
 | 
			
		||||
 | 
			
		||||
(defconst fuel-con--comint-finished-regex
 | 
			
		||||
  (format "%s%s" fuel-con--eot-marker fuel-con--prompt-regex))
 | 
			
		||||
 | 
			
		||||
(defun fuel-con--setup-comint ()
 | 
			
		||||
  (comint-redirect-cleanup)
 | 
			
		||||
  (add-hook 'comint-redirect-filter-functions
 | 
			
		||||
            'fuel-con--comint-redirect-filter t t)
 | 
			
		||||
  (add-hook 'comint-redirect-hook
 | 
			
		||||
            'fuel-con--comint-redirect-hook))
 | 
			
		||||
            'fuel-con--comint-redirect-hook nil t))
 | 
			
		||||
 | 
			
		||||
(defadvice comint-redirect-setup (after fuel-con--advice activate)
 | 
			
		||||
  (setq comint-redirect-finished-regexp fuel-con--comint-finished-regex))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
;;; Requests handling:
 | 
			
		||||
| 
						 | 
				
			
			@ -169,6 +187,8 @@
 | 
			
		|||
        (error (fuel-log--error "<%s>: continuation failed %S \n\t%s"
 | 
			
		||||
                                id rstr cerr))))))
 | 
			
		||||
 | 
			
		||||
(defvar fuel-con--debug-comint-p nil)
 | 
			
		||||
 | 
			
		||||
(defun fuel-con--comint-redirect-filter (str)
 | 
			
		||||
  (if (not fuel-con--connection)
 | 
			
		||||
      (fuel-log--error "No connection in buffer (%s)" str)
 | 
			
		||||
| 
						 | 
				
			
			@ -176,13 +196,13 @@
 | 
			
		|||
      (if (not req) (fuel-log--error "No current request (%s)" str)
 | 
			
		||||
        (fuel-con--request-output req str)
 | 
			
		||||
        (fuel-log--info "<%s>: in progress" (fuel-con--request-id req)))))
 | 
			
		||||
  (fuel--shorten-str str 70))
 | 
			
		||||
  (if fuel-con--debug-comint-p (fuel--shorten-str str 256) ""))
 | 
			
		||||
 | 
			
		||||
(defun fuel-con--comint-redirect-hook ()
 | 
			
		||||
  (if (not fuel-con--connection)
 | 
			
		||||
      (fuel-log--error "No connection in buffer")
 | 
			
		||||
    (let ((req (fuel-con--connection-current-request fuel-con--connection)))
 | 
			
		||||
      (if (not req) (fuel-log--error "No current request (%s)" str)
 | 
			
		||||
      (if (not req) (fuel-log--error "No current request")
 | 
			
		||||
        (fuel-con--process-completed-request req)
 | 
			
		||||
        (fuel-con--connection-clean-current-request fuel-con--connection)))))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,7 +76,6 @@
 | 
			
		|||
        ((listp usings) `(:array ,@usings))
 | 
			
		||||
        (t (error "Invalid 'usings' (%s)" usings))))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
;;; Code sending:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,9 +14,10 @@
 | 
			
		|||
 | 
			
		||||
;;; Code:
 | 
			
		||||
 | 
			
		||||
(require 'fuel-base)
 | 
			
		||||
(require 'fuel-font-lock)
 | 
			
		||||
(require 'fuel-eval)
 | 
			
		||||
(require 'fuel-completion)
 | 
			
		||||
(require 'fuel-font-lock)
 | 
			
		||||
(require 'fuel-base)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
;;; Customization:
 | 
			
		||||
| 
						 | 
				
			
			@ -108,14 +109,15 @@ displayed in the minibuffer."
 | 
			
		|||
;;; Help browser history:
 | 
			
		||||
 | 
			
		||||
(defvar fuel-help--history
 | 
			
		||||
  (list nil
 | 
			
		||||
        (make-ring fuel-help-history-cache-size)
 | 
			
		||||
        (make-ring fuel-help-history-cache-size)))
 | 
			
		||||
  (list nil                                        ; current
 | 
			
		||||
        (make-ring fuel-help-history-cache-size)   ; previous
 | 
			
		||||
        (make-ring fuel-help-history-cache-size))) ; next
 | 
			
		||||
 | 
			
		||||
(defvar fuel-help--history-idx 0)
 | 
			
		||||
 | 
			
		||||
(defun fuel-help--history-push (term)
 | 
			
		||||
  (when (car fuel-help--history)
 | 
			
		||||
  (when (and (car fuel-help--history)
 | 
			
		||||
             (not (string= (caar fuel-help--history) (car term))))
 | 
			
		||||
    (ring-insert (nth 1 fuel-help--history) (car fuel-help--history)))
 | 
			
		||||
  (setcar fuel-help--history term))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +137,7 @@ displayed in the minibuffer."
 | 
			
		|||
;;; Fuel help buffer and internals:
 | 
			
		||||
 | 
			
		||||
(defun fuel-help--help-buffer ()
 | 
			
		||||
  (with-current-buffer (get-buffer-create "*fuel-help*")
 | 
			
		||||
  (with-current-buffer (get-buffer-create "*fuel help*")
 | 
			
		||||
    (fuel-help-mode)
 | 
			
		||||
    (current-buffer)))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -148,7 +150,9 @@ displayed in the minibuffer."
 | 
			
		|||
         (ask (or (not (memq major-mode '(factor-mode fuel-help-mode)))
 | 
			
		||||
                  (not def)
 | 
			
		||||
                  fuel-help-always-ask))
 | 
			
		||||
         (def (if ask (read-string prompt nil 'fuel-help--prompt-history def)
 | 
			
		||||
         (def (if ask (fuel-completion--read-word prompt
 | 
			
		||||
                                                  def
 | 
			
		||||
                                                  'fuel-help--prompt-history)
 | 
			
		||||
                def))
 | 
			
		||||
         (cmd `(:fuel* ((:quote ,def) ,(if see 'see 'help)) t)))
 | 
			
		||||
    (message "Looking up '%s' ..." def)
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +161,7 @@ displayed in the minibuffer."
 | 
			
		|||
(defun fuel-help--show-help-cont (def ret)
 | 
			
		||||
  (let ((out (fuel-eval--retort-output ret)))
 | 
			
		||||
    (if (or (fuel-eval--retort-error ret) (empty-string-p out))
 | 
			
		||||
        (message "No help for '%s'" ret)
 | 
			
		||||
        (message "No help for '%s'" def)
 | 
			
		||||
      (fuel-help--insert-contents def out))))
 | 
			
		||||
 | 
			
		||||
(defun fuel-help--insert-contents (def str &optional nopush)
 | 
			
		||||
| 
						 | 
				
			
			@ -167,14 +171,15 @@ displayed in the minibuffer."
 | 
			
		|||
    (set-buffer hb)
 | 
			
		||||
    (erase-buffer)
 | 
			
		||||
    (insert str)
 | 
			
		||||
    (goto-char (point-min))
 | 
			
		||||
    (when (re-search-forward (format "^%s" def) nil t)
 | 
			
		||||
      (beginning-of-line)
 | 
			
		||||
      (kill-region (point-min) (point))
 | 
			
		||||
      (next-line)
 | 
			
		||||
      (open-line 1))
 | 
			
		||||
    (unless nopush
 | 
			
		||||
      (goto-char (point-min))
 | 
			
		||||
      (when (re-search-forward (format "^%s" def) nil t)
 | 
			
		||||
        (beginning-of-line)
 | 
			
		||||
        (kill-region (point-min) (point))
 | 
			
		||||
        (next-line)
 | 
			
		||||
        (open-line 1)
 | 
			
		||||
        (fuel-help--history-push (cons def (buffer-string)))))
 | 
			
		||||
    (set-buffer-modified-p nil)
 | 
			
		||||
    (unless nopush (fuel-help--history-push (cons def str)))
 | 
			
		||||
    (pop-to-buffer hb)
 | 
			
		||||
    (goto-char (point-min))
 | 
			
		||||
    (message "%s" def)))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,9 +14,11 @@
 | 
			
		|||
;;; Code:
 | 
			
		||||
 | 
			
		||||
(require 'fuel-eval)
 | 
			
		||||
(require 'fuel-base)
 | 
			
		||||
(require 'fuel-completion)
 | 
			
		||||
(require 'fuel-connection)
 | 
			
		||||
(require 'fuel-syntax)
 | 
			
		||||
(require 'fuel-base)
 | 
			
		||||
 | 
			
		||||
(require 'comint)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -63,19 +65,21 @@ buffer."
 | 
			
		|||
 | 
			
		||||
(defun fuel-listener--start-process ()
 | 
			
		||||
  (let ((factor (expand-file-name fuel-listener-factor-binary))
 | 
			
		||||
        (image (expand-file-name fuel-listener-factor-image)))
 | 
			
		||||
        (image (expand-file-name fuel-listener-factor-image))
 | 
			
		||||
        (comint-redirect-perform-sanity-check nil))
 | 
			
		||||
    (unless (file-executable-p factor)
 | 
			
		||||
      (error "Could not run factor: %s is not executable" factor))
 | 
			
		||||
    (unless (file-readable-p image)
 | 
			
		||||
      (error "Could not run factor: image file %s not readable" image))
 | 
			
		||||
    (message "Starting FUEL listener ...")
 | 
			
		||||
    (comint-exec (fuel-listener--buffer) "factor"
 | 
			
		||||
                 factor nil `("-run=listener" ,(format "-i=%s" image)))
 | 
			
		||||
    (pop-to-buffer (fuel-listener--buffer))
 | 
			
		||||
    (goto-char (point-max))
 | 
			
		||||
    (comint-send-string nil "USE: fuel \"FUEL loaded\\n\" write\n")
 | 
			
		||||
    (fuel-listener--wait-for-prompt 30)
 | 
			
		||||
    (message "FUEL listener up and running!")))
 | 
			
		||||
    (make-comint-in-buffer "fuel listener" (current-buffer) factor nil
 | 
			
		||||
                           "-run=listener" (format "-i=%s" image))
 | 
			
		||||
    (fuel-listener--wait-for-prompt 10000)
 | 
			
		||||
    (fuel-con--send-string/wait (current-buffer)
 | 
			
		||||
                                fuel-con--init-stanza
 | 
			
		||||
                                '(lambda (s) (message "FUEL listener up and running!"))
 | 
			
		||||
                                20000)))
 | 
			
		||||
 | 
			
		||||
(defun fuel-listener--process (&optional start)
 | 
			
		||||
  (or (and (buffer-live-p (fuel-listener--buffer))
 | 
			
		||||
| 
						 | 
				
			
			@ -87,21 +91,15 @@ buffer."
 | 
			
		|||
 | 
			
		||||
(setq fuel-eval--default-proc-function 'fuel-listener--process)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
;;; Prompt chasing
 | 
			
		||||
 | 
			
		||||
(defun fuel-listener--wait-for-prompt (&optional timeout)
 | 
			
		||||
  (let ((proc (get-buffer-process (fuel-listener--buffer)))
 | 
			
		||||
        (seen))
 | 
			
		||||
    (with-current-buffer (fuel-listener--buffer)
 | 
			
		||||
      (goto-char (or comint-last-input-end (point-max)))
 | 
			
		||||
      (while (and (not seen)
 | 
			
		||||
                  (accept-process-output proc (or timeout 10) nil t))
 | 
			
		||||
        (sleep-for 0 1)
 | 
			
		||||
        (goto-char comint-last-input-end)
 | 
			
		||||
        (setq seen (re-search-forward comint-prompt-regexp nil t)))
 | 
			
		||||
      (goto-char (point-max))
 | 
			
		||||
      (unless seen (error "No prompt found!")))))
 | 
			
		||||
(defun fuel-listener--wait-for-prompt (timeout)
 | 
			
		||||
  (let ((p (point)) (seen))
 | 
			
		||||
    (while (and (not seen) (> timeout 0))
 | 
			
		||||
      (sleep-for 0.1)
 | 
			
		||||
      (setq timeout (- timeout 100))
 | 
			
		||||
      (goto-char p)
 | 
			
		||||
      (setq seen (re-search-forward comint-prompt-regexp nil t)))
 | 
			
		||||
    (goto-char (point-max))
 | 
			
		||||
    (unless seen (error "No prompt found!"))))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
;;; Completion support
 | 
			
		||||
| 
						 | 
				
			
			@ -132,12 +130,10 @@ buffer."
 | 
			
		|||
 | 
			
		||||
;;; Fuel listener mode:
 | 
			
		||||
 | 
			
		||||
(defconst fuel-listener--prompt-regex ".* ) ")
 | 
			
		||||
 | 
			
		||||
(define-derived-mode fuel-listener-mode comint-mode "Fuel Listener"
 | 
			
		||||
  "Major mode for interacting with an inferior Factor listener process.
 | 
			
		||||
\\{fuel-listener-mode-map}"
 | 
			
		||||
  (set (make-local-variable 'comint-prompt-regexp) fuel-listener--prompt-regex)
 | 
			
		||||
  (set (make-local-variable 'comint-prompt-regexp) fuel-con--prompt-regex)
 | 
			
		||||
  (set (make-local-variable 'comint-prompt-read-only) t)
 | 
			
		||||
  (fuel-listener--setup-completion))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,18 +114,26 @@ buffer in case of errors."
 | 
			
		|||
  "Opens a new window visiting the definition of the word at point.
 | 
			
		||||
With prefix, asks for the word to edit."
 | 
			
		||||
  (interactive "P")
 | 
			
		||||
  (let* ((word (fuel-syntax-symbol-at-point))
 | 
			
		||||
         (ask (or arg (not word)))
 | 
			
		||||
         (word (if ask
 | 
			
		||||
                   (read-string nil
 | 
			
		||||
                                (format "Edit word%s: "
 | 
			
		||||
                                        (if word (format " (%s)" word) ""))
 | 
			
		||||
                                word)
 | 
			
		||||
                 word)))
 | 
			
		||||
    (let ((cmd `(:fuel ((:quote ,word) fuel-get-edit-location))))
 | 
			
		||||
      (condition-case nil
 | 
			
		||||
          (fuel--try-edit (fuel-eval--send/wait cmd))
 | 
			
		||||
        (error (fuel-edit-vocabulary nil word))))))
 | 
			
		||||
  (let* ((word (or (and (not arg) (fuel-syntax-symbol-at-point))
 | 
			
		||||
                  (fuel-completion--read-word "Edit word: ")))
 | 
			
		||||
         (cmd `(:fuel ((:quote ,word) fuel-get-edit-location))))
 | 
			
		||||
    (condition-case nil
 | 
			
		||||
        (fuel--try-edit (fuel-eval--send/wait cmd))
 | 
			
		||||
      (error (fuel-edit-vocabulary nil word)))))
 | 
			
		||||
 | 
			
		||||
(defvar fuel-mode--word-history nil)
 | 
			
		||||
 | 
			
		||||
(defun fuel-edit-word (&optional arg)
 | 
			
		||||
  "Asks for a word to edit, with completion.
 | 
			
		||||
With prefix, only words visible in the current vocabulary are
 | 
			
		||||
offered."
 | 
			
		||||
  (interactive "P")
 | 
			
		||||
  (let* ((word (fuel-completion--read-word "Edit word: "
 | 
			
		||||
                                           nil
 | 
			
		||||
                                           fuel-mode--word-history
 | 
			
		||||
                                           arg))
 | 
			
		||||
         (cmd `(:fuel ((:quote ,word) fuel-get-edit-location))))
 | 
			
		||||
    (fuel--try-edit (fuel-eval--send/wait cmd))))
 | 
			
		||||
 | 
			
		||||
(defvar fuel--vocabs-prompt-history nil)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +203,7 @@ interacting with a factor listener is at your disposal.
 | 
			
		|||
(fuel-mode--key ?e ?e 'fuel-eval-extended-region)
 | 
			
		||||
(fuel-mode--key ?e ?r 'fuel-eval-region)
 | 
			
		||||
(fuel-mode--key ?e ?v 'fuel-edit-vocabulary)
 | 
			
		||||
(fuel-mode--key ?e ?w 'fuel-edit-word-at-point)
 | 
			
		||||
(fuel-mode--key ?e ?w 'fuel-edit-word)
 | 
			
		||||
(fuel-mode--key ?e ?x 'fuel-eval-definition)
 | 
			
		||||
 | 
			
		||||
(fuel-mode--key ?d ?a 'fuel-autodoc-mode)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue