logs
work
build-support/wordsize
+*.bak
clean:
rm -f vm/*.o
- rm -f factor*.dll libfactor*.*
+ rm -f factor*.dll libfactor.{a,so,dylib}
vm/resources.o:
$(WINDRES) vm/factor.rs vm/resources.o
For X11 support, you need recent development libraries for libc,
Freetype, X11, OpenGL and GLUT. On a Debian-derived Linux distribution
-(like Ubuntu), you can use the line
+(like Ubuntu), you can use the following line to grab everything:
sudo apt-get install libc6-dev libfreetype6-dev libx11-dev glutg3-dev
-to grab everything (if you're on a non-debian-derived distro please tell
-us what the equivalent command is on there and it can be added).
-
* Bootstrapping the Factor image
Once you have compiled the Factor runtime, you must bootstrap the Factor
! Copyright (C) 2005, 2008 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays calendar combinators generic init
-kernel math namespaces sequences heaps boxes threads debugger
+kernel math namespaces sequences heaps boxes threads
quotations assocs math.order ;
IN: alarms
[ time>> ] dip before=? ;
: reschedule-alarm ( alarm -- )
- dup [ swap interval>> time+ ] change-time register-alarm ;
+ dup [ swap interval>> time+ now max ] change-time register-alarm ;
: call-alarm ( alarm -- )
[ entry>> box> drop ]
IN: alien.arrays\r
USING: help.syntax help.markup byte-arrays alien.c-types ;\r
\r
-ARTICLE: "c-arrays-factor" "Converting C arrays to and from Factor arrays"\r
-"Each primitive C type has a pair of words, " { $snippet ">" { $emphasis "type" } "-array" } " and " { $snippet { $emphasis "type" } "-array>" } ", for converting an array of Factor objects to and from a " { $link byte-array } " of C values. This set of words consists of:"\r
-{ $subsection >c-bool-array }\r
-{ $subsection >c-char-array }\r
-{ $subsection >c-double-array }\r
-{ $subsection >c-float-array }\r
-{ $subsection >c-int-array }\r
-{ $subsection >c-long-array }\r
-{ $subsection >c-longlong-array }\r
-{ $subsection >c-short-array }\r
-{ $subsection >c-uchar-array }\r
-{ $subsection >c-uint-array }\r
-{ $subsection >c-ulong-array }\r
-{ $subsection >c-ulonglong-array }\r
-{ $subsection >c-ushort-array }\r
-{ $subsection >c-void*-array }\r
-{ $subsection c-bool-array> }\r
-{ $subsection c-char-array> }\r
-{ $subsection c-double-array> }\r
-{ $subsection c-float-array> }\r
-{ $subsection c-int-array> }\r
-{ $subsection c-long-array> }\r
-{ $subsection c-longlong-array> }\r
-{ $subsection c-short-array> }\r
-{ $subsection c-uchar-array> }\r
-{ $subsection c-uint-array> }\r
-{ $subsection c-ulong-array> }\r
-{ $subsection c-ulonglong-array> }\r
-{ $subsection c-ushort-array> }\r
-{ $subsection c-void*-array> } ;\r
-\r
-ARTICLE: "c-arrays-get/set" "Reading and writing elements in C arrays"\r
-"Each C type has a pair of words, " { $snippet { $emphasis "type" } "-nth" } " and " { $snippet "set-" { $emphasis "type" } "-nth" } ", for reading and writing values of this type stored in an array. This set of words includes but is not limited to:"\r
-{ $subsection char-nth }\r
-{ $subsection set-char-nth }\r
-{ $subsection uchar-nth }\r
-{ $subsection set-uchar-nth }\r
-{ $subsection short-nth }\r
-{ $subsection set-short-nth }\r
-{ $subsection ushort-nth }\r
-{ $subsection set-ushort-nth }\r
-{ $subsection int-nth }\r
-{ $subsection set-int-nth }\r
-{ $subsection uint-nth }\r
-{ $subsection set-uint-nth }\r
-{ $subsection long-nth }\r
-{ $subsection set-long-nth }\r
-{ $subsection ulong-nth }\r
-{ $subsection set-ulong-nth }\r
-{ $subsection longlong-nth }\r
-{ $subsection set-longlong-nth }\r
-{ $subsection ulonglong-nth }\r
-{ $subsection set-ulonglong-nth }\r
-{ $subsection float-nth }\r
-{ $subsection set-float-nth }\r
-{ $subsection double-nth }\r
-{ $subsection set-double-nth }\r
-{ $subsection void*-nth }\r
-{ $subsection set-void*-nth } ;\r
-\r
ARTICLE: "c-arrays" "C arrays"\r
"C arrays are allocated in the same manner as other C data; see " { $link "c-byte-arrays" } " and " { $link "malloc" } "."\r
$nl\r
-"C type specifiers for array types are documented in " { $link "c-types-specs" } "."\r
-{ $subsection "c-arrays-factor" }\r
-{ $subsection "c-arrays-get/set" } ;\r
+"C type specifiers for array types are documented in " { $link "c-types-specs" } "." ;\r
M: array c-type ;
+M: array c-type-class drop object ;
+
M: array heap-size unclip heap-size [ * ] reduce ;
M: array c-type-align first c-type-align ;
{ $warning "Don't forget to deallocate the memory with a call to " { $link free } "." }
{ $errors "Throws an error if memory allocation fails." } ;
-HELP: define-nth
-{ $values { "name" "a word name" } { "vocab" "a vocabulary name" } }
-{ $description "Defines a word " { $snippet { $emphasis "name" } "-nth" } " with stack effect " { $snippet "( n c-ptr -- value )" } " for reading the value with C type " { $snippet "name" } " stored at an alien pointer, displaced by a multiple of the C type's size." }
-{ $notes "This is an internal word called when defining C types, there is no need to call it on your own." } ;
-
-HELP: define-set-nth
-{ $values { "name" "a word name" } { "vocab" "a vocabulary name" } }
-{ $description "Defines a word " { $snippet "set-" { $emphasis "name" } "-nth" } " with stack effect " { $snippet "( value n c-ptr -- )" } " for writing the value with C type " { $snippet "name" } " to an alien pointer, displaced by a multiple of the C type's size." }
-{ $notes "This is an internal word called when defining C types, there is no need to call it on your own." } ;
-
HELP: box-parameter
{ $values { "n" integer } { "ctype" string } }
{ $description "Generates code for converting a C value stored at offset " { $snippet "n" } " from the top of the stack into a Factor object to be pushed on the data stack." }
{ $notes "This is an internal word used by the compiler when compiling callbacks." } ;
HELP: define-deref
-{ $values { "name" "a word name" } { "vocab" "a vocabulary name" } }
+{ $values { "name" "a word name" } }
{ $description "Defines a word " { $snippet "*name" } " with stack effect " { $snippet "( c-ptr -- value )" } " for reading a value with C type " { $snippet "name" } " stored at an alien pointer." }
{ $notes "This is an internal word called when defining C types, there is no need to call it on your own." } ;
HELP: define-out
-{ $values { "name" "a word name" } { "vocab" "a vocabulary name" } }
+{ $values { "name" "a word name" } }
{ $description "Defines a word " { $snippet "<" { $emphasis "name" } ">" } " with stack effect " { $snippet "( value -- array )" } ". This word allocates a byte array large enough to hold a value with C type " { $snippet "name" } ", and writes the value at the top of the stack to the array." }
{ $notes "This is an internal word called when defining C types, there is no need to call it on your own." } ;
"You can copy a range of bytes from memory into a byte array:"
{ $subsection memory>byte-array }
"You can copy a byte array to memory unsafely:"
-{ $subsection byte-array>memory }
-"A wrapper for temporarily allocating a block of memory:"
-{ $subsection with-malloc } ;
+{ $subsection byte-array>memory } ;
ARTICLE: "c-data" "Passing data between Factor and C"
"Two defining characteristics of Factor are dynamic typing and automatic memory management, which are somewhat incompatible with the machine-level data model exposed by C. Factor's C library interface defines its own set of C data types, distinct from Factor language types, together with automatic conversion between Factor values and C types. For example, C integer types must be declared and are fixed-width, whereas Factor supports arbitrary-precision integers."
[ { "blah" 123 } ] [ { "blah" xyz } expand-constants ] unit-test
-: foo ( -- n ) "fdafd" f dlsym [ 123 ] unless* ;
+: foo ( -- n ) &: fdafd [ 123 ] unless* ;
[ 123 ] [ foo ] unit-test
0 B{ 1 2 3 4 } <displaced-alien> <void*>
] must-fail
-[ t ] [ { t f t } >c-bool-array { 1 0 1 } >c-int-array = ] unit-test
+os windows? cpu x86.64? and [
+ [ -2147467259 ] [ 2147500037 <long> *long ] unit-test
+] when
namespaces make 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 continuations ;
+accessors combinators effects continuations fry ;
IN: alien.c-types
DEFER: <int>
: little-endian? ( -- ? ) 1 <int> *char 1 = ; foldable
TUPLE: c-type
+class
boxer boxer-quot unboxer unboxer-quot
getter setter
reg-class size align stack-align? ;
: new-c-type ( class -- type )
new
- int-regs >>reg-class ;
+ int-regs >>reg-class
+ object >>class ; inline
: <c-type> ( -- type )
\ c-type new-c-type ;
: parse-array-type ( name -- array )
"[" split unclip
- >r [ "]" ?tail drop string>number ] map r> prefix ;
+ [ [ "]" ?tail drop string>number ] map ] dip prefix ;
M: string c-type ( name -- type )
CHAR: ] over member? [
] ?if
] if ;
+GENERIC: c-type-class ( name -- class )
+
+M: c-type c-type-class class>> ;
+
+M: string c-type-class c-type c-type-class ;
+
GENERIC: c-type-boxer ( name -- boxer )
M: c-type c-type-boxer boxer>> ;
M: string stack-size c-type stack-size ;
-M: c-type stack-size size>> ;
+M: c-type stack-size size>> cell align ;
GENERIC: byte-length ( seq -- n ) flushable
: c-getter ( name -- quot )
c-type-getter [
- [ "Cannot read struct fields with type" throw ]
+ [ "Cannot read struct fields with this type" throw ]
] unless* ;
: c-setter ( name -- quot )
c-type-setter [
- [ "Cannot write struct fields with type" throw ]
+ [ "Cannot write struct fields with this type" throw ]
] unless* ;
: <c-array> ( n type -- array )
1 swap malloc-array ; inline
: malloc-byte-array ( byte-array -- alien )
- dup length dup malloc [ -rot memcpy ] keep ;
+ dup length [ nip malloc dup ] 2keep memcpy ;
: memory>byte-array ( alien len -- byte-array )
- dup <byte-array> [ -rot memcpy ] keep ;
+ [ nip (byte-array) dup ] 2keep memcpy ;
: byte-array>memory ( byte-array base -- )
swap dup length memcpy ;
-: (define-nth) ( word type quot -- )
+: array-accessor ( type quot -- def )
[
\ swap , [ heap-size , [ * >fixnum ] % ] [ % ] bi*
- ] [ ] make define-inline ;
-
-: nth-word ( name vocab -- word )
- >r "-nth" append r> create ;
-
-: define-nth ( name vocab -- )
- dupd nth-word swap dup c-getter (define-nth) ;
-
-: set-nth-word ( name vocab -- word )
- >r "set-" swap "-nth" 3append r> create ;
-
-: define-set-nth ( name vocab -- )
- dupd set-nth-word swap dup c-setter (define-nth) ;
+ ] [ ] make ;
: typedef ( old new -- ) c-types get set-at ;
-: define-c-type ( type name vocab -- )
- >r tuck typedef r> [ define-nth ] 2keep define-set-nth ;
-
TUPLE: long-long-type < c-type ;
: <long-long-type> ( -- type )
M: long-long-type box-return ( type -- )
f swap box-parameter ;
-: define-deref ( name vocab -- )
- >r dup CHAR: * prefix r> create
- swap c-getter 0 prefix define-inline ;
+: define-deref ( name -- )
+ [ CHAR: * prefix "alien.c-types" create ]
+ [ c-getter 0 prefix ] bi
+ define-inline ;
-: define-out ( name vocab -- )
- over [ <c-object> tuck 0 ] over c-setter append swap
- >r >r constructor-word r> r> prefix define-inline ;
+: define-out ( name -- )
+ [ "alien.c-types" constructor-word ]
+ [ dup c-setter '[ _ <c-object> [ 0 @ ] keep ] ]
+ bi define-inline ;
: c-bool> ( int -- ? )
zero? not ;
-: >c-array ( seq type word -- byte-array )
- [ [ dup length ] dip <c-array> ] dip
- [ [ execute ] 2curry each-index ] 2keep drop ; inline
-
-: >c-array-quot ( type vocab -- quot )
- dupd set-nth-word [ >c-array ] 2curry ;
-
-: to-array-word ( name vocab -- word )
- >r ">c-" swap "-array" 3append r> create ;
-
-: define-to-array ( type vocab -- )
- [ to-array-word ] 2keep >c-array-quot
- (( array -- byte-array )) define-declared ;
-
-: c-array>quot ( type vocab -- quot )
- [
- \ swap ,
- nth-word 1quotation ,
- [ curry map ] %
- ] [ ] make ;
-
-: from-array-word ( name vocab -- word )
- >r "c-" swap "-array>" 3append r> create ;
-
-: define-from-array ( type vocab -- )
- [ from-array-word ] 2keep c-array>quot
- (( c-ptr n -- array )) define-declared ;
-
: define-primitive-type ( type name -- )
- "alien.c-types"
- {
- [ define-c-type ]
- [ define-deref ]
- [ define-to-array ]
- [ define-from-array ]
- [ define-out ]
- } 2cleave ;
+ [ typedef ]
+ [ define-deref ]
+ [ define-out ]
+ tri ;
: expand-constants ( c-type -- c-type' )
dup array? [
- unclip >r [
- dup word? [
- def>> { } swap with-datastack first
- ] when
- ] map r> prefix
+ unclip [
+ [
+ dup word? [
+ def>> { } swap with-datastack first
+ ] when
+ ] map
+ ] dip prefix
] when ;
: malloc-file-contents ( path -- alien len )
: if-void ( type true false -- )
pick "void" = [ drop nip call ] [ nip call ] if ; inline
+: primitive-types
+ {
+ "char" "uchar"
+ "short" "ushort"
+ "int" "uint"
+ "long" "ulong"
+ "longlong" "ulonglong"
+ "float" "double"
+ "void*" "bool"
+ } ;
+
[
<c-type>
+ c-ptr >>class
[ alien-cell ] >>getter
[ set-alien-cell ] >>setter
bootstrap-cell >>size
"void*" define-primitive-type
<long-long-type>
+ integer >>class
[ alien-signed-8 ] >>getter
[ set-alien-signed-8 ] >>setter
8 >>size
"longlong" define-primitive-type
<long-long-type>
+ integer >>class
[ alien-unsigned-8 ] >>getter
[ set-alien-unsigned-8 ] >>setter
8 >>size
"ulonglong" define-primitive-type
<c-type>
+ integer >>class
[ alien-signed-cell ] >>getter
[ set-alien-signed-cell ] >>setter
bootstrap-cell >>size
"long" define-primitive-type
<c-type>
+ integer >>class
[ alien-unsigned-cell ] >>getter
[ set-alien-unsigned-cell ] >>setter
bootstrap-cell >>size
"ulong" define-primitive-type
<c-type>
+ integer >>class
[ alien-signed-4 ] >>getter
[ set-alien-signed-4 ] >>setter
4 >>size
"int" define-primitive-type
<c-type>
+ integer >>class
[ alien-unsigned-4 ] >>getter
[ set-alien-unsigned-4 ] >>setter
4 >>size
"uint" define-primitive-type
<c-type>
+ fixnum >>class
[ alien-signed-2 ] >>getter
[ set-alien-signed-2 ] >>setter
2 >>size
"short" define-primitive-type
<c-type>
+ fixnum >>class
[ alien-unsigned-2 ] >>getter
[ set-alien-unsigned-2 ] >>setter
2 >>size
"ushort" define-primitive-type
<c-type>
+ fixnum >>class
[ alien-signed-1 ] >>getter
[ set-alien-signed-1 ] >>setter
1 >>size
"char" define-primitive-type
<c-type>
+ fixnum >>class
[ alien-unsigned-1 ] >>getter
[ set-alien-unsigned-1 ] >>setter
1 >>size
"bool" define-primitive-type
<c-type>
+ float >>class
[ alien-float ] >>getter
[ [ >float ] 2dip set-alien-float ] >>setter
4 >>size
"float" define-primitive-type
<c-type>
+ float >>class
[ alien-double ] >>getter
[ [ >float ] 2dip set-alien-double ] >>setter
8 >>size
"double" define-primitive-type
"long" "ptrdiff_t" typedef
-
+ "long" "intptr_t" typedef
"ulong" "size_t" typedef
] with-compilation-unit
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types arrays assocs effects grouping kernel
+parser sequences splitting words fry locals ;
+IN: alien.parser
+
+: parse-arglist ( parameters return -- types effect )
+ [ 2 group unzip [ "," ?tail drop ] map ]
+ [ [ { } ] [ 1array ] if-void ]
+ bi* <effect> ;
+
+: function-quot ( return library function types -- quot )
+ '[ _ _ _ _ alien-invoke ] ;
+
+:: define-function ( return library function parameters -- )
+ function create-in dup reset-generic
+ return library function
+ parameters return parse-arglist [ function-quot ] dip
+ define-declared ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel combinators alien alien.strings alien.syntax
+prettyprint.backend prettyprint.custom prettyprint.sections ;
+IN: alien.prettyprint
+
+M: alien pprint*
+ {
+ { [ dup expired? ] [ drop \ BAD-ALIEN pprint-word ] }
+ { [ dup pinned-c-ptr? not ] [ drop "( displaced alien )" text ] }
+ [ \ ALIEN: [ alien-address pprint* ] pprint-prefix ]
+ } cond ;
+
+M: dll pprint* dll-path dup "DLL\" " "\"" pprint-string ;
$nl
"On Windows CE, symbols are represented as UCS2 strings, and on all other platforms they are ASCII strings." } ;
-HELP: utf16n
-{ $class-description "The encoding descriptor for UTF-16 without a byte order mark in native endian order. This is useful mostly for FFI calls which take input of strings of the type wchar_t*" }
-{ $see-also "encodings-introduction" } ;
-
ARTICLE: "c-strings" "C strings"
"C string types are arrays with shape " { $snippet "{ \"char*\" encoding }" } ", where " { $snippet "encoding" } " is an encoding descriptor. The type " { $snippet "\"char*\"" } " is an alias for " { $snippet "{ \"char*\" utf8 }" } ". See " { $link "encodings-descriptors" } " for information about encoding descriptors."
$nl
USING: alien.strings tools.test kernel libc
io.encodings.8-bit io.encodings.utf8 io.encodings.utf16
-io.encodings.ascii alien io.encodings.string ;
+io.encodings.utf16n io.encodings.ascii alien io.encodings.string ;
IN: alien.strings.tests
[ "\u0000ff" ]
! See http://factorcode.org/license.txt for BSD license.
USING: arrays sequences kernel accessors math alien.accessors
alien.c-types byte-arrays words io io.encodings
-io.streams.byte-array io.streams.memory io.encodings.utf8
-io.encodings.utf16 system alien strings cpu.architecture ;
+io.encodings.utf8 io.streams.byte-array io.streams.memory system
+alien strings cpu.architecture fry vocabs.loader combinators ;
IN: alien.strings
GENERIC# alien>string 1 ( c-ptr encoding -- string/f )
M: c-ptr alien>string
- >r <memory-stream> r> <decoder>
+ [ <memory-stream> ] [ <decoder> ] bi*
"\0" swap stream-read-until drop ;
M: f alien>string
M: string-type c-type ;
+M: string-type c-type-class
+ drop object ;
+
M: string-type heap-size
drop "void*" heap-size ;
drop "void*" c-type-unboxer ;
M: string-type c-type-boxer-quot
- second [ alien>string ] curry [ ] like ;
+ second '[ _ alien>string ] ;
M: string-type c-type-unboxer-quot
- second [ string>alien ] curry [ ] like ;
+ second '[ _ string>alien ] ;
M: string-type c-type-getter
drop [ alien-cell ] ;
M: string-type c-type-setter
drop [ set-alien-cell ] ;
-! Native-order UTF-16
-
-SINGLETON: utf16n
-
-: utf16n ( -- descriptor )
- little-endian? utf16le utf16be ? ; foldable
+HOOK: alien>native-string os ( alien -- string )
-M: utf16n <decoder> drop utf16n <decoder> ;
-
-M: utf16n <encoder> drop utf16n <encoder> ;
-
-: alien>native-string ( alien -- string )
- os windows? [ utf16n ] [ utf8 ] if alien>string ;
+HOOK: native-string>alien os ( string -- alien )
: dll-path ( dll -- string )
path>> alien>native-string ;
: string>symbol ( str -- alien )
- [ os wince? [ utf16n ] [ utf8 ] if string>alien ]
- over string? [ call ] [ map ] if ;
+ dup string?
+ [ native-string>alien ]
+ [ [ native-string>alien ] map ] if ;
{ "char*" utf8 } "char*" typedef
-{ "char*" utf16n } "wchar_t*" typedef
"char*" "uchar*" typedef
+
+{
+ { [ os windows? ] [ "alien.strings.windows" require ] }
+ { [ os unix? ] [ "alien.strings.unix" require ] }
+} cond
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.strings io.encodings.utf8 system ;
+IN: alien.strings.unix
+
+M: unix alien>native-string utf8 alien>string ;
+
+M: unix native-string>alien utf8 string>alien ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.strings alien.c-types io.encodings.utf8
+io.encodings.utf16n system ;
+IN: alien.strings.windows
+
+M: windows alien>native-string utf16n alien>string ;
+
+M: wince native-string>alien utf16n string>alien ;
+
+M: winnt native-string>alien utf8 string>alien ;
+
+{ "char*" utf16n } "wchar_t*" typedef
writer>> swap "writing" set-word-prop ;
: reader-word ( class name vocab -- word )
- >r >r "-" r> 3append r> create ;
+ [ "-" glue ] dip create ;
: writer-word ( class name vocab -- word )
- >r [ swap "set-" % % "-" % % ] "" make r> create ;
+ [ [ swap "set-" % % "-" % % ] "" make ] dip create ;
: <field-spec> ( struct-name vocab type field-name -- spec )
field-spec new
[ (>>offset) ] [ type>> heap-size + ] 2bi
] reduce ;
-: define-struct-slot-word ( spec word quot -- )
- rot offset>> prefix define-inline ;
+: define-struct-slot-word ( word quot spec -- )
+ offset>> prefix define-inline ;
: define-getter ( type spec -- )
[ set-reader-props ] keep
- [ ]
[ reader>> ]
[
type>>
[ c-getter ] [ c-type-boxer-quot ] bi append
- ] tri
- define-struct-slot-word ;
+ ]
+ [ ] tri define-struct-slot-word ;
: define-setter ( type spec -- )
[ set-writer-props ] keep
- [ ]
- [ writer>> ]
- [ type>> c-setter ] tri
- define-struct-slot-word ;
+ [ writer>> ] [ type>> c-setter ] [ ] tri define-struct-slot-word ;
: define-field ( type spec -- )
[ define-getter ] [ define-setter ] 2bi ;
[ 120 ] [ "barx" heap-size ] unit-test
"help" vocab [
- "help" "help" lookup "help" set
+ "print-topic" "help" lookup "help" set
[ ] [ \ foox-x "help" get execute ] unit-test
[ ] [ \ set-foox-x "help" get execute ] unit-test
] when
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays generic hashtables kernel kernel.private
-math namespaces parser sequences strings words libc
+math namespaces parser sequences strings words libc fry
alien.c-types alien.structs.fields cpu.architecture ;
IN: alien.structs
-: if-value-structs? ( ctype true false -- )
- value-structs?
- [ drop call ] [ >r 2drop "void*" r> call ] if ; inline
-
TUPLE: struct-type size align fields ;
M: struct-type heap-size size>> ;
+M: struct-type c-type-class drop object ;
+
M: struct-type c-type-align align>> ;
M: struct-type c-type-stack-align? drop f ;
-M: struct-type unbox-parameter
- [ %unbox-struct ] [ unbox-parameter ] if-value-structs? ;
+: if-value-struct ( ctype true false -- )
+ [ dup value-struct? ] 2dip '[ drop "void*" @ ] if ; inline
-M: struct-type unbox-return
- f swap %unbox-struct ;
+M: struct-type unbox-parameter
+ [ %unbox-large-struct ] [ unbox-parameter ] if-value-struct ;
M: struct-type box-parameter
- [ %box-struct ] [ box-parameter ] if-value-structs? ;
+ [ %box-large-struct ] [ box-parameter ] if-value-struct ;
+
+: if-small-struct ( c-type true false -- ? )
+ [ dup struct-small-enough? ] 2dip '[ f swap @ ] if ; inline
+
+M: struct-type unbox-return
+ [ %unbox-small-struct ] [ %unbox-large-struct ] if-small-struct ;
M: struct-type box-return
- f swap %box-struct ;
+ [ %box-small-struct ] [ %box-large-struct ] if-small-struct ;
M: struct-type stack-size
- [ heap-size ] [ stack-size ] if-value-structs? ;
+ [ heap-size ] [ stack-size ] if-value-struct ;
: c-struct? ( type -- ? ) (c-type) struct-type? ;
-: (define-struct) ( name vocab size align fields -- )
- >r [ align ] keep r>
+: (define-struct) ( name size align fields -- )
+ [ [ align ] keep ] dip
struct-type boa
- -rot define-c-type ;
+ swap typedef ;
-: define-struct-early ( name vocab fields -- fields )
- -rot [ rot first2 <field-spec> ] 2curry map ;
+: make-fields ( name vocab fields -- fields )
+ [ first2 <field-spec> ] with with map ;
: compute-struct-align ( types -- n )
[ c-type-align ] map supremum ;
: define-struct ( name vocab fields -- )
- pick >r
- [ struct-offsets ] keep
- [ [ type>> ] map compute-struct-align ] keep
- [ (define-struct) ] keep
- r> [ swap define-field ] curry each ;
-
-: define-union ( name vocab members -- )
+ [
+ [ 2drop ] [ make-fields ] 3bi
+ [ struct-offsets ] keep
+ [ [ type>> ] map compute-struct-align ] keep
+ [ (define-struct) ] keep
+ ] [ 2drop '[ _ swap define-field ] ] 3bi each ;
+
+: define-union ( name members -- )
[ expand-constants ] map
[ [ heap-size ] map supremum ] keep
compute-struct-align f (define-struct) ;
IN: alien.syntax
-USING: alien alien.c-types alien.structs alien.syntax.private
+USING: alien alien.c-types alien.parser alien.structs
help.markup help.syntax ;
HELP: DLL"
{ $description "Aliases the C type " { $snippet "old" } " under the name " { $snippet "new" } " if ." }
{ $notes "This word differs from " { $link typedef } " in that it runs at parse time, to ensure correct ordering of operations when loading source files. Words defined in source files are compiled before top-level forms are run, so if a source file defines C binding words and uses " { $link typedef } ", the type alias won't be available at compile time." } ;
-HELP: TYPEDEF-IF:
-{ $syntax "TYPEDEF-IF: word old new" }
-{ $values { "word" "a word with stack effect " { $snippet "( -- ? )" } } { "old" "a C type" } { "new" "a C type" } }
-{ $description "Aliases the C type " { $snippet "old" } " under the name " { $snippet "new" } " if " { $snippet "word" } " evaluates to a true value." }
-{ $notes "This word differs from " { $link typedef } " in that it runs at parse time, to ensure correct ordering of operations when loading source files. Words defined in source files are compiled before top-level forms are run, so if a source file defines C binding words and uses " { $link typedef } ", the type alias won't be available at compile time." } ;
-
HELP: C-STRUCT:
{ $syntax "C-STRUCT: name pairs... ;" }
{ $values { "name" "a new C type name" } { "pairs" "C type / field name string pairs" } }
{ $code "C-ENUM: red green blue ;" ": red 0 ; : green 1 ; : blue 2 ;" }
} ;
+HELP: &:
+{ $syntax "&: symbol" }
+{ $values { "symbol" "A C library symbol name" } }
+{ $description "Pushes the address of a symbol named " { $snippet "symbol" } " from the current library, set with " { $link POSTPONE: LIBRARY: } "." } ;
+
HELP: typedef
{ $values { "old" "a string" } { "new" "a string" } }
{ $description "Alises the C type " { $snippet "old" } " under the name " { $snippet "new" } "." }
{ $notes "Using this word in the same source file which defines C bindings can cause problems, because words are compiled before top-level forms are run. Use the " { $link POSTPONE: TYPEDEF: } " word instead." } ;
-{ POSTPONE: TYPEDEF-IF: POSTPONE: TYPEDEF: typedef } related-words
+{ POSTPONE: TYPEDEF: typedef } related-words
HELP: c-struct?
{ $values { "type" "a string" } { "?" "a boolean" } }
USING: accessors arrays alien alien.c-types alien.structs
alien.arrays alien.strings kernel math namespaces parser
sequences words quotations math.parser splitting grouping
-effects prettyprint prettyprint.sections prettyprint.backend
-assocs combinators lexer strings.parser ;
+effects assocs combinators lexer strings.parser alien.parser
+fry ;
IN: alien.syntax
-<PRIVATE
-
-: parse-arglist ( return seq -- types effect )
- 2 group dup keys swap values [ "," ?tail drop ] map
- rot dup "void" = [ drop { } ] [ 1array ] if <effect> ;
-
-: function-quot ( type lib func types -- quot )
- [ alien-invoke ] 2curry 2curry ;
-
-: define-function ( return library function parameters -- )
- >r pick r> parse-arglist
- pick create-in dup reset-generic
- >r >r function-quot r> r>
- -rot define-declared ;
-
-PRIVATE>
-
-: indirect-quot ( function-ptr-quot return types abi -- quot )
- [ alien-indirect ] 3curry compose ;
-
-: define-indirect ( abi return function-ptr-quot function-name parameters -- )
- >r pick r> parse-arglist
- rot create-in dup reset-generic
- >r >r swapd roll indirect-quot r> r>
- -rot define-declared ;
-
: DLL" lexer get skip-blank parse-string dlopen parsed ; parsing
: ALIEN: scan string>number <alien> parsed ; parsing
: TYPEDEF:
scan scan typedef ; parsing
-: TYPEDEF-IF:
- scan-word execute scan scan rot [ typedef ] [ 2drop ] if ; parsing
-
: C-STRUCT:
- scan in get
- parse-definition
- >r 2dup r> define-struct-early
- define-struct ; parsing
+ scan in get parse-definition define-struct ; parsing
: C-UNION:
- scan in get parse-definition define-union ; parsing
+ scan parse-definition define-union ; parsing
: C-ENUM:
";" parse-tokens
dup length
- [ >r create-in r> 1quotation define ] 2each ;
+ [ [ create-in ] dip 1quotation define ] 2each ;
parsing
-M: alien pprint*
- {
- { [ dup expired? ] [ drop \ BAD-ALIEN pprint-word ] }
- { [ dup pinned-c-ptr? not ] [ drop "( displaced alien )" text ] }
- [ \ ALIEN: [ alien-address pprint* ] pprint-prefix ]
- } cond ;
-
-M: dll pprint* dll-path dup "DLL\" " "\"" pprint-string ;
+: &:
+ scan "c-library" get
+ '[ _ _ load-library dlsym ] over push-all ; parsing
! See http://factorcode.org/license.txt for BSD license.
USING: alien.c-types accessors math alien.accessors kernel
kernel.private locals sequences sequences.private byte-arrays
-parser prettyprint.backend ;
+parser prettyprint.custom fry ;
IN: bit-arrays
TUPLE: bit-array
: bits>bytes 7 + n>byte ; inline
: (set-bits) ( bit-array n -- )
- [ [ length bits>cells ] keep ] dip
- [ -rot underlying>> set-uint-nth ] 2curry
- each ; inline
+ [ [ length bits>cells ] keep ] dip swap underlying>>
+ '[ [ _ _ ] dip set-alien-unsigned-4 ] each ; inline
PRIVATE>
:: integer>bit-array ( n -- bit-array )
n zero? [ 0 <bit-array> ] [
[let | out [ n log2 1+ <bit-array> ] i! [ 0 ] n'! [ n ] |
- [ n' zero? not ] [
+ [ n' zero? ] [
n' out underlying>> i set-alien-unsigned-1
n' -8 shift n'!
i 1+ i!
- ] [ ] while
+ ] [ ] until
out
]
] if ;
: bit-array>integer ( bit-array -- n )
- 0 swap underlying>> [ length ] keep [
- uchar-nth swap 8 shift bitor
- ] curry each ;
+ 0 swap underlying>> dup length [
+ alien-unsigned-1 swap 8 shift bitor
+ ] with each ;
INSTANCE: bit-array sequence
[ 0 ] [ 123 <bit-vector> length ] unit-test\r
\r
: do-it\r
- 1234 swap [ >r even? r> push ] curry each ;\r
+ 1234 swap [ [ even? ] dip push ] curry each ;\r
\r
[ t ] [\r
3 <bit-vector> dup do-it\r
! Copyright (C) 2008 Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
USING: arrays kernel kernel.private math sequences\r
-sequences.private growable bit-arrays prettyprint.backend\r
+sequences.private growable bit-arrays prettyprint.custom\r
parser accessors ;\r
IN: bit-vectors\r
\r
--- /dev/null
+USING: continuations kernel io debugger vocabs words system namespaces ;
+
+:c
+:error
+"listener" vocab
+[ restarts. vocab-main execute ]
+[ die ] if*
+1 exit
classes.private arrays hashtables vectors classes.tuple sbufs
hashtables.private sequences.private math classes.tuple.private
growable namespaces.private assocs words command-line vocabs io
-io.encodings.string prettyprint libc splitting math.parser
+io.encodings.string libc splitting math.parser
compiler.units math.order compiler.tree.builder
compiler.tree.optimizer compiler.cfg.optimizer ;
IN: bootstrap.compiler
! Don't bring this in when deploying, since it will store a
! reference to 'eval' in a global variable
-"deploy-vocab" get [
+"deploy-vocab" get "staging" get or [
"alien.remote-control" require
] unless
+"prettyprint" vocab [
+ "stack-checker.errors.prettyprint" require
+ "alien.prettyprint" require
+] when
+
"cpu." cpu name>> append require
enable-compiler
"." write flush
{
- new-sequence nth push pop peek
+ new-sequence nth push pop peek flip
} compile-uncompiled
"." write flush
"." write flush
{
- . malloc calloc free memcpy
+ malloc calloc free memcpy
} compile-uncompiled
"." write flush
--- /dev/null
+USING: init command-line debugger system continuations
+namespaces eval kernel vocabs.loader io ;
+
+[
+ boot
+ do-init-hooks
+ [
+ (command-line) parse-command-line
+ load-vocab-roots
+ run-user-init
+ "e" get [ eval ] when*
+ ignore-cli-args? not script get and
+ [ run-script ] [ "run" get run ] if*
+ output-stream get [ stream-flush ] when*
+ ] [ print-error 1 exit ] recover
+] set-boot-quot
--- /dev/null
+USING: init command-line system namespaces kernel vocabs.loader
+io ;
+
+[
+ boot
+ do-init-hooks
+ (command-line) parse-command-line
+ "run" get run
+ output-stream get [ stream-flush ] when*
+] set-boot-quot
USING: help help.topics help.syntax help.crossref
help.definitions io io.files kernel namespaces vocabs sequences
-parser vocabs.loader ;
+parser vocabs.loader vocabs.loader.private accessors assocs ;
IN: bootstrap.help
: load-help ( -- )
t load-help? set-global
[ drop ] load-vocab-hook [
- vocabs
- [ vocab-docs-loaded? not ] filter
+ dictionary get values
+ [ docs-loaded?>> not ] filter
[ load-docs ] each
] with-variable ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: http.client checksums checksums.openssl splitting assocs
+USING: http.client checksums checksums.md5 splitting assocs
kernel io.files bootstrap.image sequences io urls ;
IN: bootstrap.image.download
: need-new-image? ( image -- ? )
dup exists?
[
- [ openssl-md5 checksum-file hex-string ]
+ [ md5 checksum-file hex-string ]
[ download-checksums at ]
bi = not
] [ drop t ] if ;
os name>> cpu name>> arch ;
: boot-image-name ( arch -- string )
- "boot." swap ".image" 3append ;
+ "boot." ".image" surround ;
: my-boot-image-name ( -- string )
my-arch boot-image-name ;
: put-object ( n obj -- ) (objects) set-at ;
: cache-object ( obj quot -- value )
- >r (objects) r> [ obj>> ] prepose cache ; inline
+ [ (objects) ] dip [ obj>> ] prepose cache ; inline
! Constants
{ [ { } make ] [ ] [ ] [ ] } spread 4array ; inline
: jit-define ( quot rc rt offset name -- )
- >r make-jit r> set ; inline
+ [ make-jit ] dip set ; inline
: define-sub-primitive ( quot rc rt offset word -- )
- >r make-jit r> sub-primitives get set-at ;
+ [ make-jit ] dip sub-primitives get set-at ;
! The image being constructed; a vector of word-size integers
SYMBOL: image
SYMBOL: jit-primitive
SYMBOL: jit-word-jump
SYMBOL: jit-word-call
-SYMBOL: jit-push-literal
SYMBOL: jit-push-immediate
SYMBOL: jit-if-word
-SYMBOL: jit-if-jump
+SYMBOL: jit-if-1
+SYMBOL: jit-if-2
SYMBOL: jit-dispatch-word
SYMBOL: jit-dispatch
+SYMBOL: jit-dip-word
+SYMBOL: jit-dip
+SYMBOL: jit-2dip-word
+SYMBOL: jit-2dip
+SYMBOL: jit-3dip-word
+SYMBOL: jit-3dip
SYMBOL: jit-epilog
SYMBOL: jit-return
SYMBOL: jit-profiling
! Default definition for undefined words
SYMBOL: undefined-quot
-: userenv-offset ( symbol -- n )
- {
+: userenvs ( -- assoc )
+ H{
{ bootstrap-boot-quot 20 }
{ bootstrap-global 21 }
{ jit-code-format 22 }
{ jit-primitive 25 }
{ jit-word-jump 26 }
{ jit-word-call 27 }
- { jit-push-literal 28 }
- { jit-if-word 29 }
- { jit-if-jump 30 }
+ { jit-if-word 28 }
+ { jit-if-1 29 }
+ { jit-if-2 30 }
{ jit-dispatch-word 31 }
{ jit-dispatch 32 }
{ jit-epilog 33 }
{ jit-push-immediate 36 }
{ jit-declare-word 42 }
{ jit-save-stack 43 }
+ { jit-dip-word 44 }
+ { jit-dip 45 }
+ { jit-2dip-word 46 }
+ { jit-2dip 47 }
+ { jit-3dip-word 48 }
+ { jit-3dip 49 }
{ undefined-quot 60 }
- } at header-size + ;
+ } ; inline
+
+: userenv-offset ( symbol -- n )
+ userenvs at header-size + ;
: emit ( cell -- ) image get push ;
: emit-fixnum ( n -- ) tag-fixnum emit ;
: emit-object ( header tag quot -- addr )
- swap here-as >r swap tag-fixnum emit call align-here r> ;
+ swap here-as [ swap tag-fixnum emit call align-here ] dip ;
inline
! Write an object to the image.
: pad-bytes ( seq -- newseq )
dup length bootstrap-cell align 0 pad-right ;
+: check-string ( string -- )
+ [ 127 > ] contains?
+ [ "Bootstrap cannot emit non-ASCII strings" throw ] when ;
+
: emit-string ( string -- ptr )
+ dup check-string
string type-number object tag-number [
dup length emit-fixnum
f ' emit
\ dispatch jit-dispatch-word set
\ do-primitive jit-primitive-word set
\ declare jit-declare-word set
+ \ dip jit-dip-word set
+ \ 2dip jit-2dip-word set
+ \ 3dip jit-3dip-word set
[ undefined ] undefined-quot set
{
jit-code-format
jit-primitive
jit-word-jump
jit-word-call
- jit-push-literal
jit-push-immediate
jit-if-word
- jit-if-jump
+ jit-if-1
+ jit-if-2
jit-dispatch-word
jit-dispatch
+ jit-dip-word
+ jit-dip
+ jit-2dip-word
+ jit-2dip
+ jit-3dip-word
+ jit-3dip
jit-epilog
jit-return
jit-profiling
-USE: vocabs.loader
+USING: vocabs vocabs.loader kernel ;
"math.ratios" require
"math.floats" require
"math.complex" require
+
+"prettyprint" vocab [ "math.complex.prettyprint" require ] when
! See http://factorcode.org/license.txt for BSD license.
USING: accessors init namespaces words io
kernel.private math memory continuations kernel io.files
-io.backend system parser vocabs sequences prettyprint
+io.backend system parser vocabs sequences
vocabs.loader combinators splitting source-files strings
definitions assocs compiler.errors compiler.units
-math.parser generic sets debugger command-line ;
+math.parser generic sets command-line ;
IN: bootstrap.stage2
SYMBOL: core-bootstrap-time
: count-words ( pred -- )
all-words swap count number>string write ;
-: print-time ( time -- )
+: print-time ( ms -- )
1000 /i
60 /mod swap
number>string write
"math compiler threads help io tools ui ui.tools unicode handbook" "include" set-global
"" "exclude" set-global
- parse-command-line
+ (command-line) parse-command-line
- "-no-crossref" cli-args member? [ do-crossref ] unless
+ do-crossref
! Set dll paths
os wince? [ "windows.ce" require ] when
os winnt? [ "windows.nt" require ] when
- "deploy-vocab" get [
+ "staging" get "deploy-vocab" get or [
"stage2: deployment mode" print
] [
"listener" require
f error set-global
f error-continuation set-global
+ millis swap - bootstrap-time set-global
+ print-report
+
"deploy-vocab" get [
"tools.deploy.shaker" run
] [
- [
- boot
- do-init-hooks
- [
- parse-command-line
- run-user-init
- "run" get run
- output-stream get [ stream-flush ] when*
- ] [ print-error 1 exit ] recover
- ] set-boot-quot
-
- millis swap - bootstrap-time set-global
- print-report
+ "staging" get [
+ "resource:basis/bootstrap/finish-staging.factor" run-file
+ ] [
+ "resource:basis/bootstrap/finish-bootstrap.factor" run-file
+ ] if
"output-image" get save-image-and-exit
] if
] [
- :c
- dup print-error flush
- "listener" vocab
- [ restarts. vocab-main execute ]
- [ die ] if*
- 1 exit
+ drop
+ load-help? off
+ "resource:basis/bootstrap/bootstrap-error.factor" run-file
] recover
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
+USING: vocabs vocabs.loader kernel ;
IN: bootstrap.threads
USE: io.thread
USE: threads
-USE: debugger.threads
+
+"debugger" vocab [
+ "debugger.threads" require
+] when
dup occupied>> [ box> t ] [ drop f f ] if ;\r
\r
: if-box? ( box quot -- )\r
- >r ?box r> [ drop ] if ; inline\r
+ [ ?box ] dip [ drop ] if ; inline\r
--- /dev/null
+USING: arrays byte-arrays help.markup help.syntax kernel\r
+byte-vectors.private combinators ;\r
+IN: byte-vectors\r
+\r
+ARTICLE: "byte-vectors" "Byte vectors"\r
+"A byte vector is a resizable mutable sequence of unsigned bytes. Byte vector words are found in the " { $vocab-link "byte-vectors" } " vocabulary."\r
+$nl\r
+"Byte vectors form a class:"\r
+{ $subsection byte-vector }\r
+{ $subsection byte-vector? }\r
+"Creating byte vectors:"\r
+{ $subsection >byte-vector }\r
+{ $subsection <byte-vector> }\r
+"Literal syntax:"\r
+{ $subsection POSTPONE: BV{ }\r
+"If you don't care about initial capacity, a more elegant way to create a new byte vector is to write:"\r
+{ $code "BV{ } clone" } ;\r
+\r
+ABOUT: "byte-vectors"\r
+\r
+HELP: byte-vector\r
+{ $description "The class of resizable byte vectors. See " { $link "byte-vectors" } " for information." } ;\r
+\r
+HELP: <byte-vector>\r
+{ $values { "n" "a positive integer specifying initial capacity" } { "byte-vector" byte-vector } }\r
+{ $description "Creates a new byte vector that can hold " { $snippet "n" } " bytes before resizing." } ;\r
+\r
+HELP: >byte-vector\r
+{ $values { "seq" "a sequence" } { "byte-vector" byte-vector } }\r
+{ $description "Outputs a freshly-allocated byte vector with the same elements as a given sequence." }\r
+{ $errors "Throws an error if the sequence contains elements other than integers." } ;\r
+\r
+HELP: BV{\r
+{ $syntax "BV{ elements... }" }\r
+{ $values { "elements" "a list of bytes" } }\r
+{ $description "Marks the beginning of a literal byte vector. Literal byte vectors are terminated by " { $link POSTPONE: } } "." } \r
+{ $examples { $code "BV{ 1 2 3 12 }" } } ;\r
--- /dev/null
+IN: byte-vectors.tests\r
+USING: tools.test byte-vectors vectors sequences kernel\r
+prettyprint ;\r
+\r
+[ 0 ] [ 123 <byte-vector> length ] unit-test\r
+\r
+: do-it\r
+ 123 [ over push ] each ;\r
+\r
+[ t ] [\r
+ 3 <byte-vector> do-it\r
+ 3 <vector> do-it sequence=\r
+] unit-test\r
+\r
+[ t ] [ BV{ } byte-vector? ] unit-test\r
+\r
+[ "BV{ }" ] [ BV{ } unparse ] unit-test\r
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.\r
+! See http://factorcode.org/license.txt for BSD license.\r
+USING: arrays kernel kernel.private math sequences\r
+sequences.private growable byte-arrays accessors parser\r
+prettyprint.custom ;\r
+IN: byte-vectors\r
+\r
+TUPLE: byte-vector\r
+{ underlying byte-array }\r
+{ length array-capacity } ;\r
+\r
+: <byte-vector> ( n -- byte-vector )\r
+ (byte-array) 0 byte-vector boa ; inline\r
+\r
+: >byte-vector ( seq -- byte-vector )\r
+ T{ byte-vector f B{ } 0 } clone-like ;\r
+\r
+M: byte-vector like\r
+ drop dup byte-vector? [\r
+ dup byte-array?\r
+ [ dup length byte-vector boa ] [ >byte-vector ] if\r
+ ] unless ;\r
+\r
+M: byte-vector new-sequence\r
+ drop [ (byte-array) ] [ >fixnum ] bi byte-vector boa ;\r
+\r
+M: byte-vector equal?\r
+ over byte-vector? [ sequence= ] [ 2drop f ] if ;\r
+\r
+M: byte-array like\r
+ #! If we have an byte-array, we're done.\r
+ #! If we have a byte-vector, and it's at full capacity,\r
+ #! we're done. Otherwise, call resize-byte-array, which is a\r
+ #! relatively fast primitive.\r
+ drop dup byte-array? [\r
+ dup byte-vector? [\r
+ [ length ] [ underlying>> ] bi\r
+ 2dup length eq?\r
+ [ nip ] [ resize-byte-array ] if\r
+ ] [ >byte-array ] if\r
+ ] unless ;\r
+\r
+M: byte-array new-resizable drop <byte-vector> ;\r
+\r
+: BV{ \ } [ >byte-vector ] parse-literal ; parsing\r
+\r
+M: byte-vector pprint* pprint-object ;\r
+M: byte-vector pprint-delims drop \ BV{ \ } ;\r
+M: byte-vector >pprint-sequence ;\r
+\r
+INSTANCE: byte-vector growable\r
--- /dev/null
+Growable byte arrays
--- /dev/null
+collections
{ $values { "timestamp" timestamp } }
{ $description "Outputs the beginning of UNIX time, or midnight, January 1, 1970." } ;
-HELP: millis>timestamp
+HELP: micros>timestamp
{ $values { "x" number } { "timestamp" timestamp } }
-{ $description "Converts a number of milliseconds into a timestamp value in GMT time." }
+{ $description "Converts a number of microseconds into a timestamp value in GMT time." }
{ $examples
{ $example "USING: accessors calendar prettyprint ;"
- "1000 millis>timestamp year>> ."
+ "1000 micros>timestamp year>> ."
"1970"
}
} ;
[ +gt+ ] [ 2005 1 1 12 30 0 instant <timestamp>
2004 1 1 13 30 0 instant <timestamp> <=> ] unit-test
-[ t ] [ now timestamp>millis millis - 1000 < ] unit-test
-[ t ] [ 0 millis>timestamp unix-1970 = ] unit-test
-[ t ] [ 123456789000 [ millis>timestamp timestamp>millis ] keep = ] unit-test
-[ t ] [ 123456789123456 [ millis>timestamp timestamp>millis ] keep = ] unit-test
+[ t ] [ now timestamp>micros micros - 1000000 < ] unit-test
+[ t ] [ 0 micros>timestamp unix-1970 = ] unit-test
+[ t ] [ 123456789000000 [ micros>timestamp timestamp>micros ] keep = ] unit-test
+[ t ] [ 123456789123456000 [ micros>timestamp timestamp>micros ] keep = ] unit-test
: checktime+ now dup clone [ rot time+ drop ] keep = ;
12 /rem dup zero? [ drop 1- 12 ] when swap ; inline
M: integer +month ( timestamp n -- timestamp )
- [ over month>> + months/years >r >>month r> +year ] unless-zero ;
+ [ over month>> + months/years [ >>month ] dip +year ] unless-zero ;
M: real +month ( timestamp n -- timestamp )
[ float>whole-part swapd average-month * +day swap +month ] unless-zero ;
M: integer +day ( timestamp n -- timestamp )
[
over >date< julian-day-number + julian-day-number>date
- >r >r >>year r> >>month r> >>day
+ [ >>year ] [ >>month ] [ >>day ] tri*
] unless-zero ;
M: real +day ( timestamp n -- timestamp )
24 /rem swap ;
M: integer +hour ( timestamp n -- timestamp )
- [ over hour>> + hours/days >r >>hour r> +day ] unless-zero ;
+ [ over hour>> + hours/days [ >>hour ] dip +day ] unless-zero ;
M: real +hour ( timestamp n -- timestamp )
float>whole-part swapd 60 * +minute swap +hour ;
60 /rem swap ;
M: integer +minute ( timestamp n -- timestamp )
- [ over minute>> + minutes/hours >r >>minute r> +hour ] unless-zero ;
+ [ over minute>> + minutes/hours [ >>minute ] dip +hour ] unless-zero ;
M: real +minute ( timestamp n -- timestamp )
[ float>whole-part swapd 60 * +second swap +minute ] unless-zero ;
60 /rem swap >integer ;
M: number +second ( timestamp n -- timestamp )
- [ over second>> + seconds/minutes >r >>second r> +minute ] unless-zero ;
+ [ over second>> + seconds/minutes [ >>second ] dip +minute ] unless-zero ;
: (time+)
[ second>> +second ] keep
GENERIC# time+ 1 ( time1 time2 -- time3 )
M: timestamp time+
- >r clone r> (time+) drop ;
+ [ clone ] dip (time+) drop ;
M: duration time+
dup timestamp? [
: (time-) ( timestamp timestamp -- n )
[ >gmt ] bi@
[ [ >date< julian-day-number ] bi@ - 86400 * ] 2keep
- [ >time< >r >r 3600 * r> 60 * r> + + ] bi@ - + ;
+ [ >time< [ [ 3600 * ] [ 60 * ] bi* ] dip + + ] bi@ - + ;
M: timestamp time-
#! Exact calendar-time difference
1970 1 1 0 0 0 instant <timestamp> ;
: millis>timestamp ( x -- timestamp )
- >r unix-1970 r> milliseconds time+ ;
+ [ unix-1970 ] dip milliseconds time+ ;
: timestamp>millis ( timestamp -- n )
unix-1970 (time-) 1000 * >integer ;
+: micros>timestamp ( x -- timestamp )
+ [ unix-1970 ] dip microseconds time+ ;
+
+: timestamp>micros ( timestamp -- n )
+ unix-1970 (time-) 1000000 * >integer ;
+
: gmt ( -- timestamp )
#! GMT time, right now
- unix-1970 millis milliseconds time+ ;
+ unix-1970 micros microseconds time+ ;
: now ( -- timestamp ) gmt >local-time ;
: hence ( duration -- timestamp ) now swap time+ ;
#! Zeller Congruence
#! http://web.textfiles.com/computers/formulas.txt
#! good for any date since October 15, 1582
- >r dup 2 <= [ 12 + >r 1- r> ] when
- >r dup [ 4 /i + ] keep [ 100 /i - ] keep 400 /i + r>
- [ 1+ 3 * 5 /i + ] keep 2 * + r>
- 1+ + 7 mod ;
+ [
+ dup 2 <= [ [ 1- ] [ 12 + ] bi* ] when
+ [ dup [ 4 /i + ] keep [ 100 /i - ] keep 400 /i + ] dip
+ [ 1+ 3 * 5 /i + ] keep 2 * +
+ ] dip 1+ + 7 mod ;
GENERIC: days-in-year ( obj -- n )
: since-1970 ( duration -- timestamp )
unix-1970 time+ >local-time ;
-M: timestamp sleep-until timestamp>millis sleep-until ;
+M: timestamp sleep-until timestamp>micros sleep-until ;
M: duration sleep hence sleep-until ;
-USING: math math.order math.parser math.functions kernel sequences io\r
-accessors arrays io.streams.string splitting\r
-combinators accessors debugger\r
-calendar calendar.format.macros ;\r
+! Copyright (C) 2008 Slava Pestov.\r
+! See http://factorcode.org/license.txt for BSD license.\r
+USING: math math.order math.parser math.functions kernel\r
+sequences io accessors arrays io.streams.string splitting\r
+combinators accessors calendar calendar.format.macros present ;\r
IN: calendar.format\r
\r
: pad-00 ( n -- str ) number>string 2 CHAR: 0 pad-left ;\r
\r
: read-rfc3339-gmt-offset ( ch -- dt )\r
dup CHAR: Z = [ drop instant ] [\r
- >r\r
- read-00 hours\r
- read1 { { CHAR: : [ read-00 ] } { f [ 0 ] } } case minutes\r
- time+\r
- r> signed-gmt-offset\r
+ [\r
+ read-00 hours\r
+ read1 { { CHAR: : [ read-00 ] } { f [ 0 ] } } case minutes\r
+ time+\r
+ ] dip signed-gmt-offset\r
] if ;\r
\r
: read-ymd ( -- y m d )\r
read-00 ":" expect read-00 ":" expect read-00 ;\r
\r
: read-rfc3339-seconds ( s -- s' ch )\r
- "+-Z" read-until >r\r
- [ string>number ] [ length 10 swap ^ ] bi / + r> ;\r
+ "+-Z" read-until [\r
+ [ string>number ] [ length 10 swap ^ ] bi / +\r
+ ] dip ;\r
\r
: (rfc3339>timestamp) ( -- timestamp )\r
read-ymd\r
\r
: parse-rfc822-gmt-offset ( string -- dt )\r
dup "GMT" = [ drop instant ] [\r
- unclip >r\r
- 2 cut [ string>number ] bi@ [ hours ] [ minutes ] bi* time+\r
- r> signed-gmt-offset\r
+ unclip [ \r
+ 2 cut [ string>number ] bi@ [ hours ] [ minutes ] bi* time+\r
+ ] dip signed-gmt-offset\r
] if ;\r
\r
: (rfc822>timestamp) ( -- timestamp )\r
]\r
} formatted\r
] with-string-writer ;\r
+\r
+M: timestamp present timestamp>string ;\r
\r
: (time-thread) ( -- )\r
now time get set-model\r
- 1000 sleep (time-thread) ;\r
+ 1 seconds sleep (time-thread) ;\r
\r
: time-thread ( -- )\r
[\r
PRIVATE>
: publish ( channel -- id )
- 256 random-bits dup >r remote-channels set-at r> ;
+ 256 random-bits dup [ remote-channels set-at ] dip ;
: get-channel ( id -- channel )
remote-channels at ;
] "" make 64 group ;
: update-old-new ( old new -- )
- [ get >r get r> ] 2keep >r >r w+ dup r> set r> set ; inline
+ [ [ get ] bi@ w+ dup ] 2keep [ set ] bi@ ; inline
math.functions math.parser namespaces splitting grouping strings
sequences byte-arrays locals sequences.private
io.encodings.binary symbols math.bitwise checksums
-checksums.common ;
+checksums.common checksums.stream ;
IN: checksums.md5
! See http://www.faqs.org/rfcs/rfc1321.html
SYMBOLS: a b c d old-a old-b old-c old-d ;
: T ( N -- Y )
- sin abs 4294967296 * >bignum ; foldable
+ sin abs 4294967296 * >integer ; foldable
: initialize-md5 ( -- )
0 bytes-read set
SINGLETON: md5
-INSTANCE: md5 checksum
+INSTANCE: md5 stream-checksum
M: md5 checksum-stream ( stream -- byte-array )
drop [ initialize-md5 stream>md5 get-md5 ] with-input-stream ;
! Copyright (C) 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: accessors byte-arrays alien.c-types kernel continuations
-destructors sequences io openssl openssl.libcrypto checksums ;
+destructors sequences io openssl openssl.libcrypto checksums
+checksums.stream ;
IN: checksums.openssl
ERROR: unknown-digest name ;
: openssl-sha1 T{ openssl-checksum f "sha1" } ;
-INSTANCE: openssl-checksum checksum
+INSTANCE: openssl-checksum stream-checksum
C: <openssl-checksum> openssl-checksum
handle>> EVP_MD_CTX_cleanup drop ;
: with-evp-md-context ( quot -- )
- maybe-init-ssl >r <evp-md-context> r> with-disposal ; inline
+ maybe-init-ssl [ <evp-md-context> ] dip with-disposal ; inline
: digest-named ( name -- md )
dup EVP_get_digestbyname
USING: arrays combinators kernel io io.encodings.binary io.files
io.streams.byte-array math.vectors strings sequences namespaces
make math parser sequences assocs grouping vectors io.binary
-hashtables symbols math.bitwise checksums checksums.common ;
+hashtables symbols math.bitwise checksums checksums.common
+checksums.stream ;
IN: checksums.sha1
! Implemented according to RFC 3174.
: sha1-f ( B C D t -- f_tbcd )
20 /i
{
- { 0 [ >r over bitnot r> bitand >r bitand r> bitor ] }
+ { 0 [ [ over bitnot ] dip bitand [ bitand ] dip bitor ] }
{ 1 [ bitxor bitxor ] }
- { 2 [ 2dup bitand >r pick bitand >r bitand r> r> bitor bitor ] }
+ { 2 [ 2dup bitand [ pick bitand [ bitand ] dip ] dip bitor bitor ] }
{ 3 [ bitxor bitxor ] }
} case ;
SINGLETON: sha1
-INSTANCE: sha1 checksum
+INSTANCE: sha1 stream-checksum
M: sha1 checksum-stream ( stream -- sha1 )
drop [ initialize-sha1 stream>sha1 get-sha1 ] with-input-stream ;
[ 15 - swap nth s0-256 ] 2keep
[ 7 - swap nth ] 2keep
[ 2 - swap nth s1-256 ] 2keep
- >r >r + + w+ r> r> swap set-nth ; inline
+ [ + + w+ ] 2dip swap set-nth ; inline
: prepare-message-schedule ( seq -- w-seq )
word-size get group [ be> ] map block-size get 0 pad-right
[ bitxor bitand ] keep bitxor ;
: maj ( x y z -- x' )
- >r [ bitand ] 2keep bitor r> bitand bitor ;
+ [ [ bitand ] 2keep bitor ] dip bitand bitor ;
: S0-256 ( x -- x' )
[ -2 bitroll-32 ] keep
[ -11 bitroll-32 ] keep
-25 bitroll-32 bitxor bitxor ; inline
-: slice3 ( n seq -- a b c ) >r dup 3 + r> <slice> first3 ; inline
+: slice3 ( n seq -- a b c ) [ dup 3 + ] dip <slice> first3 ; inline
: T1 ( W n -- T1 )
[ swap nth ] keep
d c pick exchange
c b pick exchange
b a pick exchange
- >r w+ a r> set-nth ;
+ [ w+ a ] dip set-nth ;
: process-chunk ( M -- )
H get clone vars set
: preprocess-plaintext ( string big-endian? -- padded-string )
#! pad 0x80 then 00 til 8 bytes left, then 64bit length in bits
- >r >sbuf r> over [
+ [ >sbuf ] dip over [
HEX: 80 ,
dup length HEX: 3f bitand
calculate-pad-length 0 <string> %
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: io.encodings.binary io.streams.byte-array kernel
+checksums ;
+IN: checksums.stream
+
+MIXIN: stream-checksum
+
+M: stream-checksum checksum-bytes
+ [ binary <byte-reader> ] dip checksum-stream ;
+
+INSTANCE: stream-checksum checksum
USING: debugger quotations help.markup help.syntax strings alien
-core-foundation ;
+core-foundation core-foundation.strings core-foundation.arrays ;
IN: cocoa.application
HELP: <NSString>
-! Copyright (C) 2006, 2007 Slava Pestov
+! Copyright (C) 2006, 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.syntax io kernel namespaces core-foundation
-core-foundation.run-loop cocoa.messages cocoa cocoa.classes
-cocoa.runtime sequences threads debugger init summary
+core-foundation.run-loop core-foundation.arrays
+core-foundation.data core-foundation.strings cocoa.messages
+cocoa cocoa.classes cocoa.runtime sequences threads init summary
kernel.private assocs ;
IN: cocoa.application
: NSApp ( -- app ) NSApplication -> sharedApplication ;
+: NSAnyEventMask ( -- mask ) HEX: ffffffff ; inline
+
FUNCTION: void NSBeep ( ) ;
: with-cocoa ( quot -- )
[ NSApp drop call ] with-autorelease-pool ; inline
: next-event ( app -- event )
- 0 f CFRunLoopDefaultMode 1
+ NSAnyEventMask f CFRunLoopDefaultMode 1
-> nextEventMatchingMask:untilDate:inMode:dequeue: ;
: do-event ( app -- ? )
- dup next-event [ -> sendEvent: t ] [ drop f ] if* ;
+ dup next-event [ dupd -> sendEvent: -> updateWindows t ] [ drop f ] if* ;
: add-observer ( observer selector name object -- )
- >r >r >r >r NSNotificationCenter -> defaultCenter
- r> r> sel_registerName
- r> r> -> addObserver:selector:name:object: ;
+ [
+ [ NSNotificationCenter -> defaultCenter ] 2dip
+ sel_registerName
+ ] 2dip -> addObserver:selector:name:object: ;
: remove-observer ( observer -- )
- >r NSNotificationCenter -> defaultCenter r>
+ [ NSNotificationCenter -> defaultCenter ] dip
-> removeObserver: ;
-: finish-launching ( -- ) NSApp -> finishLaunching ;
-
-: cocoa-app ( quot -- )
- [
- call
- finish-launching
- NSApp -> run
- ] with-cocoa ; inline
+: cocoa-app ( quot -- ) [ call NSApp -> run ] with-cocoa ; inline
: install-delegate ( receiver delegate -- )
-> alloc -> init -> setDelegate: ;
running.app? [
drop
] [
- "The " swap " requires you to run Factor from an application bundle."
- 3append throw
+ "The " " requires you to run Factor from an application bundle."
+ surround throw
] if ;
IN: cocoa.tests
USING: cocoa cocoa.messages cocoa.subclassing cocoa.types
compiler kernel namespaces cocoa.classes tools.test memory
-compiler.units ;
+compiler.units math ;
CLASS: {
{ +superclass+ "NSObject" }
[ 2.0 ] [ "x" get NSRect-y ] unit-test
[ 101.0 ] [ "x" get NSRect-w ] unit-test
[ 102.0 ] [ "x" get NSRect-h ] unit-test
+
+! Make sure that we can add methods
+CLASS: {
+ { +superclass+ "NSObject" }
+ { +name+ "Bar" }
+} {
+ "bar"
+ "NSRect"
+ { "id" "SEL" }
+ [ 2drop test-foo "x" get ]
+} {
+ "babb"
+ "int"
+ { "id" "SEL" "int" }
+ [ 2nip sq ]
+} ;
+
+[ 144 ] [
+ Bar [
+ -> alloc -> init
+ dup 12 -> babb
+ swap -> release
+ ] compile-call
+] unit-test
! See http://factorcode.org/license.txt for BSD license.
USING: compiler io kernel cocoa.runtime cocoa.subclassing
cocoa.messages cocoa.types sequences words vocabs parser
-core-foundation namespaces assocs hashtables compiler.units
-lexer init ;
+core-foundation.bundles namespaces assocs hashtables
+compiler.units lexer init ;
IN: cocoa
: (remember-send) ( selector variable -- )
-! Copyright (C) 2006, 2007 Slava Pestov
+! Copyright (C) 2006, 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: kernel cocoa cocoa.messages cocoa.classes
-cocoa.application sequences splitting core-foundation ;
+cocoa.application sequences splitting core-foundation
+core-foundation.strings ;
IN: cocoa.dialogs
: <NSOpenPanel> ( -- panel )
[ -> filenames CF>string-array ] [ drop f ] if ;
: split-path ( path -- dir file )
- "/" last-split1 [ <NSString> ] bi@ ;
+ "/" split1-last [ <NSString> ] bi@ ;
: save-panel ( path -- paths )
- <NSSavePanel> dup
- rot split-path -> runModalForDirectory:file: NSOKButton =
+ [ <NSSavePanel> dup ] dip
+ split-path -> runModalForDirectory:file: NSOKButton =
[ -> filename CF>string ] [ drop f ] if ;
-USING: kernel cocoa cocoa.types alien.c-types locals math sequences
-vectors fry libc ;
+! Copyright (C) 2008 Joe Groff.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel cocoa cocoa.types alien.c-types locals math
+sequences vectors fry libc destructors
+specialized-arrays.direct.alien ;
IN: cocoa.enumeration
: NS-EACH-BUFFER-SIZE 16 ; inline
-: (with-enumeration-buffers) ( quot -- )
- "NSFastEnumerationState" heap-size swap '[
- NS-EACH-BUFFER-SIZE "id" heap-size * [
- NS-EACH-BUFFER-SIZE @
- ] with-malloc
- ] with-malloc ; inline
+: with-enumeration-buffers ( quot -- )
+ [
+ [
+ "NSFastEnumerationState" malloc-object &free
+ NS-EACH-BUFFER-SIZE "id" heap-size * malloc-object &free
+ NS-EACH-BUFFER-SIZE
+ ] dip call
+ ] with-destructors ; inline
:: (NSFastEnumeration-each) ( object quot: ( elt -- ) state stackbuf count -- )
object state stackbuf count -> countByEnumeratingWithState:objects:count:
- dup zero? [ drop ] [
+ dup 0 = [ drop ] [
state NSFastEnumerationState-itemsPtr [ stackbuf ] unless*
- '[ _ void*-nth quot call ] each
+ swap <direct-void*-array> quot each
object quot state stackbuf count (NSFastEnumeration-each)
] if ; inline recursive
: NSFastEnumeration-each ( object quot -- )
- [ (NSFastEnumeration-each) ] (with-enumeration-buffers) ; inline
+ [ (NSFastEnumeration-each) ] with-enumeration-buffers ; inline
: NSFastEnumeration-map ( object quot -- vector )
NS-EACH-BUFFER-SIZE <vector>
! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors alien alien.c-types alien.strings arrays assocs
-combinators compiler compiler.alien kernel math namespaces make
-parser prettyprint prettyprint.sections quotations sequences
-strings words cocoa.runtime io macros memoize debugger
-io.encodings.ascii effects libc libc.private parser lexer init
-core-foundation fry ;
+continuations combinators compiler compiler.alien kernel math
+namespaces make parser quotations sequences strings words
+cocoa.runtime io macros memoize io.encodings.utf8
+effects libc libc.private parser lexer init core-foundation fry
+generalizations specialized-arrays.direct.alien ;
IN: cocoa.messages
: make-sender ( method function -- quot )
[ over first , f , , second , \ alien-invoke , ] [ ] make ;
-: sender-stub-name ( method function -- string )
- [ % "_" % unparse % ] "" make ;
-
: sender-stub ( method function -- word )
- [ sender-stub-name f <word> dup ] 2keep
+ [ "( sender-stub )" f <word> dup ] 2dip
over first large-struct? [ "_stret" append ] when
make-sender define ;
: cache-stub ( method function hash -- )
[
- over get [ 2drop ] [ over >r sender-stub r> set ] if
+ over get [ 2drop ] [ over [ sender-stub ] dip set ] if
] bind ;
: cache-stubs ( method -- )
: <super> ( receiver -- super )
"objc-super" <c-object> [
- >r dup object_getClass class_getSuperclass r>
+ [ dup object_getClass class_getSuperclass ] dip
set-objc-super-class
] keep
[ set-objc-super-receiver ] keep ;
dup objc-methods get at
[ ] [ "No such method: " prepend throw ] ?if ;
-: make-dip ( quot n -- quot' )
- dup
- \ >r <repetition> >quotation -rot
- \ r> <repetition> >quotation 3append ;
-
MEMO: make-prepare-send ( selector method super? -- quot )
[
[ \ <super> , ] when
swap <selector> , \ selector ,
] [ ] make
- swap second length 2 - make-dip ;
+ swap second length 2 - '[ _ _ ndip ] ;
MACRO: (send) ( selector super? -- quot )
- >r dup lookup-method r>
+ [ dup lookup-method ] dip
[ make-prepare-send ] 2keep
super-message-senders message-senders ? get at
- [ slip execute ] 2curry ;
+ '[ _ call _ execute ] ;
: send ( receiver args... selector -- return... ) f (send) ; inline
-\ send soft "break-after" set-word-prop
-
: super-send ( receiver args... selector -- return... ) t (send) ; inline
-\ super-send soft "break-after" set-word-prop
-
! Runtime introspection
-: (objc-class) ( string word -- class )
- dupd execute
- [ ] [ "No such class: " prepend throw ] ?if ; inline
+SYMBOL: class-init-hooks
+
+class-init-hooks global [ H{ } clone or ] change-at
+
+: (objc-class) ( name word -- class )
+ 2dup execute dup [ 2nip ] [
+ drop over class-init-hooks get at [ assert-depth ] when*
+ 2dup execute dup [ 2nip ] [
+ 2drop "No such class: " prepend throw
+ ] if
+ ] if ; inline
: objc-class ( string -- class )
\ objc_getClass (objc-class) ;
assoc-union alien>objc-types set-global
: objc-struct-type ( i string -- ctype )
- 2dup CHAR: = -rot index-from swap subseq
+ [ CHAR: = ] 2keep index-from swap subseq
dup c-types get key? [
"Warning: no such C type: " write dup print
drop "void*"
] unless ;
: (parse-objc-type) ( i string -- ctype )
- 2dup nth >r >r 1+ r> r> {
+ [ [ 1+ ] dip ] [ nth ] 2bi {
{ [ dup "rnNoORV" member? ] [ drop (parse-objc-type) ] }
{ [ dup CHAR: ^ = ] [ 3drop "void*" ] }
{ [ dup CHAR: { = ] [ drop objc-struct-type ] }
: method-arg-type ( method i -- type )
method_copyArgumentType
- [ ascii alien>string parse-objc-type ] keep
+ [ utf8 alien>string parse-objc-type ] keep
(free) ;
: method-arg-types ( method -- args )
: method-return-type ( method -- ctype )
method_copyReturnType
- [ ascii alien>string parse-objc-type ] keep
+ [ utf8 alien>string parse-objc-type ] keep
(free) ;
: register-objc-method ( method -- )
objc-methods get set-at ;
: each-method-in-class ( class quot -- )
- [ 0 <uint> [ class_copyMethodList ] keep *uint over ] dip
- '[ _ void*-nth @ ] each (free) ; inline
+ [ 0 <uint> [ class_copyMethodList ] keep *uint ] dip
+ over 0 = [ 3drop ] [
+ [ <direct-void*-array> ] dip
+ [ each ] [ drop underlying>> (free) ] 2bi
+ ] if ; inline
: register-objc-methods ( class -- )
[ register-objc-method ] each-method-in-class ;
-: method. ( method -- )
- {
- [ method_getName sel_getName ]
- [ method-return-type ]
- [ method-arg-types ]
- [ method_getImplementation ]
- } cleave 4array . ;
-
-: methods. ( class -- )
- [ method. ] each-method-in-class ;
-
: class-exists? ( string -- class ) objc_getClass >boolean ;
-: unless-defined ( class quot -- )
- >r class-exists? r> unless ; inline
-
-: define-objc-class-word ( name quot -- )
+: define-objc-class-word ( quot name -- )
+ [ class-init-hooks get set-at ]
[
- over , , \ unless-defined , dup , \ objc-class ,
- ] [ ] make >r "cocoa.classes" create r>
- (( -- class )) define-declared ;
+ [ "cocoa.classes" create ] [ '[ _ objc-class ] ] bi
+ (( -- class )) define-declared
+ ] bi ;
: import-objc-class ( name quot -- )
- 2dup unless-defined
- dupd define-objc-class-word
- [
- dup
- objc-class register-objc-methods
- objc-meta-class register-objc-methods
- ] curry try ;
+ over define-objc-class-word
+ [ objc-class register-objc-methods ]
+ [ objc-meta-class register-objc-methods ] bi ;
: root-class ( class -- root )
dup class_getSuperclass [ root-class ] [ ] ?if ;
-USING: cocoa.application cocoa.messages cocoa.classes cocoa.runtime
-kernel cocoa core-foundation alien.c-types ;
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: cocoa.application cocoa.messages cocoa.classes
+cocoa.runtime kernel cocoa alien.c-types core-foundation
+core-foundation.arrays ;
IN: cocoa.nibs
: load-nib ( name -- )
-! Copyright (C) 2006, 2007 Slava Pestov.
+! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.c-types arrays kernel cocoa.messages
-cocoa.classes cocoa.application cocoa core-foundation
-sequences ;
+USING: alien.accessors arrays kernel cocoa.messages
+cocoa.classes cocoa.application sequences cocoa core-foundation
+core-foundation.strings core-foundation.arrays ;
IN: cocoa.pasteboard
: NSStringPboardType "NSStringPboardType" ;
: set-pasteboard-string ( str pasteboard -- )
NSStringPboardType <NSString>
dup 1array pick set-pasteboard-types
- >r swap <NSString> r> -> setString:forType: drop ;
+ [ swap <NSString> ] dip -> setString:forType: drop ;
: pasteboard-error ( error -- f )
"Pasteboard does not hold a string" <NSString>
- 0 spin set-void*-nth f ;
+ 0 set-alien-cell f ;
: ?pasteboard-string ( pboard error -- str/f )
over pasteboard-string? [
USING: strings arrays hashtables assocs sequences
cocoa.messages cocoa.classes cocoa.application cocoa kernel
namespaces io.backend math cocoa.enumeration byte-arrays
-combinators alien.c-types core-foundation ;
+combinators alien.c-types core-foundation core-foundation.data ;
IN: cocoa.plists
GENERIC: >plist ( value -- plist )
-! Copyright (C) 2006, 2008 Slava Pestov
+! Copyright (C) 2006, 2008 Slava Pestov, Joe Groff.
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types alien.strings arrays assocs
combinators compiler hashtables kernel libc math namespaces
-parser sequences words cocoa.messages cocoa.runtime
-compiler.units io.encodings.ascii generalizations
-continuations make ;
+parser sequences words cocoa.messages cocoa.runtime locals
+compiler.units io.encodings.utf8 continuations make fry ;
IN: cocoa.subclassing
: init-method ( method -- sel imp types )
first3 swap
- [ sel_registerName ] [ execute ] [ ascii string>alien ]
+ [ sel_registerName ] [ execute ] [ utf8 string>alien ]
tri* ;
-: throw-if-false ( YES/NO -- )
- zero? [ "Failed to add method or protocol to class" throw ]
- when ;
+: throw-if-false ( obj what -- )
+ swap { f 0 } member?
+ [ "Failed to " prepend throw ] [ drop ] if ;
+
+: add-method ( class sel imp types -- )
+ class_addMethod "add method to class" throw-if-false ;
: add-methods ( methods class -- )
- swap
- [ init-method class_addMethod throw-if-false ] with each ;
+ '[ [ _ ] dip init-method add-method ] each ;
+
+: add-protocol ( class protocol -- )
+ class_addProtocol "add protocol to class" throw-if-false ;
: add-protocols ( protocols class -- )
- swap [ objc-protocol class_addProtocol throw-if-false ]
- with each ;
+ '[ [ _ ] dip objc-protocol add-protocol ] each ;
-: (define-objc-class) ( protocols superclass name imeth -- )
- -rot
+: (define-objc-class) ( imeth protocols superclass name -- )
[ objc-class ] dip 0 objc_allocateClassPair
- [ add-methods ] [ add-protocols ] [ objc_registerClassPair ]
+ [ add-protocols ] [ add-methods ] [ objc_registerClassPair ]
tri ;
: encode-types ( return types -- encoding )
] map concat ;
: prepare-method ( ret types quot -- type imp )
- >r [ encode-types ] 2keep r> [
+ [ [ encode-types ] 2keep ] dip [
"cdecl" swap 4array % \ alien-callback ,
] [ ] make define-temp ;
[ first4 prepare-method 3array ] map
] with-compilation-unit ;
-: types= ( a b -- ? )
- [ ascii alien>string ] bi@ = ;
-
-: (verify-method-type) ( class sel types -- )
- [ class_getInstanceMethod method_getTypeEncoding ]
- dip types=
- [ "Objective-C method types cannot be changed once defined" throw ]
- unless ;
-: verify-method-type ( class sel imp types -- class sel imp types )
- 4 ndup nip (verify-method-type) ;
-
-: (redefine-objc-method) ( class method -- )
- init-method ! verify-method-type
- drop
- [ class_getInstanceMethod ] dip method_setImplementation drop ;
+:: (redefine-objc-method) ( class method -- )
+ method init-method [| sel imp types |
+ class sel class_getInstanceMethod [
+ imp method_setImplementation drop
+ ] [
+ class sel imp types add-method
+ ] if*
+ ] call ;
: redefine-objc-methods ( imeth name -- )
dup class-exists? [
- objc_getClass swap [ (redefine-objc-method) ] with each
- ] [
- 2drop
- ] if ;
+ objc_getClass '[ [ _ ] dip (redefine-objc-method) ] each
+ ] [ 2drop ] if ;
SYMBOL: +name+
SYMBOL: +protocols+
clone [
prepare-methods
+name+ get "cocoa.classes" create drop
- +name+ get 2dup redefine-objc-methods swap [
- +protocols+ get , +superclass+ get , +name+ get , ,
- \ (define-objc-class) ,
- ] [ ] make import-objc-class
+ +name+ get 2dup redefine-objc-methods swap
+ +protocols+ get +superclass+ get +name+ get
+ '[ _ _ _ _ (define-objc-class) ]
+ import-objc-class
] bind ;
: CLASS:
-! Copyright (C) 2006, 2007 Slava Pestov
+! Copyright (C) 2006, 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.c-types arrays kernel math namespaces make cocoa
-cocoa.messages cocoa.classes cocoa.types sequences
-continuations ;
+USING: specialized-arrays.int arrays kernel math namespaces make
+cocoa cocoa.messages cocoa.classes cocoa.types sequences
+continuations accessors ;
IN: cocoa.views
: NSOpenGLPFAAllRenderers 1 ;
: with-multisample ( quot -- )
t +multisample+ pick with-variable ; inline
-: <PixelFormat> ( -- pixelfmt )
- NSOpenGLPixelFormat -> alloc [
- NSOpenGLPFAWindow ,
- NSOpenGLPFADoubleBuffer ,
+: <PixelFormat> ( attributes -- pixelfmt )
+ NSOpenGLPixelFormat -> alloc swap [
+ %
NSOpenGLPFADepthSize , 16 ,
+software-renderer+ get [
NSOpenGLPFARendererID , kCGLRendererGenericFloatID ,
NSOpenGLPFASamples , 8 ,
] when
0 ,
- ] { } make >c-int-array
+ ] int-array{ } make underlying>>
-> initWithAttributes:
-> autorelease ;
: <GLView> ( class dim -- view )
- >r -> alloc 0 0 r> first2 <NSRect> <PixelFormat>
+ [ -> alloc 0 0 ] dip first2 <NSRect>
+ NSOpenGLPFAWindow NSOpenGLPFADoubleBuffer 2array <PixelFormat>
-> initWithFrame:pixelFormat:
dup 1 -> setPostsBoundsChangedNotifications:
dup 1 -> setPostsFrameChangedNotifications: ;
swap NSRect-h >fixnum 2array ;
: mouse-location ( view event -- loc )
- over >r
- -> locationInWindow f -> convertPoint:fromView:
- dup NSPoint-x swap NSPoint-y
- r> -> frame NSRect-h swap - 2array ;
+ [
+ -> locationInWindow f -> convertPoint:fromView:
+ [ NSPoint-x ] [ NSPoint-y ] bi
+ ] [ drop -> frame NSRect-h ] 2bi
+ swap - 2array ;
USE: opengl.gl
USE: alien.syntax
dup 0 -> setReleasedWhenClosed: ;
: window-content-rect ( window -- rect )
- NSWindow over -> frame rot -> styleMask
+ [ NSWindow ] dip
+ [ -> frame ] [ -> styleMask ] bi
-> contentRectForFrameRect:styleMask: ;
{ "quot" quotation } }
{ $description "Returns true if any quotation in the sequence returns true. Each quotation takes the same three elements from the datastack and must return a boolean." } ;
-HELP: n&&-rewrite
+HELP: n&&
{ $values
{ "quots" "a sequence of quotations" } { "N" integer }
{ "quot" quotation } }
-{ $description "A macro that reqrites the code to pass " { $snippet "N" } " parameters from the stack to each AND quotation." } ;
+{ $description "A macro that rewrites the code to pass " { $snippet "n" } " parameters from the stack to each AND quotation." } ;
-HELP: n||-rewrite
+HELP: n||
{ $values
- { "quots" "a sequence of quotations" } { "N" integer }
+ { "quots" "a sequence of quotations" } { "n" integer }
{ "quot" quotation } }
-{ $description "A macro that reqrites the code to pass " { $snippet "N" } " parameters from the stack to each OR quotation." } ;
+{ $description "A macro that rewrites the code to pass " { $snippet "n" } " parameters from the stack to each OR quotation." } ;
ARTICLE: "combinators.short-circuit" "Short-circuit combinators"
"The " { $vocab-link "combinators.short-circuit" } " vocabulary stops a computation early once a condition is met." $nl
{ $subsection 2|| }
{ $subsection 3|| }
"Generalized combinators:"
-{ $subsection n&&-rewrite }
-{ $subsection n||-rewrite }
+{ $subsection n&& }
+{ $subsection n|| }
;
ABOUT: "combinators.short-circuit"
-
USING: kernel combinators quotations arrays sequences assocs
- locals generalizations macros fry ;
-
+locals generalizations macros fry ;
IN: combinators.short-circuit
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-:: n&&-rewrite ( quots N -- quot )
- quots
- [ '[ drop N ndup @ dup not ] [ drop N ndrop f ] 2array ]
- map
- [ t ] [ N nnip ] 2array suffix
- '[ f _ cond ] ;
-
-MACRO: 0&& ( quots -- quot ) 0 n&&-rewrite ;
-MACRO: 1&& ( quots -- quot ) 1 n&&-rewrite ;
-MACRO: 2&& ( quots -- quot ) 2 n&&-rewrite ;
-MACRO: 3&& ( quots -- quot ) 3 n&&-rewrite ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-:: n||-rewrite ( quots N -- quot )
- quots
- [ '[ drop N ndup @ dup ] [ N nnip ] 2array ]
- map
- [ drop N ndrop t ] [ f ] 2array suffix
- '[ f _ cond ] ;
-
-MACRO: 0|| ( quots -- quot ) 0 n||-rewrite ;
-MACRO: 1|| ( quots -- quot ) 1 n||-rewrite ;
-MACRO: 2|| ( quots -- quot ) 2 n||-rewrite ;
-MACRO: 3|| ( quots -- quot ) 3 n||-rewrite ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+MACRO:: n&& ( quots n -- quot )
+ [ f ] quots [| q |
+ n
+ [ q '[ drop _ ndup @ dup not ] ]
+ [ '[ drop _ ndrop f ] ]
+ bi 2array
+ ] map
+ n '[ _ nnip ] suffix 1array
+ [ cond ] 3append ;
+
+MACRO: 0&& ( quots -- quot ) '[ _ 0 n&& ] ;
+MACRO: 1&& ( quots -- quot ) '[ _ 1 n&& ] ;
+MACRO: 2&& ( quots -- quot ) '[ _ 2 n&& ] ;
+MACRO: 3&& ( quots -- quot ) '[ _ 3 n&& ] ;
+
+MACRO:: n|| ( quots n -- quot )
+ [ f ] quots [| q |
+ n
+ [ q '[ drop _ ndup @ dup ] ]
+ [ '[ _ nnip ] ]
+ bi 2array
+ ] map
+ n '[ drop _ ndrop t ] [ f ] 2array suffix 1array
+ [ cond ] 3append ;
+
+MACRO: 0|| ( quots -- quot ) '[ _ 0 n|| ] ;
+MACRO: 1|| ( quots -- quot ) '[ _ 1 n|| ] ;
+MACRO: 2|| ( quots -- quot ) '[ _ 2 n|| ] ;
+MACRO: 3|| ( quots -- quot ) '[ _ 3 n|| ] ;
-
USING: kernel sequences math stack-checker effects accessors macros
- combinators.short-circuit ;
-
+fry combinators.short-circuit ;
IN: combinators.short-circuit.smart
<PRIVATE
PRIVATE>
-MACRO: && ( quots -- quot ) dup arity n&&-rewrite ;
+MACRO: && ( quots -- quot ) dup arity '[ _ _ n&& ] ;
-MACRO: || ( quots -- quot ) dup arity n||-rewrite ;
+MACRO: || ( quots -- quot ) dup arity '[ _ _ n|| ] ;
-USING: help.markup help.syntax parser vocabs.loader strings ;
+USING: help.markup help.syntax parser vocabs.loader strings
+command-line.private ;
IN: command-line
HELP: run-bootstrap-init
HELP: run-user-init
{ $description "Runs the startup initialization file in the user's home directory, unless the " { $snippet "-no-user-init" } " command line switch was given. This file is named " { $snippet ".factor-rc" } " on Unix and " { $snippet "factor-rc" } " on Windows." } ;
-HELP: cli-param
+HELP: load-vocab-roots
+{ $description "Loads the newline-separated list of additional vocabulary roots from the file named " { $snippet ".factor-roots" } " on Unix and " { $snippet "factor-roots" } " on Windows." } ;
+
+HELP: param
{ $values { "param" string } }
{ $description "Process a command-line switch."
$nl
$nl
"Otherwise, sets the global variable named by the parameter to " { $link t } "." } ;
-HELP: cli-args
+HELP: (command-line)
{ $values { "args" "a sequence of strings" } }
{ $description "Outputs the command line parameters which were passed to the Factor VM on startup." } ;
+HELP: command-line
+{ $var-description "The command line parameters which follow the name of the script on the command line." } ;
+
HELP: main-vocab-hook
{ $var-description "Global variable holding a quotation which outputs a vocabulary name. UI backends set this so that the UI can automatically start if the prerequisites are met (for example, " { $snippet "$DISPLAY" } " being set on X11)." } ;
{ $values { "?" "a boolean" } }
{ $description "On Mac OS X, source files to run are supplied by the Cocoa API, so to avoid running them twice the startup code has to call this word." } ;
-HELP: parse-command-line
-{ $description "Called on startup to process command line arguments. This sets global variables with " { $link cli-param } ", runs source files, and evaluates the string given by the " { $snippet "-e" } " switch, if there is one." } ;
-
ARTICLE: "runtime-cli-args" "Command line switches for the VM"
"A handful of command line switches are processed by the VM and not the library. They control low-level features."
{ $table
}
"Bootstrap can load various optional components:"
{ $table
+ { { $snippet "math" } "Rational and complex number support." }
+ { { $snippet "threads" } "Thread support." }
{ { $snippet "compiler" } "The compiler." }
{ { $snippet "tools" } "Terminal-based developer tools." }
{ { $snippet "help" } "The help system." }
+ { { $snippet "help.handbook" } "The help handbook." }
{ { $snippet "ui" } "The graphical user interface." }
{ { $snippet "ui.tools" } "Graphical developer tools." }
{ { $snippet "io" } "Non-blocking I/O and networking." }
{ { $snippet "-run=" { $emphasis "vocab" } } { { $snippet { $emphasis "vocab" } } " is the name of a vocabulary with a " { $link POSTPONE: MAIN: } " hook to run on startup, for example " { $vocab-link "listener" } ", " { $vocab-link "ui" } " or " { $vocab-link "none" } "." } }
{ { $snippet "-no-user-init" } { "Inhibits the running of user initialization files on startup. See " { $link "rc-files" } "." } }
{ { $snippet "-quiet" } { "If set, " { $link run-file } " and " { $link require } " will not print load messages." } }
- { { $snippet "-script" } { "Equivalent to " { $snippet "-quiet -run=none" } "." $nl "On Unix systems, Factor can be used for scripting - just create an executable text file whose first line is:" { $code "#! /usr/local/bin/factor -script" } "The space after " { $snippet "#!" } " is necessary because of Factor syntax." } }
} ;
ARTICLE: "factor-boot-rc" "Bootstrap initialization file"
"A word to run this file from an existing Factor session:"
{ $subsection run-user-init } ;
+ARTICLE: "factor-roots" "Additional vocabulary roots file"
+"The vocabulary roots file is named " { $snippet "factor-roots" } " on Windows and " { $snippet ".factor-roots" } " on Unix. If it exists, it is loaded every time Factor starts. It contains a newline-separated list of " { $link "vocabs.roots" } "."
+$nl
+"A word to run this file from an existing Factor session:"
+{ $subsection load-vocab-roots } ;
+
ARTICLE: "rc-files" "Running code on startup"
-"Factor looks for two files in your home directory."
+"Factor looks for three optional files in your home directory."
{ $subsection "factor-boot-rc" }
{ $subsection "factor-rc" }
-"The " { $snippet "-no-user-init" } " command line switch will inhibit the running of these files."
+{ $subsection "factor-roots" }
+"The " { $snippet "-no-user-init" } " command line switch will inhibit loading running of these files."
$nl
"If you are unsure where the files should be located, evaluate the following code:"
{ $code
"100 dpi set-global"
} ;
-ARTICLE: "cli" "Command line usage"
-"Zero or more command line arguments may be passed to the Factor runtime. Command line arguments starting with a dash (" { $snippet "-" } ") is interpreted as switches. All other arguments are taken to be file names to be run by " { $link run-file } "."
+ARTICLE: "cli" "Command line arguments"
+"Factor command line usage:"
+{ $code "factor [system switches...] [script args...]" }
+"Zero or more system switches can be passed in, followed by an optional script file name. If the script file is specified, it will be run on startup, any arguments after the script file are stored in a variable, with no further processing by Factor itself:"
+{ $subsection command-line }
+"Instead of running a script, it is also possible to run a vocabulary; this invokes the vocabulary's " { $link POSTPONE: MAIN: } " word:"
+{ $code "factor [system switches...] -run=<vocab name>" }
+"If no script file or " { $snippet "-run=" } " switch is specified, Factor will start " { $link "listener" } " or " { $link "ui-tools" } ", depending on the operating system."
+$nl
+"As stated above, arguments in the first part of the command line, before the optional script name, are interpreted by to the Factor system. These arguments all start with a dash (" { $snippet "-" } ")."
$nl
"Switches can take one of the following three forms:"
{ $list
{ $subsection "runtime-cli-args" }
{ $subsection "bootstrap-cli-args" }
{ $subsection "standard-cli-args" }
-"The list of command line arguments can be obtained and inspected directly:"
-{ $subsection cli-args }
-"There is a way to override the default vocabulary to run on startup:"
+"The raw list of command line arguments can also be obtained and inspected directly:"
+{ $subsection (command-line) }
+"There is a way to override the default vocabulary to run on startup, if no script name or " { $snippet "-run" } " switch is specified:"
{ $subsection main-vocab-hook } ;
ABOUT: "cli"
+++ /dev/null
-USING: namespaces tools.test kernel command-line ;
-IN: command-line.tests
-
-[
- [ f ] [ "-no-user-init" cli-arg ] unit-test
- [ f ] [ "user-init" get ] unit-test
-
- [ f ] [ "-user-init" cli-arg ] unit-test
- [ t ] [ "user-init" get ] unit-test
-
- [ "sdl.factor" ] [ "sdl.factor" cli-arg ] unit-test
-] with-scope
! Copyright (C) 2003, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: init continuations debugger hashtables io kernel
-kernel.private namespaces parser sequences strings system
-splitting io.files eval ;
+USING: init continuations hashtables io io.encodings.utf8
+io.files kernel kernel.private namespaces parser sequences
+strings system splitting vocabs.loader ;
IN: command-line
+SYMBOL: script
+SYMBOL: command-line
+
+: (command-line) ( -- args ) 10 getenv sift ;
+
: rc-path ( name -- path )
os windows? [ "." prepend ] unless
home prepend-path ;
"factor-rc" rc-path ?run-file
] when ;
-: cli-var-param ( name value -- ) swap set-global ;
+: load-vocab-roots ( -- )
+ "user-init" get [
+ "factor-roots" rc-path dup exists? [
+ utf8 file-lines [ add-vocab-root ] each
+ ] [ drop ] if
+ ] when ;
+
+: var-param ( name value -- ) swap set-global ;
-: cli-bool-param ( name -- ) "no-" ?head not cli-var-param ;
+: bool-param ( name -- ) "no-" ?head not var-param ;
-: cli-param ( param -- )
- "=" split1 [ cli-var-param ] [ cli-bool-param ] if* ;
+: param ( param -- )
+ "=" split1 [ var-param ] [ bool-param ] if* ;
-: cli-arg ( argument -- argument )
- "-" ?head [ cli-param f ] when ;
+: run-script ( file -- )
+ t "quiet" set-global run-file ;
-: cli-args ( -- args ) 10 getenv ;
+: parse-command-line ( args -- )
+ [ command-line off script off ] [
+ unclip "-" ?head
+ [ param parse-command-line ]
+ [ script set command-line set ] if
+ ] if-empty ;
SYMBOL: main-vocab-hook
: ignore-cli-args? ( -- ? )
os macosx? "run" get "ui" = and ;
-: script-mode ( -- )
- t "quiet" set-global
- "none" "run" set-global ;
-
-: parse-command-line ( -- )
- cli-args [ cli-arg ] filter
- "script" get [ script-mode ] when
- ignore-cli-args? [ drop ] [ [ run-file ] each ] if
- "e" get [ eval ] when* ;
+: script-mode ( -- ) ;
[ default-cli-args ] "command-line" add-init-hook
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> - ;
+ [ c-type-stack-align align dup ] [ drop ] 2bi - ;
: parameter-sizes ( types -- total offsets )
#! Compute stack frame locations.
USING: compiler.cfg.instructions compiler.cfg.registers
-compiler.cfg.alias-analysis cpu.architecture tools.test
-kernel ;
+compiler.cfg.alias-analysis compiler.cfg.debugger
+cpu.architecture tools.test kernel ;
IN: compiler.cfg.alias-analysis.tests
[ ] [
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel math namespaces assocs hashtables sequences
+USING: kernel math namespaces assocs hashtables sequences arrays
accessors vectors combinators sets classes compiler.cfg
compiler.cfg.registers compiler.cfg.instructions
compiler.cfg.copy-prop ;
M: ##slot-imm insn-slot# slot>> ;
M: ##set-slot insn-slot# slot>> constant ;
M: ##set-slot-imm insn-slot# slot>> ;
+M: ##alien-global insn-slot# [ library>> ] [ symbol>> ] bi 2array ;
M: ##peek insn-object loc>> class ;
M: ##replace insn-object loc>> class ;
M: ##slot-imm insn-object obj>> resolve ;
M: ##set-slot insn-object obj>> resolve ;
M: ##set-slot-imm insn-object obj>> resolve ;
+M: ##alien-global insn-object drop \ ##alien-global ;
: init-alias-analysis ( -- )
H{ } clone histories set
M: ##load-indirect analyze-aliases*
dup dst>> set-heap-ac ;
+M: ##alien-global analyze-aliases*
+ dup dst>> set-heap-ac ;
+
M: ##allot analyze-aliases*
#! A freshly allocated object is distinct from any other
#! object.
! Convert tree SSA IR to CFG SSA IR.
-: stop-iterating ( -- next ) end-basic-block f ;
-
SYMBOL: procedures
SYMBOL: current-word
SYMBOL: current-label
! #call
M: #call emit-node
dup word>> dup "intrinsic" word-prop
- [ emit-intrinsic iterate-next ] [ nip emit-call ] if ;
+ [ emit-intrinsic ] [ nip emit-call ] if ;
! #call-recursive
M: #call-recursive emit-node label>> id>> emit-call ;
: emit-alien-node ( node quot -- next )
[ params>> ] dip [ drop alien-stack-frame ] [ call ] 2bi
- begin-basic-block iterate-next ; inline
+ ##branch begin-basic-block iterate-next ; inline
M: #alien-invoke emit-node
[ ##alien-invoke ] emit-alien-node ;
USING: compiler.cfg.dead-code compiler.cfg.instructions
-compiler.cfg.registers cpu.architecture tools.test ;
+compiler.cfg.registers compiler.cfg.debugger
+cpu.architecture tools.test ;
IN: compiler.cfg.dead-code.tests
[ { } ] [
! See http://factorcode.org/license.txt for BSD license.
USING: kernel words sequences quotations namespaces io
classes.tuple accessors prettyprint prettyprint.config
-compiler.tree.builder compiler.tree.optimizer
+prettyprint.backend prettyprint.custom prettyprint.sections
+parser compiler.tree.builder compiler.tree.optimizer
compiler.cfg.builder compiler.cfg.linearization
-compiler.cfg.stack-frame compiler.cfg.linear-scan
-compiler.cfg.two-operand compiler.cfg.optimizer ;
+compiler.cfg.registers compiler.cfg.stack-frame
+compiler.cfg.linear-scan compiler.cfg.two-operand
+compiler.cfg.optimizer ;
IN: compiler.cfg.debugger
GENERIC: test-cfg ( quot -- cfgs )
instructions>> [ insn. ] each
nl
] each ;
+
+! Prettyprinting
+M: vreg pprint*
+ <block
+ \ V pprint-word [ reg-class>> pprint* ] [ n>> pprint* ] bi
+ block> ;
+
+: pprint-loc ( loc word -- ) <block pprint-word n>> pprint* block> ;
+
+M: ds-loc pprint* \ D pprint-loc ;
+
+M: rs-loc pprint* \ R pprint-loc ;
M: ##unary/temp defs-vregs dst/tmp-vregs ;
M: ##allot defs-vregs dst/tmp-vregs ;
M: ##dispatch defs-vregs temp>> 1array ;
-M: ##slot defs-vregs [ dst>> ] [ temp>> ] bi 2array ;
+M: ##slot defs-vregs dst/tmp-vregs ;
M: ##set-slot defs-vregs temp>> 1array ;
-M: ##string-nth defs-vregs [ dst>> ] [ temp>> ] bi 2array ;
+M: ##string-nth defs-vregs dst/tmp-vregs ;
+M: ##set-string-nth-fast defs-vregs temp>> 1array ;
+M: ##compare defs-vregs dst/tmp-vregs ;
+M: ##compare-imm defs-vregs dst/tmp-vregs ;
+M: ##compare-float defs-vregs dst/tmp-vregs ;
+M: ##fixnum-mul defs-vregs [ temp1>> ] [ temp2>> ] bi 2array ;
+M: ##fixnum-mul-tail defs-vregs [ temp1>> ] [ temp2>> ] bi 2array ;
M: insn defs-vregs drop f ;
M: ##unary uses-vregs src>> 1array ;
M: ##set-slot uses-vregs [ src>> ] [ obj>> ] [ slot>> ] tri 3array ;
M: ##set-slot-imm uses-vregs [ src>> ] [ obj>> ] bi 2array ;
M: ##string-nth uses-vregs [ obj>> ] [ index>> ] bi 2array ;
+M: ##set-string-nth-fast uses-vregs [ src>> ] [ obj>> ] [ index>> ] tri 3array ;
M: ##conditional-branch uses-vregs [ src1>> ] [ src2>> ] bi 2array ;
M: ##compare-imm-branch uses-vregs src1>> 1array ;
M: ##dispatch uses-vregs src>> 1array ;
M: ##alien-getter uses-vregs src>> 1array ;
M: ##alien-setter uses-vregs [ src>> ] [ value>> ] bi 2array ;
+M: ##fixnum-overflow uses-vregs [ src1>> ] [ src2>> ] bi 2array ;
M: _conditional-branch uses-vregs [ src1>> ] [ src2>> ] bi 2array ;
M: _compare-imm-branch uses-vregs src1>> 1array ;
M: insn uses-vregs drop f ;
##write-barrier
##dispatch
##effect
+##fixnum-overflow
##conditional-branch
##compare-imm-branch
_conditional-branch
: ^^shr-imm ( src1 src2 -- dst ) ^^i2 ##shr-imm ; inline
: ^^sar-imm ( src1 src2 -- dst ) ^^i2 ##sar-imm ; inline
: ^^not ( src -- dst ) ^^i1 ##not ; inline
+: ^^log2 ( src -- dst ) ^^i1 ##log2 ; inline
: ^^bignum>integer ( src -- dst ) ^^i1 i ##bignum>integer ; inline
: ^^integer>bignum ( src -- dst ) ^^i1 i ##integer>bignum ; inline
: ^^add-float ( src1 src2 -- dst ) ^^d2 ##add-float ; inline
: ^^alien-cell ( src -- dst ) ^^i1 ##alien-cell ; inline
: ^^alien-float ( src -- dst ) ^^d1 ##alien-float ; inline
: ^^alien-double ( src -- dst ) ^^d1 ##alien-double ; inline
-: ^^compare ( src1 src2 cc -- dst ) ^^i3 ##compare ; inline
-: ^^compare-imm ( src1 src2 cc -- dst ) ^^i3 ##compare-imm ; inline
-: ^^compare-float ( src1 src2 cc -- dst ) ^^i3 ##compare-float ; inline
+: ^^alien-global ( symbol library -- dst ) ^^i2 ##alien-global ; inline
+: ^^compare ( src1 src2 cc -- dst ) ^^i3 i ##compare ; inline
+: ^^compare-imm ( src1 src2 cc -- dst ) ^^i3 i ##compare-imm ; inline
+: ^^compare-float ( src1 src2 cc -- dst ) ^^i3 i ##compare-float ; inline
: ^^offset>slot ( vreg -- vreg' ) cell 4 = [ 1 ^^shr-imm ] when ; inline
: ^^tag-fixnum ( src -- dst ) ^^i1 ##tag-fixnum ; inline
: ^^untag-fixnum ( src -- dst ) ^^i1 ##untag-fixnum ; inline
! String element access
INSN: ##string-nth < ##flushable { obj vreg } { index vreg } { temp vreg } ;
+INSN: ##set-string-nth-fast < ##effect { obj vreg } { index vreg } { temp vreg } ;
! Integer arithmetic
INSN: ##add < ##commutative ;
INSN: ##shr-imm < ##binary-imm ;
INSN: ##sar-imm < ##binary-imm ;
INSN: ##not < ##unary ;
+INSN: ##log2 < ##unary ;
+
+! Overflowing arithmetic
+TUPLE: ##fixnum-overflow < insn src1 src2 ;
+INSN: ##fixnum-add < ##fixnum-overflow ;
+INSN: ##fixnum-add-tail < ##fixnum-overflow ;
+INSN: ##fixnum-sub < ##fixnum-overflow ;
+INSN: ##fixnum-sub-tail < ##fixnum-overflow ;
+INSN: ##fixnum-mul < ##fixnum-overflow temp1 temp2 ;
+INSN: ##fixnum-mul-tail < ##fixnum-overflow temp1 temp2 ;
: ##tag-fixnum ( dst src -- ) tag-bits get ##shl-imm ; inline
: ##untag-fixnum ( dst src -- ) tag-bits get ##sar-imm ; inline
INSN: ##allot < ##flushable size class { temp vreg } ;
INSN: ##write-barrier < ##effect card# table ;
+INSN: ##alien-global < ##read symbol library ;
+
! FFI
INSN: ##alien-invoke params ;
INSN: ##alien-indirect params ;
INSN: ##compare-branch < ##conditional-branch ;
INSN: ##compare-imm-branch { src1 vreg } { src2 integer } cc ;
-INSN: ##compare < ##binary cc ;
-INSN: ##compare-imm < ##binary-imm cc ;
+INSN: ##compare < ##binary cc temp ;
+INSN: ##compare-imm < ##binary-imm cc temp ;
INSN: ##compare-float-branch < ##conditional-branch ;
-INSN: ##compare-float < ##binary cc ;
+INSN: ##compare-float < ##binary cc temp ;
! Instructions used by machine IR only.
INSN: _prologue stack-frame ;
: bytes>cells ( m -- n ) cell align cell /i ;
-:: emit-<byte-array> ( node -- )
- [let | len [ node node-input-infos first literal>> ] |
- len expand-<byte-array>? [
- [let | elt [ 0 ^^load-literal ]
- reg [ len ^^allot-byte-array ] |
- ds-drop
- len reg store-length
- elt reg len bytes>cells store-initial-element
- reg ds-push
- ]
- ] [ node emit-primitive ] if
- ] ;
+: emit-allot-byte-array ( len -- dst )
+ ds-drop
+ dup ^^allot-byte-array
+ [ store-length ] [ ds-push ] [ ] tri ;
+
+: emit-(byte-array) ( node -- )
+ dup node-input-infos first literal>> dup expand-<byte-array>?
+ [ nip emit-allot-byte-array drop ] [ drop emit-primitive ] if ;
+
+: emit-<byte-array> ( node -- )
+ dup node-input-infos first literal>> dup expand-<byte-array>? [
+ nip
+ [ 0 ^^load-literal ] dip
+ [ emit-allot-byte-array ] keep
+ bytes>cells store-initial-element
+ ] [ drop emit-primitive ] if ;
USING: sequences accessors layouts kernel math namespaces
combinators fry locals
compiler.tree.propagation.info
-compiler.cfg.stacks compiler.cfg.hats compiler.cfg.instructions
-compiler.cfg.utilities ;
+compiler.cfg.hats
+compiler.cfg.stacks
+compiler.cfg.iterator
+compiler.cfg.instructions
+compiler.cfg.utilities
+compiler.cfg.registers ;
IN: compiler.cfg.intrinsics.fixnum
+: emit-both-fixnums? ( -- )
+ 2inputs
+ ^^or
+ tag-mask get ^^and-imm
+ 0 cc= ^^compare-imm
+ ds-push ;
+
: (emit-fixnum-imm-op) ( infos insn -- dst )
ds-drop
[ ds-pop ]
: emit-fixnum-bitnot ( -- )
ds-pop ^^not tag-mask get ^^xor-imm ds-push ;
+: emit-fixnum-log2 ( -- )
+ ds-pop ^^log2 tag-bits get ^^sub-imm ^^tag-fixnum ds-push ;
+
: (emit-fixnum*fast) ( -- dst )
2inputs ^^untag-fixnum ^^mul ;
: emit-fixnum>bignum ( -- )
ds-pop ^^untag-fixnum ^^integer>bignum ds-push ;
+
+: emit-fixnum-overflow-op ( quot quot-tail -- next )
+ [ 2inputs 1 ##inc-d ] 2dip
+ tail-call? [
+ ##epilogue
+ nip call
+ stop-iterating
+ ] [
+ drop call
+ ##branch
+ begin-basic-block
+ iterate-next
+ ] if ; inline
compiler.cfg.intrinsics.allot
compiler.cfg.intrinsics.fixnum
compiler.cfg.intrinsics.float
-compiler.cfg.intrinsics.slots ;
+compiler.cfg.intrinsics.slots
+compiler.cfg.intrinsics.misc
+compiler.cfg.iterator ;
QUALIFIED: kernel
QUALIFIED: arrays
QUALIFIED: byte-arrays
QUALIFIED: strings.private
QUALIFIED: classes.tuple.private
QUALIFIED: math.private
+QUALIFIED: math.integers.private
QUALIFIED: alien.accessors
IN: compiler.cfg.intrinsics
{
kernel.private:tag
+ kernel.private:getenv
+ math.private:both-fixnums?
+ math.private:fixnum+
+ math.private:fixnum-
+ math.private:fixnum*
math.private:fixnum+fast
math.private:fixnum-fast
math.private:fixnum-bitand
slots.private:slot
slots.private:set-slot
strings.private:string-nth
+ strings.private:set-string-nth-fast
classes.tuple.private:<tuple-boa>
arrays:<array>
byte-arrays:<byte-array>
+ byte-arrays:(byte-array)
math.private:<complex>
math.private:<ratio>
kernel:<wrapper>
alien.accessors:set-alien-double
} [ t "intrinsic" set-word-prop ] each ;
-: emit-intrinsic ( node word -- )
+: enable-fixnum-log2 ( -- )
+ \ math.integers.private:fixnum-log2 t "intrinsic" set-word-prop ;
+
+: emit-intrinsic ( node word -- node/f )
{
- { \ kernel.private:tag [ drop emit-tag ] }
- { \ math.private:fixnum+fast [ [ ^^add ] [ ^^add-imm ] emit-fixnum-op ] }
- { \ math.private:fixnum-fast [ [ ^^sub ] [ ^^sub-imm ] emit-fixnum-op ] }
- { \ math.private:fixnum-bitand [ [ ^^and ] [ ^^and-imm ] emit-fixnum-op ] }
- { \ math.private:fixnum-bitor [ [ ^^or ] [ ^^or-imm ] emit-fixnum-op ] }
- { \ math.private:fixnum-bitxor [ [ ^^xor ] [ ^^xor-imm ] emit-fixnum-op ] }
- { \ math.private:fixnum-shift-fast [ emit-fixnum-shift-fast ] }
- { \ math.private:fixnum-bitnot [ drop emit-fixnum-bitnot ] }
- { \ math.private:fixnum*fast [ emit-fixnum*fast ] }
- { \ math.private:fixnum< [ cc< emit-fixnum-comparison ] }
- { \ math.private:fixnum<= [ cc<= emit-fixnum-comparison ] }
- { \ math.private:fixnum>= [ cc>= emit-fixnum-comparison ] }
- { \ math.private:fixnum> [ cc> emit-fixnum-comparison ] }
- { \ kernel:eq? [ cc= emit-fixnum-comparison ] }
- { \ math.private:bignum>fixnum [ drop emit-bignum>fixnum ] }
- { \ math.private:fixnum>bignum [ drop emit-fixnum>bignum ] }
- { \ math.private:float+ [ drop [ ^^add-float ] emit-float-op ] }
- { \ math.private:float- [ drop [ ^^sub-float ] emit-float-op ] }
- { \ math.private:float* [ drop [ ^^mul-float ] emit-float-op ] }
- { \ math.private:float/f [ drop [ ^^div-float ] emit-float-op ] }
- { \ math.private:float< [ drop cc< emit-float-comparison ] }
- { \ math.private:float<= [ drop cc<= emit-float-comparison ] }
- { \ math.private:float>= [ drop cc>= emit-float-comparison ] }
- { \ math.private:float> [ drop cc> emit-float-comparison ] }
- { \ math.private:float= [ drop cc= emit-float-comparison ] }
- { \ math.private:float>fixnum [ drop emit-float>fixnum ] }
- { \ math.private:fixnum>float [ drop emit-fixnum>float ] }
- { \ slots.private:slot [ emit-slot ] }
- { \ slots.private:set-slot [ emit-set-slot ] }
- { \ strings.private:string-nth [ drop emit-string-nth ] }
- { \ classes.tuple.private:<tuple-boa> [ emit-<tuple-boa> ] }
- { \ arrays:<array> [ emit-<array> ] }
- { \ byte-arrays:<byte-array> [ emit-<byte-array> ] }
- { \ math.private:<complex> [ emit-simple-allot ] }
- { \ math.private:<ratio> [ emit-simple-allot ] }
- { \ kernel:<wrapper> [ emit-simple-allot ] }
- { \ alien.accessors:alien-unsigned-1 [ 1 emit-alien-unsigned-getter ] }
- { \ alien.accessors:set-alien-unsigned-1 [ 1 emit-alien-integer-setter ] }
- { \ alien.accessors:alien-signed-1 [ 1 emit-alien-signed-getter ] }
- { \ alien.accessors:set-alien-signed-1 [ 1 emit-alien-integer-setter ] }
- { \ alien.accessors:alien-unsigned-2 [ 2 emit-alien-unsigned-getter ] }
- { \ alien.accessors:set-alien-unsigned-2 [ 2 emit-alien-integer-setter ] }
- { \ alien.accessors:alien-signed-2 [ 2 emit-alien-signed-getter ] }
- { \ alien.accessors:set-alien-signed-2 [ 2 emit-alien-integer-setter ] }
- { \ alien.accessors:alien-unsigned-4 [ 4 emit-alien-unsigned-getter ] }
- { \ alien.accessors:set-alien-unsigned-4 [ 4 emit-alien-integer-setter ] }
- { \ alien.accessors:alien-signed-4 [ 4 emit-alien-signed-getter ] }
- { \ alien.accessors:set-alien-signed-4 [ 4 emit-alien-integer-setter ] }
- { \ alien.accessors:alien-cell [ emit-alien-cell-getter ] }
- { \ alien.accessors:set-alien-cell [ emit-alien-cell-setter ] }
- { \ alien.accessors:alien-float [ single-float-regs emit-alien-float-getter ] }
- { \ alien.accessors:set-alien-float [ single-float-regs emit-alien-float-setter ] }
- { \ alien.accessors:alien-double [ double-float-regs emit-alien-float-getter ] }
- { \ alien.accessors:set-alien-double [ double-float-regs emit-alien-float-setter ] }
+ { \ kernel.private:tag [ drop emit-tag iterate-next ] }
+ { \ kernel.private:getenv [ emit-getenv iterate-next ] }
+ { \ math.private:both-fixnums? [ drop emit-both-fixnums? iterate-next ] }
+ { \ math.private:fixnum+ [ drop [ ##fixnum-add ] [ ##fixnum-add-tail ] emit-fixnum-overflow-op ] }
+ { \ math.private:fixnum- [ drop [ ##fixnum-sub ] [ ##fixnum-sub-tail ] emit-fixnum-overflow-op ] }
+ { \ math.private:fixnum* [ drop [ i i ##fixnum-mul ] [ i i ##fixnum-mul-tail ] emit-fixnum-overflow-op ] }
+ { \ math.private:fixnum+fast [ [ ^^add ] [ ^^add-imm ] emit-fixnum-op iterate-next ] }
+ { \ math.private:fixnum-fast [ [ ^^sub ] [ ^^sub-imm ] emit-fixnum-op iterate-next ] }
+ { \ math.private:fixnum-bitand [ [ ^^and ] [ ^^and-imm ] emit-fixnum-op iterate-next ] }
+ { \ math.private:fixnum-bitor [ [ ^^or ] [ ^^or-imm ] emit-fixnum-op iterate-next ] }
+ { \ math.private:fixnum-bitxor [ [ ^^xor ] [ ^^xor-imm ] emit-fixnum-op iterate-next ] }
+ { \ math.private:fixnum-shift-fast [ emit-fixnum-shift-fast iterate-next ] }
+ { \ math.private:fixnum-bitnot [ drop emit-fixnum-bitnot iterate-next ] }
+ { \ math.integers.private:fixnum-log2 [ drop emit-fixnum-log2 iterate-next ] }
+ { \ math.private:fixnum*fast [ emit-fixnum*fast iterate-next ] }
+ { \ math.private:fixnum< [ cc< emit-fixnum-comparison iterate-next ] }
+ { \ math.private:fixnum<= [ cc<= emit-fixnum-comparison iterate-next ] }
+ { \ math.private:fixnum>= [ cc>= emit-fixnum-comparison iterate-next ] }
+ { \ math.private:fixnum> [ cc> emit-fixnum-comparison iterate-next ] }
+ { \ kernel:eq? [ cc= emit-fixnum-comparison iterate-next ] }
+ { \ math.private:bignum>fixnum [ drop emit-bignum>fixnum iterate-next ] }
+ { \ math.private:fixnum>bignum [ drop emit-fixnum>bignum iterate-next ] }
+ { \ math.private:float+ [ drop [ ^^add-float ] emit-float-op iterate-next ] }
+ { \ math.private:float- [ drop [ ^^sub-float ] emit-float-op iterate-next ] }
+ { \ math.private:float* [ drop [ ^^mul-float ] emit-float-op iterate-next ] }
+ { \ math.private:float/f [ drop [ ^^div-float ] emit-float-op iterate-next ] }
+ { \ math.private:float< [ drop cc< emit-float-comparison iterate-next ] }
+ { \ math.private:float<= [ drop cc<= emit-float-comparison iterate-next ] }
+ { \ math.private:float>= [ drop cc>= emit-float-comparison iterate-next ] }
+ { \ math.private:float> [ drop cc> emit-float-comparison iterate-next ] }
+ { \ math.private:float= [ drop cc= emit-float-comparison iterate-next ] }
+ { \ math.private:float>fixnum [ drop emit-float>fixnum iterate-next ] }
+ { \ math.private:fixnum>float [ drop emit-fixnum>float iterate-next ] }
+ { \ slots.private:slot [ emit-slot iterate-next ] }
+ { \ slots.private:set-slot [ emit-set-slot iterate-next ] }
+ { \ strings.private:string-nth [ drop emit-string-nth iterate-next ] }
+ { \ strings.private:set-string-nth-fast [ drop emit-set-string-nth-fast iterate-next ] }
+ { \ classes.tuple.private:<tuple-boa> [ emit-<tuple-boa> iterate-next ] }
+ { \ arrays:<array> [ emit-<array> iterate-next ] }
+ { \ byte-arrays:<byte-array> [ emit-<byte-array> iterate-next ] }
+ { \ byte-arrays:(byte-array) [ emit-(byte-array) iterate-next ] }
+ { \ math.private:<complex> [ emit-simple-allot iterate-next ] }
+ { \ math.private:<ratio> [ emit-simple-allot iterate-next ] }
+ { \ kernel:<wrapper> [ emit-simple-allot iterate-next ] }
+ { \ alien.accessors:alien-unsigned-1 [ 1 emit-alien-unsigned-getter iterate-next ] }
+ { \ alien.accessors:set-alien-unsigned-1 [ 1 emit-alien-integer-setter iterate-next ] }
+ { \ alien.accessors:alien-signed-1 [ 1 emit-alien-signed-getter iterate-next ] }
+ { \ alien.accessors:set-alien-signed-1 [ 1 emit-alien-integer-setter iterate-next ] }
+ { \ alien.accessors:alien-unsigned-2 [ 2 emit-alien-unsigned-getter iterate-next ] }
+ { \ alien.accessors:set-alien-unsigned-2 [ 2 emit-alien-integer-setter iterate-next ] }
+ { \ alien.accessors:alien-signed-2 [ 2 emit-alien-signed-getter iterate-next ] }
+ { \ alien.accessors:set-alien-signed-2 [ 2 emit-alien-integer-setter iterate-next ] }
+ { \ alien.accessors:alien-unsigned-4 [ 4 emit-alien-unsigned-getter iterate-next ] }
+ { \ alien.accessors:set-alien-unsigned-4 [ 4 emit-alien-integer-setter iterate-next ] }
+ { \ alien.accessors:alien-signed-4 [ 4 emit-alien-signed-getter iterate-next ] }
+ { \ alien.accessors:set-alien-signed-4 [ 4 emit-alien-integer-setter iterate-next ] }
+ { \ alien.accessors:alien-cell [ emit-alien-cell-getter iterate-next ] }
+ { \ alien.accessors:set-alien-cell [ emit-alien-cell-setter iterate-next ] }
+ { \ alien.accessors:alien-float [ single-float-regs emit-alien-float-getter iterate-next ] }
+ { \ alien.accessors:set-alien-float [ single-float-regs emit-alien-float-setter iterate-next ] }
+ { \ alien.accessors:alien-double [ double-float-regs emit-alien-float-getter iterate-next ] }
+ { \ alien.accessors:set-alien-double [ double-float-regs emit-alien-float-setter iterate-next ] }
} case ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: namespaces layouts sequences kernel
+accessors compiler.tree.propagation.info
+compiler.cfg.stacks compiler.cfg.hats
+compiler.cfg.instructions compiler.cfg.utilities ;
+IN: compiler.cfg.intrinsics.misc
+
+: emit-tag ( -- )
+ ds-pop tag-mask get ^^and-imm ^^tag-fixnum ds-push ;
+
+: emit-getenv ( node -- )
+ "userenv" f ^^alien-global
+ swap node-input-infos first literal>>
+ [ ds-drop 0 ^^slot-imm ] [ ds-pop ^^offset>slot 0 ^^slot ] if*
+ ds-push ;
compiler.cfg.utilities ;
IN: compiler.cfg.intrinsics.slots
-: emit-tag ( -- )
- ds-pop tag-mask get ^^and-imm ^^tag-fixnum ds-push ;
-
: value-tag ( info -- n ) class>> class-tag ; inline
: (emit-slot) ( infos -- dst )
: emit-string-nth ( -- )
2inputs swap ^^untag-fixnum ^^string-nth ^^tag-fixnum ds-push ;
+
+: emit-set-string-nth-fast ( -- )
+ 3inputs [ ^^untag-fixnum ] [ ^^untag-fixnum ] [ ] tri*
+ swap i ##set-string-nth-fast ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors namespaces kernel arrays
-parser prettyprint.backend prettyprint.sections ;
+USING: accessors namespaces kernel arrays parser ;
IN: compiler.cfg.registers
! Virtual registers, used by CFG and machine IRs
TUPLE: rs-loc < loc ;
C: <rs-loc> rs-loc
-! Prettyprinting
: V scan-word scan-word vreg boa parsed ; parsing
-
-M: vreg pprint*
- <block
- \ V pprint-word [ reg-class>> pprint* ] [ n>> pprint* ] bi
- block> ;
-
-: pprint-loc ( loc word -- ) <block pprint-word n>> pprint* block> ;
-
: D scan-word <ds-loc> parsed ; parsing
-
-M: ds-loc pprint* \ D pprint-loc ;
-
: R scan-word <rs-loc> parsed ; parsing
-
-M: rs-loc pprint* \ R pprint-loc ;
\ _gc t frame-required? set-word-prop
\ _spill t frame-required? set-word-prop
+\ ##fixnum-add t frame-required? set-word-prop
+\ ##fixnum-sub t frame-required? set-word-prop
+\ ##fixnum-mul t frame-required? set-word-prop
+\ ##fixnum-add-tail f frame-required? set-word-prop
+\ ##fixnum-sub-tail f frame-required? set-word-prop
+\ ##fixnum-mul-tail f frame-required? set-word-prop
: compute-stack-frame ( insns -- )
frame-required? off
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays kernel sequences sequences.deep
+USING: accessors arrays kernel sequences compiler.utilities
compiler.cfg.instructions cpu.architecture ;
IN: compiler.cfg.two-operand
: convert-two-operand ( mr -- mr' )
[
two-operand? [
- [ convert-two-operand* ] map flatten
+ [ convert-two-operand* ] map-flat
] when
] change-instructions ;
building off
basic-block off ;
+: stop-iterating ( -- next ) end-basic-block f ;
+
: emit-primitive ( node -- )
word>> ##call ##branch begin-basic-block ;
M: ##dispatch propagate
[ resolve ] change-src ;
+M: ##fixnum-overflow propagate
+ [ resolve ] change-src1
+ [ resolve ] change-src2 ;
+
M: insn propagate ;
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences layouts accessors combinators namespaces
math fry
+compiler.cfg.hats
compiler.cfg.instructions
compiler.cfg.value-numbering.graph
compiler.cfg.value-numbering.simplify
M: ##compare-imm rewrite-tagged-comparison
[ dst>> ] [ (rewrite-tagged-comparison) ] bi
- f \ ##compare-imm boa ;
+ i f \ ##compare-imm boa ;
M: ##compare-imm-branch rewrite
dup rewrite-boolean-comparison? [ rewrite-boolean-comparison ] when
[ dst>> ]
[ src2>> ]
[ src1>> vreg>vn vn>constant ] tri
- cc= f \ ##compare-imm boa ;
+ cc= f i \ ##compare-imm boa ;
M: ##compare rewrite
dup flip-comparison? [
: rewrite-redundant-comparison ( insn -- insn' )
[ cc>> ] [ dst>> ] [ src1>> vreg>expr dup op>> ] tri {
- { \ ##compare [ >compare-expr< f \ ##compare boa ] }
- { \ ##compare-imm [ >compare-imm-expr< f \ ##compare-imm boa ] }
- { \ ##compare-float [ >compare-expr< f \ ##compare-float boa ] }
+ { \ ##compare [ >compare-expr< i f \ ##compare boa ] }
+ { \ ##compare-imm [ >compare-imm-expr< i f \ ##compare-imm boa ] }
+ { \ ##compare-float [ >compare-expr< i f \ ##compare-float boa ] }
} case
swap cc= eq? [ [ negate-cc ] change-cc ] when ;
IN: compiler.cfg.value-numbering.tests
USING: compiler.cfg.value-numbering compiler.cfg.instructions
-compiler.cfg.registers cpu.architecture tools.test kernel math ;
+compiler.cfg.registers compiler.cfg.debugger cpu.architecture
+tools.test kernel math combinators.short-circuit accessors
+sequences ;
+
+: trim-temps ( insns -- insns )
+ [
+ dup {
+ [ ##compare? ]
+ [ ##compare-imm? ]
+ [ ##compare-float? ]
+ } 1|| [ f >>temp ] when
+ ] map ;
+
[
{
T{ ##peek f V int-regs 45 D 1 }
T{ ##compare f V int-regs 4 V int-regs 2 V int-regs 1 cc> }
T{ ##compare-imm f V int-regs 6 V int-regs 4 7 cc/= }
T{ ##replace f V int-regs 6 D 0 }
- } value-numbering
+ } value-numbering trim-temps
] unit-test
[
T{ ##compare f V int-regs 4 V int-regs 2 V int-regs 1 cc<= }
T{ ##compare-imm f V int-regs 6 V int-regs 4 7 cc= }
T{ ##replace f V int-regs 6 D 0 }
- } value-numbering
+ } value-numbering trim-temps
] unit-test
[
T{ ##compare-float f V int-regs 12 V double-float-regs 10 V double-float-regs 11 cc< }
T{ ##compare-imm f V int-regs 14 V int-regs 12 7 cc= }
T{ ##replace f V int-regs 14 D 0 }
- } value-numbering
+ } value-numbering trim-temps
] unit-test
[
T{ ##peek f V int-regs 30 D -2 }
T{ ##compare f V int-regs 33 V int-regs 29 V int-regs 30 cc<= }
T{ ##compare-imm-branch f V int-regs 33 7 cc/= }
- } value-numbering
+ } value-numbering trim-temps
] unit-test
USING: compiler.cfg.write-barrier compiler.cfg.instructions
-compiler.cfg.registers cpu.architecture arrays tools.test ;
+compiler.cfg.registers compiler.cfg.debugger cpu.architecture
+arrays tools.test ;
IN: compiler.cfg.write-barrier.tests
[
[ temp>> register ]
} cleave %string-nth ;
+M: ##set-string-nth-fast generate-insn
+ {
+ [ src>> register ]
+ [ obj>> register ]
+ [ index>> register ]
+ [ temp>> register ]
+ } cleave %set-string-nth-fast ;
+
: dst/src ( insn -- dst src )
[ dst>> register ] [ src>> register ] bi ; inline
M: ##shr-imm generate-insn dst/src1/src2 %shr-imm ;
M: ##sar-imm generate-insn dst/src1/src2 %sar-imm ;
M: ##not generate-insn dst/src %not ;
+M: ##log2 generate-insn dst/src %log2 ;
+
+: src1/src2 ( insn -- src1 src2 )
+ [ src1>> register ] [ src2>> register ] bi ; inline
+
+: src1/src2/temp1/temp2 ( insn -- src1 src2 temp1 temp2 )
+ [ src1/src2 ] [ temp1>> register ] [ temp2>> register ] tri ; inline
+
+M: ##fixnum-add generate-insn src1/src2 %fixnum-add ;
+M: ##fixnum-add-tail generate-insn src1/src2 %fixnum-add-tail ;
+M: ##fixnum-sub generate-insn src1/src2 %fixnum-sub ;
+M: ##fixnum-sub-tail generate-insn src1/src2 %fixnum-sub-tail ;
+M: ##fixnum-mul generate-insn src1/src2/temp1/temp2 %fixnum-mul ;
+M: ##fixnum-mul-tail generate-insn src1/src2/temp1/temp2 %fixnum-mul-tail ;
: dst/src/temp ( insn -- dst src temp )
[ dst/src ] [ temp>> register ] bi ; inline
M: ##loop-entry generate-insn drop %loop-entry ;
+M: ##alien-global generate-insn
+ [ dst>> register ] [ symbol>> ] [ library>> ] tri
+ %alien-global ;
+
! ##alien-invoke
GENERIC: reg-size ( register-class -- n )
GENERIC: inc-reg-class ( register-class -- )
: ?dummy-stack-params ( reg-class -- )
- dummy-stack-params? [ reg-size stack-params +@ ] [ drop ] if ;
+ dummy-stack-params? [ reg-size cell align stack-params +@ ] [ drop ] if ;
: ?dummy-int-params ( reg-class -- )
dummy-int-params? [ reg-size cell /i 1 max int-regs +@ ] [ drop ] if ;
: spill-param ( reg-class -- n reg-class )
stack-params get
- >r reg-size stack-params +@ r>
+ [ reg-size cell align stack-params +@ ] dip
stack-params ;
: fastcall-param ( reg-class -- n reg-class )
] { } make ;
: each-parameter ( parameters quot -- )
- >r [ parameter-sizes nip ] keep r> 2each ; inline
+ [ [ parameter-sizes nip ] keep ] dip 2each ; inline
: reverse-each-parameter ( parameters quot -- )
- >r [ parameter-sizes nip ] keep r> 2reverse-each ; inline
+ [ [ parameter-sizes nip ] keep ] dip 2reverse-each ; inline
: reset-freg-counts ( -- )
{ int-regs float-regs stack-params } [ 0 swap set ] each ;
#! 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> '[ alloc-parameter _ execute ] each-parameter ;
- inline
+ [ alien-parameters flatten-value-types ]
+ [ '[ alloc-parameter _ execute ] ]
+ bi* each-parameter ; inline
: unbox-parameters ( offset node -- )
parameters>> [
- %prepare-unbox >r over + r> unbox-parameter
+ %prepare-unbox [ over + ] dip unbox-parameter
] reverse-each-parameter drop ;
: prepare-box-struct ( node -- offset )
TUPLE: callback-context ;
-: current-callback 2 getenv ;
+: current-callback ( -- id ) 2 getenv ;
: wait-to-return ( token -- )
dup current-callback eq? [
M: _branch generate-insn
label>> lookup-label %jump-label ;
-: >compare< ( insn -- label cc src1 src2 )
+: >compare< ( insn -- dst temp cc src1 src2 )
{
[ dst>> register ]
+ [ temp>> register ]
[ cc>> ]
[ src1>> register ]
[ src2>> ?register ]
! 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 make sequences words
-quotations strings alien.accessors alien.strings layouts system
-combinators math.bitwise words.private math.order accessors
-growable cpu.architecture compiler.constants ;
+USING: arrays byte-arrays byte-vectors generic assocs hashtables
+io.binary kernel kernel.private math namespaces make sequences
+words quotations strings alien.accessors alien.strings layouts
+system combinators math.bitwise words.private math.order
+accessors growable cpu.architecture compiler.constants ;
IN: compiler.codegen.fixup
GENERIC: fixup* ( obj -- )
-: code-format 22 getenv ;
+: code-format ( -- n ) 22 getenv ;
: compiled-offset ( -- n ) building get length code-format * ;
: indq ( elt seq -- n ) [ eq? ] with find drop ;
: adjoin* ( obj table -- n )
- 2dup indq [ 2nip ] [ dup length >r push r> ] if* ;
+ 2dup indq [ 2nip ] [ dup length [ push ] dip ] 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 ;
+ [ string>symbol ] dip 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 ;
+ [ literal-table get length [ add-dlsym-literals ] dip ] dip
+ rt-dlsym rel-fixup ;
: rel-word ( word class -- )
- >r add-literal r> rt-xt rel-fixup ;
+ [ add-literal ] dip rt-xt rel-fixup ;
: rel-primitive ( word class -- )
- >r def>> first r> rt-primitive rel-fixup ;
+ [ def>> first ] dip rt-primitive rel-fixup ;
-: rel-literal ( literal class -- )
- >r add-literal r> rt-literal rel-fixup ;
+: rel-immediate ( literal class -- )
+ [ add-literal ] dip rt-immediate rel-fixup ;
: rel-this ( class -- )
0 swap rt-label rel-fixup ;
{ $description "Enables the optimizing compiler." } ;
HELP: disable-compiler
-{ $description "Enables the optimizing compiler." } ;
+{ $description "Disable the optimizing compiler." } ;
ARTICLE: "compiler-usage" "Calling the optimizing compiler"
"Normally, new word definitions are recompiled automatically. This can be changed:"
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel namespaces arrays sequences io debugger
-words fry continuations vocabs assocs dlists definitions
-math threads graphs generic combinators deques search-deques
-prettyprint io stack-checker stack-checker.state
-stack-checker.inlining compiler.errors compiler.units
-compiler.tree.builder compiler.tree.optimizer
-compiler.cfg.builder compiler.cfg.optimizer
-compiler.cfg.linearization compiler.cfg.two-operand
-compiler.cfg.linear-scan compiler.cfg.stack-frame
-compiler.codegen ;
+USING: accessors kernel namespaces arrays sequences io
+words fry continuations vocabs assocs dlists definitions math
+threads graphs generic combinators deques search-deques io
+stack-checker stack-checker.state stack-checker.inlining
+compiler.errors compiler.units compiler.tree.builder
+compiler.tree.optimizer compiler.cfg.builder
+compiler.cfg.optimizer compiler.cfg.linearization
+compiler.cfg.two-operand compiler.cfg.linear-scan
+compiler.cfg.stack-frame compiler.codegen ;
IN: compiler
SYMBOL: compile-queue
2bi ;
: start ( word -- )
- "trace-compilation" get [ dup . flush ] when
+ "trace-compilation" get [ dup name>> print flush ] when
H{ } clone dependencies set
H{ } clone generic-dependencies set
f swap compiler-error ;
[
dup crossref?
[
- dependencies get >alist
- generic-dependencies get >alist
+ dependencies get
+ generic-dependencies get
compiled-xref
] [ drop ] if
] tri ;
! Relocation types
: rt-primitive 0 ; inline
: rt-dlsym 1 ; inline
-: rt-literal 2 ; inline
-: rt-dispatch 3 ; inline
-: rt-xt 4 ; inline
-: rt-here 5 ; inline
-: rt-label 6 ; inline
-: rt-immediate 7 ; inline
-: rt-stack-chain 8 ; inline
+: rt-dispatch 2 ; inline
+: rt-xt 3 ; inline
+: rt-here 4 ; inline
+: rt-label 5 ; inline
+: rt-immediate 6 ; inline
+: rt-stack-chain 7 ; inline
: rc-absolute? ( n -- ? )
[ rc-absolute-ppc-2/2 = ]
namespaces namespaces tools.test sequences stack-checker
stack-checker.errors words arrays parser quotations
continuations effects namespaces.private io io.streams.string
-memory system threads tools.test math accessors combinators ;
+memory system threads tools.test math accessors combinators
+specialized-arrays.float ;
FUNCTION: void ffi_test_0 ;
[ ] [ ffi_test_0 ] unit-test
{ 1 1 } [ indirect-test-1 ] must-infer-as
-[ 3 ] [ "ffi_test_1" f dlsym indirect-test-1 ] unit-test
+[ 3 ] [ &: ffi_test_1 indirect-test-1 ] unit-test
: indirect-test-1' ( ptr -- )
"int" { } "cdecl" alien-indirect drop ;
{ 1 0 } [ indirect-test-1' ] must-infer-as
-[ ] [ "ffi_test_1" f dlsym indirect-test-1' ] unit-test
+[ ] [ &: ffi_test_1 indirect-test-1' ] unit-test
[ -1 indirect-test-1 ] must-fail
{ 3 1 } [ indirect-test-2 ] must-infer-as
[ 5 ]
-[ 2 3 "ffi_test_2" f dlsym indirect-test-2 ]
+[ 2 3 &: ffi_test_2 indirect-test-2 ]
unit-test
: indirect-test-3 ( a b c d ptr -- result )
! Make sure XT doesn't get clobbered in stack frame
-: ffi_test_31 ( a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ptr -- result y )
- "void"
+: ffi_test_31 ( a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a -- result y )
+ "int"
f "ffi_test_31"
{ "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" "int" }
alien-invoke gc 3 ;
-[ 3 ] [ 42 [ ] each ffi_test_31 ] unit-test
+[ 861 3 ] [ 42 [ ] each ffi_test_31 ] unit-test
+
+: ffi_test_31_point_5 ( a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a -- result )
+ "float"
+ f "ffi_test_31_point_5"
+ { "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" "float" }
+ alien-invoke ;
+
+[ 861.0 ] [ 42 [ >float ] each ffi_test_31_point_5 ] unit-test
FUNCTION: longlong ffi_test_21 long x long y ;
FUNCTION: float ffi_test_23 ( float[3] x, float[3] y ) ;
-[ 32.0 ] [ { 1.0 2.0 3.0 } >c-float-array { 4.0 5.0 6.0 } >c-float-array ffi_test_23 ] unit-test
+[ 32.0 ] [
+ { 1.0 2.0 3.0 } >float-array underlying>>
+ { 4.0 5.0 6.0 } >float-array underlying>>
+ ffi_test_23
+] unit-test
! Test odd-size structs
C-STRUCT: test-struct-1 { { "char" 1 } "x" } ;
[ 1 2 3 ] [ callback-6 callback_test_1 1 2 3 ] unit-test
: callback-7 ( -- callback )
- "void" { } "cdecl" [ 1000 sleep ] alien-callback ;
+ "void" { } "cdecl" [ 1000000 sleep ] alien-callback ;
[ 1 2 3 ] [ callback-7 callback_test_1 1 2 3 ] unit-test
sequences sequences.private tools.test namespaces.private
slots.private sequences.private byte-arrays alien
alien.accessors layouts words definitions compiler.units io
-combinators vectors float-arrays ;
+combinators vectors grouping make ;
IN: compiler.tests
! Originally, this file did black box testing of templating
[ "a" ] [ 1 test-2 ] unit-test
[ "b" ] [ 2 test-2 ] unit-test
+
+! I accidentally fixnum/i-fast on PowerPC
+[ { { 1 2 } { 3 4 } } ] [
+ { 1 2 3 4 }
+ [
+ [ { array } declare 2 <groups> [ , ] each ] compile-call
+ ] { } make
+] unit-test
+
+[ 2 ] [
+ { 1 2 3 4 }
+ [ { array } declare 2 <groups> length ] compile-call
+] unit-test
+
+! Oops with new intrinsics
+: fixnum-overflow-control-flow-test ( a b -- c )
+ [ 1 fixnum- ] [ 2 fixnum- ] if 3 fixnum+fast ;
+
+[ 3 ] [ 1 t fixnum-overflow-control-flow-test ] unit-test
+[ 2 ] [ 1 f fixnum-overflow-control-flow-test ] unit-test
+
+! LOL
+: blah ( a -- b )
+ { float } declare dup 0 =
+ [ drop 1 ] [
+ dup 0 >=
+ [ 2 "double" "libm" "pow" { "double" "double" } alien-invoke ]
+ [ -0.5 "double" "libm" "pow" { "double" "double" } alien-invoke ]
+ if
+ ] if ;
+
+[ 4.0 ] [ 2.0 blah ] unit-test
+
+[ 4 ] [ 2 [ dup fixnum* ] compile-call ] unit-test
+[ 7 ] [ 2 [ dup fixnum* 3 fixnum+fast ] compile-call ] unit-test
[ -2 ] [ 4 [ -2 fixnum/i ] compile-call ] unit-test
[ 3 1 ] [ 10 3 [ fixnum/mod ] compile-call ] unit-test
+[ 2 ] [ 4 2 [ fixnum/i-fast ] compile-call ] unit-test
+[ 2 ] [ 4 [ 2 fixnum/i-fast ] compile-call ] unit-test
+[ -2 ] [ 4 [ -2 fixnum/i-fast ] compile-call ] unit-test
+[ 3 1 ] [ 10 3 [ fixnum/mod-fast ] compile-call ] unit-test
+
[ 4 ] [ 1 3 [ fixnum+ ] compile-call ] unit-test
[ 4 ] [ 1 [ 3 fixnum+ ] compile-call ] unit-test
[ 4 ] [ [ 1 3 fixnum+ ] compile-call ] unit-test
[ -1 ] [ [ -123 -64 fixnum-shift ] compile-call ] unit-test
[ -1 ] [ -123 -64 [ fixnum-shift ] compile-call ] unit-test
+[ HEX: 10000000 ] [ HEX: 1000000 HEX: 10 [ fixnum* ] compile-call ] unit-test
[ HEX: 10000000 ] [ HEX: -10000000 >fixnum [ 0 swap fixnum- ] compile-call ] unit-test
[ HEX: 10000000 ] [ HEX: -fffffff >fixnum [ 1 swap fixnum- ] compile-call ] unit-test
HINTS: recursive-inline-hang-3 array ;
! Regression
-USE: sequences.private
-
-[ ] [ { (3append) } compile ] unit-test
+[ ] [ { 3append-as } compile ] unit-test
! Wow
: counter-example ( a b c d -- a' b' c' d' )
: loop-ccc ( -- ) loop-bbb ;
[ 0 ] [ 0 counter set loop-ccc counter get ] unit-test
+
+! Type inference issue
+[ 4 3 ] [
+ 1 >bignum 2 >bignum
+ [ { bignum integer } declare [ shift ] keep 1+ ] compile-call
+] unit-test
--- /dev/null
+USING: math fry macros eval tools.test ;
+IN: compiler.tests.redefine13
+
+: breakage-word ( a b -- c ) + ;
+
+MACRO: breakage-macro ( a -- ) '[ _ breakage-word ] ;
+
+GENERIC: breakage-caller ( a -- c )
+
+M: fixnum breakage-caller 2 breakage-macro ;
+
+: breakage ( -- obj ) 2 breakage-caller ;
+
+! [ ] [ "IN: compiler.tests.redefine13 : breakage-word ( a b -- c ) ;" eval ] unit-test
--- /dev/null
+USING: compiler.units definitions tools.test sequences ;
+IN: compiler.tests.redefine14
+
+! TUPLE: bad ;
+!
+! M: bad length 1 2 3 ;
+!
+! [ ] [ [ { bad length } forget ] with-compilation-unit ] unit-test
USING: math.private kernel combinators accessors arrays
-generalizations float-arrays tools.test ;
+generalizations tools.test ;
IN: compiler.tests
: float-spill-bug ( a -- b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b )
: build-tree-with ( in-stack quot -- nodes out-stack )
#! Not safe to call from inference transforms.
[
- [ >vector meta-d set ]
+ [ >vector \ meta-d set ]
[ f initial-recursive-state infer-quot ] bi*
] with-tree-builder nip
unclip-last in-d>> ;
2over fixnum>= [
3drop
] [
- [ swap >r call 1 fixnum+fast r> ] keep (fx-repeat)
+ [ swap [ call 1 fixnum+fast ] dip ] keep (fx-repeat)
] if ; inline recursive
: fx-repeat ( n quot -- )
2over dup xyz drop >= [
3drop
] [
- [ swap >r call 1+ r> ] keep (i-repeat)
+ [ swap [ call 1+ ] dip ] keep (i-repeat)
] if ; inline recursive
-: i-repeat >r { integer } declare r> 0 -rot (i-repeat) ; inline
+: i-repeat [ { integer } declare ] dip 0 -rot (i-repeat) ; inline
[ t ] [
[ [ dup xyz drop ] i-repeat ] \ xyz inlined?
2dup >= [
2drop
] [
- >r dup annotate-entry-test-1 1+ r> (annotate-entry-test-2)
+ [ dup annotate-entry-test-1 1+ ] dip (annotate-entry-test-2)
] if ; inline recursive
: annotate-entry-test-2 0 -rot (annotate-entry-test-2) ; inline
] unit-test
[ ] [
- [ [ >r "A" throw r> ] [ "B" throw ] if ]
+ [ [ [ "A" throw ] dip ] [ "B" throw ] if ]
cleaned-up-tree drop
] unit-test
: buffalo-wings ( i seq -- )
2dup < [
2dup chicken-fingers
- >r 1+ r> buffalo-wings
+ [ 1+ ] dip buffalo-wings
] [
2drop
] if ; inline recursive
: ribs ( i seq -- )
2dup < [
steak
- >r 1+ r> ribs
+ [ 1+ ] dip ribs
] [
2drop
] if ; inline recursive
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors sequences sequences.deep combinators fry
+USING: kernel accessors sequences combinators fry
classes.algebra namespaces assocs words math math.private
math.partial-dispatch math.intervals classes classes.tuple
classes.tuple.private layouts definitions stack-checker.state
stack-checker.branches
+compiler.utilities
compiler.tree
compiler.tree.combinators
compiler.tree.propagation.info
: cleanup ( nodes -- nodes' )
#! We don't recurse into children here, instead the methods
#! do it since the logic is a bit more involved
- [ cleanup* ] map flatten ;
+ [ cleanup* ] map-flat ;
: cleanup-folding? ( #call -- ? )
node-output-infos
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: assocs fry kernel accessors sequences sequences.deep arrays
-stack-checker.inlining namespaces compiler.tree ;
+USING: assocs fry kernel accessors sequences compiler.utilities
+arrays stack-checker.inlining namespaces compiler.tree
+math.order ;
IN: compiler.tree.combinators
: each-node ( nodes quot: ( node -- ) -- )
[ _ map-nodes ] change-child
] when
] if
- ] map flatten ; inline recursive
+ ] map-flat ; inline recursive
: contains-node? ( nodes quot: ( node -- ? ) -- ? )
dup dup '[
: sift-children ( seq flags -- seq' )
zip [ nip ] assoc-filter keys ;
-: (3each) [ 3array flip ] dip '[ first3 @ ] ; inline
-
-: 3each ( seq1 seq2 seq3 quot -- seq ) (3each) each ; inline
-
-: 3map ( seq1 seq2 seq3 quot -- seq ) (3each) map ; inline
-
: until-fixed-point ( #recursive quot: ( node -- ) -- )
over label>> t >>fixed-point drop
[ with-scope ] 2keep
remove-dead-code
"no-check" get [ dup check-nodes ] unless nodes>quot ;
-[ [ drop 1 ] ] [ [ >r 1 r> drop ] optimize-quot ] unit-test
+[ [ drop 1 ] ] [ [ [ 1 ] dip drop ] optimize-quot ] unit-test
-[ [ read drop 1 2 ] ] [ [ read >r 1 2 r> drop ] optimize-quot ] unit-test
+[ [ read drop 1 2 ] ] [ [ read [ 1 2 ] dip drop ] optimize-quot ] unit-test
[ [ over >r + r> ] ] [ [ [ + ] [ drop ] 2bi ] optimize-quot ] unit-test
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: fry accessors namespaces assocs deques search-deques
-dlists kernel sequences sequences.deep words sets
+dlists kernel sequences compiler.utilities words sets
stack-checker.branches compiler.tree compiler.tree.def-use
compiler.tree.combinators ;
IN: compiler.tree.dead-code.liveness
M: node remove-dead-code* ;
: (remove-dead-code) ( nodes -- nodes' )
- [ remove-dead-code* ] map flatten ;
+ [ remove-dead-code* ] map-flat ;
[ out-d>> ] [ label>> return>> in-d>> ] bi look-at-mapping ;
:: drop-dead-inputs ( inputs outputs -- #shuffle )
- [let* | live-inputs [ inputs filter-live ]
- new-live-inputs [ outputs inputs filter-corresponding make-values ] |
- live-inputs
- new-live-inputs
- outputs
- inputs
- drop-values
- ] ;
+ inputs filter-live
+ outputs inputs filter-corresponding make-values
+ outputs
+ inputs
+ drop-values ;
M: #enter-recursive remove-dead-code*
[ filter-live ] change-out-d ;
bi
] ;
-M:: #recursive remove-dead-code* ( node -- nodes )
- [let* | drop-inputs [ node drop-recursive-inputs ]
- drop-outputs [ node drop-recursive-outputs ] |
- node [ (remove-dead-code) ] change-child drop
- node label>> [ filter-live ] change-enter-out drop
- { drop-inputs node drop-outputs }
- ] ;
+M: #recursive remove-dead-code* ( node -- nodes )
+ [ drop-recursive-inputs ]
+ [
+ [ (remove-dead-code) ] change-child
+ dup label>> [ filter-live ] change-enter-out drop
+ ]
+ [ drop-recursive-outputs ] tri 3array ;
M: #return-recursive remove-dead-code* ;
! See http://factorcode.org/license.txt for BSD license.
USING: kernel assocs match fry accessors namespaces make effects
sequences sequences.private quotations generic macros arrays
-prettyprint prettyprint.backend prettyprint.sections math words
-combinators combinators.short-circuit io sorting hints qualified
+prettyprint prettyprint.backend prettyprint.custom
+prettyprint.sections math words combinators
+combinators.short-circuit io sorting hints qualified
compiler.tree
compiler.tree.recursive
compiler.tree.normalization
[ drop "COMPLEX SHUFFLE" , ]
} cond ;
-M: #push node>quot literal>> , ;
+M: #push node>quot literal>> literalize , ;
M: #call node>quot word>> , ;
: nodes>quot ( node -- quot )
[ [ node>quot ] each ] [ ] make ;
-: optimized. ( quot/word -- )
- dup word? [ specialized-def ] when
- build-tree optimize-tree nodes>quot . ;
+GENERIC: optimized. ( quot/word -- )
+
+M: method-spec optimized. first2 method optimized. ;
+
+M: word optimized. specialized-def optimized. ;
+
+M: callable optimized. build-tree optimize-tree nodes>quot . ;
SYMBOL: words-called
SYMBOL: generics-called
H{ } clone intrinsics-called set
0 swap [
- >r 1+ r>
+ [ 1+ ] dip
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+
+ } cond inc-at
] [ drop ] if
] each-node
node-count set
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: sequences sequences.deep kernel
+USING: sequences kernel fry vectors
compiler.tree compiler.tree.def-use ;
IN: compiler.tree.def-use.simplified
! A 'real' usage is a usage of a value that is not a #renaming.
TUPLE: real-usage value node ;
-GENERIC: actually-used-by* ( value node -- real-usages )
-
! Def
GENERIC: actually-defined-by* ( value node -- real-usage )
M: node actually-defined-by* real-usage boa ;
! Use
-: (actually-used-by) ( value -- real-usages )
- dup used-by [ actually-used-by* ] with map ;
+GENERIC# actually-used-by* 1 ( value node accum -- )
+
+: (actually-used-by) ( value accum -- )
+ [ [ used-by ] keep ] dip '[ _ swap _ actually-used-by* ] each ;
M: #renaming actually-used-by*
- inputs/outputs [ indices ] dip nths
- [ (actually-used-by) ] map ;
+ [ inputs/outputs [ indices ] dip nths ] dip
+ '[ _ (actually-used-by) ] each ;
-M: #return-recursive actually-used-by* real-usage boa ;
+M: #return-recursive actually-used-by* [ real-usage boa ] dip push ;
-M: node actually-used-by* real-usage boa ;
+M: node actually-used-by* [ real-usage boa ] dip push ;
: actually-used-by ( value -- real-usages )
- (actually-used-by) flatten ;
+ 10 <vector> [ (actually-used-by) ] keep ;
2bi ;
M: #phi escape-analysis*
- [ phi-in-d>> <flipped> ] [ out-d>> ] bi merge-allocations ;
+ [ phi-in-d>> flip ] [ out-d>> ] bi merge-allocations ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: classes classes.tuple math math.private accessors
+combinators kernel compiler.tree compiler.tree.combinators
+compiler.tree.propagation.info ;
+IN: compiler.tree.escape-analysis.check
+
+GENERIC: run-escape-analysis* ( node -- ? )
+
+M: #push run-escape-analysis*
+ literal>> [ class immutable-tuple-class? ] [ complex? ] bi or ;
+
+M: #call run-escape-analysis*
+ {
+ { [ dup word>> \ <complex> eq? ] [ t ] }
+ { [ dup immutable-tuple-boa? ] [ t ] }
+ [ f ]
+ } cond nip ;
+
+M: node run-escape-analysis* drop f ;
+
+: run-escape-analysis? ( nodes -- ? )
+ [ run-escape-analysis* ] contains-node? ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors sequences words memoize classes.builtin
+USING: kernel accessors sequences words memoize combinators
+classes classes.builtin classes.tuple math.partial-dispatch
fry assocs
compiler.tree
compiler.tree.combinators
! See the comment in compiler.tree.late-optimizations.
! This pass runs after propagation, so that it can expand
-! built-in type predicates; these cannot be expanded before
+! type predicates; these cannot be expanded before
! propagation since we need to see 'fixnum?' instead of
! 'tag 0 eq?' and so on, for semantic reasoning.
[ [ in-r>> ] [ out-r>> ] [ mapping>> ] tri '[ _ at ] map sequence= ]
bi and [ drop f ] when ;
-: builtin-predicate? ( #call -- ? )
- word>> "predicating" word-prop builtin-class? ;
-
-MEMO: builtin-predicate-expansion ( word -- nodes )
+MEMO: cached-expansion ( word -- nodes )
def>> splice-final ;
-: expand-builtin-predicate ( #call -- nodes )
- word>> builtin-predicate-expansion ;
+GENERIC: finalize-word ( #call word -- nodes )
+
+M: predicate finalize-word
+ "predicating" word-prop {
+ { [ dup builtin-class? ] [ drop word>> cached-expansion ] }
+ { [ dup tuple-class? ] [ drop word>> def>> splice-final ] }
+ [ drop ]
+ } cond ;
+
+! M: math-partial finalize-word
+! dup primitive? [ drop ] [ nip cached-expansion ] if ;
+
+M: word finalize-word drop ;
M: #call finalize*
- dup builtin-predicate? [ expand-builtin-predicate ] when ;
+ dup word>> finalize-word ;
M: node finalize* ;
[ ] [ [ [ 1 ] [ 2 ] if + * ] test-normalization ] unit-test
DEFER: bbb
-: aaa ( x -- ) dup [ dup >r bbb r> aaa ] [ drop ] if ; inline recursive
-: bbb ( x -- ) >r drop 0 r> aaa ; inline recursive
+: aaa ( x -- ) dup [ dup [ bbb ] dip aaa ] [ drop ] if ; inline recursive
+: bbb ( x -- ) [ drop 0 ] dip aaa ; inline recursive
[ ] [ [ bbb ] test-normalization ] unit-test
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: fry namespaces sequences math accessors kernel arrays
-combinators sequences.deep assocs
+combinators compiler.utilities assocs
stack-checker.backend
stack-checker.branches
stack-checker.inlining
+compiler.utilities
compiler.tree
compiler.tree.combinators
compiler.tree.normalization.introductions
[
[
[
- [ normalize* ] map flatten
+ [ normalize* ] map-flat
introduction-stack get
2array
] with-scope
: (normalize) ( nodes introductions -- nodes )
introduction-stack [
- [ normalize* ] map flatten
+ [ normalize* ] map-flat
] with-variable ;
M: #recursive normalize*
compiler.tree.propagation
compiler.tree.cleanup
compiler.tree.escape-analysis
+compiler.tree.escape-analysis.check
compiler.tree.tuple-unboxing
compiler.tree.identities
compiler.tree.def-use
normalize
propagate
cleanup
- escape-analysis
- unbox-tuples
+ dup run-escape-analysis? [
+ escape-analysis
+ unbox-tuples
+ ] when
apply-identities
compute-def-use
remove-dead-code
USING: fry kernel sequences assocs accessors namespaces
math.intervals arrays classes.algebra combinators columns
stack-checker.branches
+compiler.utilities
compiler.tree
compiler.tree.combinators
compiler.tree.propagation.info
M: #phi propagate-before ( #phi -- )
[ annotate-phi-inputs ]
- [ [ phi-info-d>> <flipped> ] [ out-d>> ] bi merge-value-infos ]
+ [ [ phi-info-d>> flip ] [ out-d>> ] bi merge-value-infos ]
bi ;
: branch-phi-constraints ( output values booleans -- )
M: #phi propagate-after ( #phi -- )
condition-value get [
[ out-d>> ]
- [ phi-in-d>> <flipped> ]
- [ phi-info-d>> <flipped> ] tri
+ [ phi-in-d>> flip ]
+ [ phi-info-d>> flip ] tri
[
[ possible-boolean-values ] map
branch-phi-constraints
] 2each ;
M: #phi compute-copy-equiv*
- [ phi-in-d>> <flipped> ] [ out-d>> ] bi compute-phi-equiv ;
+ [ phi-in-d>> flip ] [ out-d>> ] bi compute-phi-equiv ;
M: node compute-copy-equiv* drop ;
! See http://factorcode.org/license.txt for BSD license.
USING: assocs classes classes.algebra classes.tuple
classes.tuple.private kernel accessors math math.intervals
-namespaces sequences words combinators combinators.short-circuit
+namespaces sequences words combinators
arrays compiler.tree.propagation.copy ;
IN: compiler.tree.propagation.info
{ [ over not ] [ 2drop f ] }
[
{
- [ [ class>> ] bi@ class<= ]
- [ [ interval>> ] bi@ interval-subset? ]
- [ literals<= ]
- [ [ length>> ] bi@ value-info<= ]
- [ [ slots>> ] bi@ [ value-info<= ] 2all? ]
- } 2&&
+ { [ 2dup [ class>> ] bi@ class<= not ] [ f ] }
+ { [ 2dup [ interval>> ] bi@ interval-subset? not ] [ f ] }
+ { [ 2dup literals<= not ] [ f ] }
+ { [ 2dup [ length>> ] bi@ value-info<= not ] [ f ] }
+ { [ 2dup [ slots>> ] bi@ [ value-info<= ] 2all? not ] [ f ] }
+ [ t ]
+ } cond 2nip
]
} cond ;
USING: accessors kernel arrays sequences math math.order
math.partial-dispatch generic generic.standard generic.math
classes.algebra classes.union sets quotations assocs combinators
-words namespaces continuations
+words namespaces continuations classes fry
compiler.tree
compiler.tree.builder
compiler.tree.recursive
: count-nodes ( nodes -- )
0 swap [ drop 1+ ] each-node node-count set ;
+! We try not to inline the same word too many times, to avoid
+! combinatorial explosion
+SYMBOL: inlining-count
+
! Splicing nodes
GENERIC: splicing-nodes ( #call word/quot/f -- nodes )
M: word splicing-nodes
[ [ in-d>> ] [ out-d>> ] bi ] dip #call 1array ;
-M: quotation splicing-nodes
+M: callable splicing-nodes
build-sub-tree analyze-recursive normalize ;
: propagate-body ( #call -- )
] [ 2drop f >>method f >>body f >>class drop f ] if ;
: inlining-standard-method ( #call word -- class/f method/f )
- [ in-d>> <reversed> ] [ [ dispatch# ] keep ] bi*
- [ swap nth value-info class>> dup ] dip
- specific-method ;
+ dup "methods" word-prop assoc-empty? [ 2drop f f ] [
+ [ in-d>> <reversed> ] [ [ dispatch# ] keep ] bi*
+ [ swap nth value-info class>> dup ] dip
+ specific-method
+ ] if ;
: inline-standard-method ( #call word -- ? )
dupd inlining-standard-method eliminate-dispatch ;
: word-flat-length ( word -- n )
{
+ ! special-case
+ { [ dup { dip 2dip 3dip } memq? ] [ drop 1 ] }
! not inline
{ [ dup inline? not ] [ drop 1 ] }
! recursive and inline
bi and
] contains? ;
+: node-count-bias ( -- n )
+ 45 node-count get [-] 8 /i ;
+
+: body-length-bias ( word -- n )
+ [ flat-length ] [ inlining-count get at 0 or ] bi
+ over 2 <= [ drop ] [ 2/ 1+ * ] if 24 swap [-] 4 /i ;
+
: inlining-rank ( #call word -- n )
[ classes-known? 2 0 ? ]
[
{
- [ drop node-count get 45 swap [-] 8 /i ]
- [ flat-length 24 swap [-] 4 /i ]
+ [ body-length-bias ]
[ "default" word-prop -4 0 ? ]
[ "specializer" word-prop 1 0 ? ]
[ method-body? 1 0 ? ]
} cleave
- ] bi* + + + + + ;
+ node-count-bias
+ loop-nesting get 0 or 2 *
+ ] bi* + + + + + + ;
: should-inline? ( #call word -- ? )
dup "inline" word-prop [ 2drop t ] [ inlining-rank 5 >= ] if ;
SYMBOL: history
: remember-inlining ( word -- )
- history [ swap suffix ] change ;
+ [ inlining-count get inc-at ]
+ [ history [ swap suffix ] change ]
+ bi ;
-: inline-word ( #call word -- ? )
- dup history get memq? [
- 2drop f
- ] [
+: inline-word-def ( #call word quot -- ? )
+ over history get memq? [ 3drop f ] [
[
- dup remember-inlining
- dupd def>> splicing-nodes >>body
+ swap remember-inlining
+ dupd splicing-nodes >>body
propagate-body
] with-scope
t
] if ;
+: inline-word ( #call word -- ? )
+ dup def>> inline-word-def ;
+
: inline-method-body ( #call word -- ? )
2dup should-inline? [ inline-word ] [ 2drop f ] if ;
[ dup 1array ] [ "custom-inlining" word-prop ] bi* with-datastack
first object swap eliminate-dispatch ;
-: do-inlining ( #call word -- ? )
+: inline-instance-check ( #call word -- ? )
+ over in-d>> second value-info literal>> dup class?
+ [ "predicate" word-prop '[ drop @ ] inline-word-def ] [ 3drop f ] if ;
+
+: (do-inlining) ( #call word -- ? )
#! If the generic was defined in an outer compilation unit,
#! then it doesn't have a definition yet; the definition
#! is built at the end of the compilation unit. We do not
#! discouraged, but it should still work.)
{
{ [ dup deferred? ] [ 2drop f ] }
- { [ dup custom-inlining? ] [ inline-custom ] }
+ { [ dup \ instance? eq? ] [ inline-instance-check ] }
{ [ dup always-inline-word? ] [ inline-word ] }
{ [ dup standard-generic? ] [ inline-standard-method ] }
{ [ dup math-generic? ] [ inline-math-method ] }
{ [ dup method-body? ] [ inline-method-body ] }
[ 2drop f ]
} cond ;
+
+: do-inlining ( #call word -- ? )
+ #! Note the logic here: if there's a custom inlining hook,
+ #! it is permitted to return f, which means that we try the
+ #! normal inlining heuristic.
+ dup custom-inlining? [ 2dup inline-custom ] [ f ] if
+ [ 2drop t ] [ (do-inlining) ] if ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel effects accessors math math.private math.libm
-math.partial-dispatch math.intervals 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
+USING: kernel effects accessors math math.private
+math.integers.private math.partial-dispatch math.intervals
+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
stack-checker.state
compiler.tree.comparisons
compiler.tree.propagation.info
\ bitnot { integer } "input-classes" set-word-prop
-{
- fcosh
- flog
- fsinh
- fexp
- fasin
- facosh
- fasinh
- ftanh
- fatanh
- facos
- fpow
- fatan
- fatan2
- fcos
- ftan
- fsin
- fsqrt
-} [
- dup stack-effect
- [ in>> length real <repetition> "input-classes" set-word-prop ]
- [ out>> length float <repetition> "default-output-classes" set-word-prop ]
- 2bi
-] each
-
: ?change-interval ( info quot -- quot' )
over interval>> [ [ clone ] dip change-interval ] [ 2drop ] if ; inline
[ rational math-class-max ] dip
] unless ;
+: ensure-math-class ( class must-be -- class' )
+ [ class<= ] 2keep ? ;
+
: number-valued ( class interval -- class' interval' )
- [ number math-class-min ] dip ;
+ [ number ensure-math-class ] dip ;
: integer-valued ( class interval -- class' interval' )
- [ integer math-class-min ] dip ;
+ [ integer ensure-math-class ] dip ;
: real-valued ( class interval -- class' interval' )
- [ real math-class-min ] dip ;
+ [ real ensure-math-class ] dip ;
: float-valued ( class interval -- class' interval' )
over null-class? [
\ mod [ [ interval-mod ] [ real-valued ] binary-op ] each-derived-op
\ rem [ [ interval-rem ] [ may-overflow real-valued ] binary-op ] each-derived-op
+{ /mod fixnum/mod } [
+ \ /i \ mod
+ [ "outputs" word-prop ] bi@
+ '[ _ _ 2bi ] "outputs" set-word-prop
+] each
+
\ shift [ [ interval-shift-safe ] [ may-overflow integer-valued ] binary-op ] each-derived-op
\ shift [ [ interval-shift-safe ] [ integer-valued ] binary-op ] each-fast-derived-op
comparison-ops
[ dup '[ _ define-comparison-constraints ] each-derived-op ] each
-generic-comparison-ops [
- dup specific-comparison
- '[ _ _ define-comparison-constraints ] each-derived-op
-] each
+! generic-comparison-ops [
+! dup specific-comparison define-comparison-constraints
+! ] each
! Remove redundant comparisons
: fold-comparison ( info1 info2 word -- info )
2bi and maybe-or-never
] "outputs" set-word-prop
+\ both-fixnums? [
+ [ class>> fixnum classes-intersect? not ] either?
+ f <literal-info> object-info ?
+] "outputs" set-word-prop
+
{
{ >fixnum fixnum }
+ { bignum>fixnum fixnum }
+
{ >bignum bignum }
+ { fixnum>bignum bignum }
+ { float>bignum bignum }
+
{ >float float }
+ { fixnum>float float }
+ { bignum>float float }
} [
'[
_
} [
[
in-d>> second value-info >literal<
- [ power-of-2? [ 1- bitand ] f ? ] when
+ [ dup integer? [ power-of-2? [ 1- bitand ] f ? ] [ drop f ] if ] when
] "custom-inlining" set-word-prop
] each
] "custom-inlining" set-word-prop
] each
+{ numerator denominator }
+[ [ drop integer <class-info> ] "outputs" set-word-prop ] each
+
+{ (log2) fixnum-log2 bignum-log2 } [
+ [
+ [ class>> ] [ interval>> interval-log2 ] bi <class/interval-info>
+ ] "outputs" set-word-prop
+] each
+
+\ string-nth [
+ 2drop fixnum 0 23 2^ [a,b] <class/interval-info>
+] "outputs" set-word-prop
+
{
alien-signed-1
alien-unsigned-1
"outputs" set-word-prop
] each
+! Generate more efficient code for common idiom
+\ clone [
+ in-d>> first value-info literal>> {
+ { V{ } [ [ drop { } 0 vector boa ] ] }
+ { H{ } [ [ drop hashtable new ] ] }
+ [ drop f ]
+ } case
+] "custom-inlining" set-word-prop
+
\ slot [
dup literal?>>
[ literal>> swap value-info-slot ] [ 2drop object-info ] if
compiler.tree.propagation.info ;
IN: compiler.tree.propagation.nodes
+SYMBOL: loop-nesting
+
GENERIC: propagate-before ( node -- )
GENERIC: propagate-after ( node -- )
compiler.tree.propagation.info compiler.tree.def-use
compiler.tree.debugger compiler.tree.checker
slots.private words hashtables classes assocs locals
-float-arrays system sorting ;
+specialized-arrays.double system sorting math.libm
+math.intervals ;
IN: compiler.tree.propagation.tests
\ propagate must-infer
[ V{ fixnum } ] [ [ { fixnum } declare bitnot ] final-classes ] unit-test
-[ V{ number } ] [ [ + ] final-classes ] unit-test
+! Test type propagation for math ops
+: cleanup-math-class ( obj -- class )
+ { null fixnum bignum integer ratio rational float real complex number }
+ [ class= ] with find nip ;
-[ V{ float } ] [ [ { float integer } declare + ] final-classes ] unit-test
+: final-math-class ( quot -- class )
+ final-classes first cleanup-math-class ;
-[ V{ float } ] [ [ /f ] final-classes ] unit-test
+[ number ] [ [ + ] final-math-class ] unit-test
-[ V{ integer } ] [ [ /i ] final-classes ] unit-test
+[ bignum ] [ [ { fixnum bignum } declare + ] final-math-class ] unit-test
-[ V{ integer } ] [
- [ { integer } declare bitnot ] final-classes
-] unit-test
+[ integer ] [ [ { fixnum integer } declare + ] final-math-class ] unit-test
+
+[ bignum ] [ [ { integer bignum } declare + ] final-math-class ] unit-test
+
+[ integer ] [ [ { fixnum fixnum } declare + ] final-math-class ] unit-test
+
+[ float ] [ [ { float integer } declare + ] final-math-class ] unit-test
+
+[ float ] [ [ { real float } declare + ] final-math-class ] unit-test
+
+[ float ] [ [ { float real } declare + ] final-math-class ] unit-test
+
+[ rational ] [ [ { ratio ratio } declare + ] final-math-class ] unit-test
+
+[ rational ] [ [ { rational ratio } declare + ] final-math-class ] unit-test
+
+[ number ] [ [ { complex complex } declare + ] final-math-class ] unit-test
+
+[ float ] [ [ /f ] final-math-class ] unit-test
+
+[ float ] [ [ { real real } declare /f ] final-math-class ] unit-test
+
+[ integer ] [ [ /i ] final-math-class ] unit-test
+
+[ integer ] [ [ { integer float } declare /i ] final-math-class ] unit-test
+
+[ integer ] [ [ { float float } declare /i ] final-math-class ] unit-test
+
+[ integer ] [ [ { integer } declare bitnot ] final-math-class ] unit-test
+
+[ null ] [ [ { null null } declare + ] final-math-class ] unit-test
+
+[ null ] [ [ { null fixnum } declare + ] final-math-class ] unit-test
+
+[ float ] [ [ { float fixnum } declare + ] final-math-class ] unit-test
+
+[ bignum ] [ [ { bignum bignum } declare bitxor ] final-math-class ] unit-test
+
+[ float ] [ [ { float float } declare mod ] final-math-class ] unit-test
[ V{ integer } ] [ [ 255 bitand ] final-classes ] unit-test
[ { fixnum } declare 615949 * ] final-classes
] unit-test
-[ V{ null } ] [
- [ { null null } declare + ] final-classes
-] unit-test
-
-[ V{ null } ] [
- [ { null fixnum } declare + ] final-classes
-] unit-test
-
-[ V{ float } ] [
- [ { float fixnum } declare + ] final-classes
-] unit-test
-
[ V{ fixnum } ] [
[ 255 bitand >fixnum 3 bitor ] final-classes
] unit-test
[ V{ fixnum } ] [
[
- [ uchar-nth ] 2keep [ uchar-nth ] 2keep uchar-nth
+ { fixnum byte-array } declare
+ [ nth-unsafe ] 2keep [ nth-unsafe ] 2keep nth-unsafe
>r >r 298 * r> 100 * - r> 208 * - 128 + -8 shift
255 min 0 max
] final-classes
] final-classes
] unit-test
-[ V{ float } ] [
- [ { real float } declare + ] final-classes
-] unit-test
-
-[ V{ float } ] [
- [ { float real } declare + ] final-classes
-] unit-test
-
[ V{ fixnum } ] [
[ { fixnum fixnum } declare 7 bitand neg shift ] final-classes
] unit-test
] unit-test
: recursive-test-4 ( i n -- )
- 2dup < [ >r 1+ r> recursive-test-4 ] [ 2drop ] if ; inline recursive
+ 2dup < [ [ 1+ ] dip recursive-test-4 ] [ 2drop ] if ; inline recursive
[ ] [ [ recursive-test-4 ] final-info drop ] unit-test
[ { fixnum integer } declare bitand ] final-classes
] unit-test
-[ V{ float-array } ] [ [| | F{ } ] final-classes ] unit-test
+[ V{ double-array } ] [ [| | double-array{ } ] final-classes ] unit-test
[ V{ t } ] [ [ netbsd unix? ] final-literals ] unit-test
[ V{ array } ] [ [ [ <=> ] sort [ <=> ] sort ] final-classes ] unit-test
+[ V{ float } ] [ [ fsqrt ] final-classes ] unit-test
+
+[ V{ t } ] [ [ { fixnum } declare 10 mod >float -20 > ] final-literals ] unit-test
+
+[ T{ interval f { 0 t } { 127 t } } ] [
+ [ { integer } declare 127 bitand ] final-info first interval>>
+] unit-test
+
+[ V{ bignum } ] [
+ [ { bignum } declare dup 1- bitxor ] final-classes
+] unit-test
+
+[ V{ bignum integer } ] [
+ [ { bignum integer } declare [ shift ] keep ] final-classes
+] unit-test
+
+[ V{ fixnum } ] [
+ [ { fixnum } declare log2 ] final-classes
+] unit-test
+
+[ V{ word } ] [
+ [ { fixnum } declare log2 0 >= ] final-classes
+] unit-test
+
! [ V{ string } ] [
! [ dup string? t xor [ "A" throw ] [ ] if ] final-classes
! ] unit-test
H{ } clone copies set
H{ } clone 1array value-infos set
H{ } clone 1array constraints set
+ H{ } clone inlining-count set
dup count-nodes
dup (propagate) ;
M: #recursive propagate-around ( #recursive -- )
constraints [ H{ } clone suffix ] change
[
+ loop-nesting inc
+
constraints [ but-last H{ } clone suffix ] change
child>>
[ first propagate-recursive-phi ]
[ (propagate) ]
tri
+
+ loop-nesting dec
] until-fixed-point ;
: recursive-phi-infos ( node -- infos )
! See http://factorcode.org/license.txt for BSD license.
USING: fry accessors kernel sequences sequences.private assocs words
namespaces classes.algebra combinators classes classes.tuple
-classes.tuple.private continuations arrays
+classes.tuple.private continuations arrays alien.c-types
math math.private slots generic definitions
stack-checker.state
compiler.tree
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 ;
+: propagate-alien-invoke ( node -- )
+ [ out-d>> ] [ params>> return>> ] bi
+ [ drop ] [ c-type-class <class-info> swap first set-value-info ] if-void ;
-M: #alien-indirect propagate-before
- out-d>> [ object-info swap set-value-info ] each ;
+M: #alien-invoke propagate-before propagate-alien-invoke ;
+
+M: #alien-indirect propagate-before propagate-alien-invoke ;
-M: #return annotate-node
- dup in-d>> (annotate-node) ;
+M: #return annotate-node dup in-d>> (annotate-node) ;
UNION: fixed-length-sequence array byte-array string ;
: sequence-constructor? ( word -- ? )
- { <array> <byte-array> <string> } memq? ;
+ { <array> <byte-array> (byte-array) <string> } memq? ;
: constructor-output-class ( word -- class )
{
{ <array> array }
{ <byte-array> byte-array }
+ { (byte-array) byte-array }
{ <string> string }
} at ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: namespaces assocs accessors kernel combinators
-classes.algebra sequences sequences.deep slots.private
+classes.algebra sequences slots.private fry vectors
classes.tuple.private math math.private arrays
stack-checker.branches
+compiler.utilities
compiler.tree
compiler.tree.combinators
compiler.tree.propagation.info
: (expand-#push) ( object value -- nodes )
dup unboxed-allocation dup [
[ object-slots ] [ drop ] [ ] tri*
- [ (expand-#push) ] 2map
+ [ (expand-#push) ] 2map-flat
] [
drop #push
] if ;
: unbox-<complex> ( #call -- nodes )
dup unbox-output? [ drop { } ] when ;
-: (flatten-values) ( values -- values' )
- [ dup unboxed-allocation [ (flatten-values) ] [ ] ?if ] map ;
+: (flatten-values) ( values accum -- )
+ dup '[
+ dup unboxed-allocation
+ [ _ (flatten-values) ] [ _ push ] ?if
+ ] each ;
: flatten-values ( values -- values' )
- dup empty? [ (flatten-values) flatten ] unless ;
+ dup empty? [
+ 10 <vector> [ (flatten-values) ] keep
+ ] unless ;
: prepare-slot-access ( #call -- tuple-values outputs slot-values )
[ in-d>> flatten-values ]
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel sequences sequences.private arrays vectors fry
+math.order ;
+IN: compiler.utilities
+
+: flattener ( seq quot -- seq vector quot' )
+ over length <vector> [
+ dup
+ '[
+ @ [
+ dup array?
+ [ _ push-all ] [ _ push ] if
+ ] when*
+ ]
+ ] keep ; inline
+
+: flattening ( seq quot combinator -- seq' )
+ [ flattener ] dip dip { } like ; inline
+
+: map-flat ( seq quot -- seq' ) [ each ] flattening ; inline
+
+: 2map-flat ( seq quot -- seq' ) [ 2each ] flattening ; inline
+
+: (3each) ( seq1 seq2 seq3 quot -- n quot' )
+ [ [ [ length ] tri@ min min ] 3keep ] dip
+ '[ [ _ nth-unsafe ] [ _ nth-unsafe ] [ _ nth-unsafe ] tri @ ] ; inline
+
+: 3each ( seq1 seq2 seq3 quot -- seq ) (3each) each ; inline
+
+: 3map ( seq1 seq2 seq3 quot -- seq ) (3each) map ; inline
{ $errors "Throws an error if one of the iterations throws an error." } ;\r
\r
ARTICLE: "concurrency.combinators" "Concurrent combinators"\r
-"The " { $vocab-link "concurrency.combinators" } " vocabulary provides concurrent variants of " { $link each } ", " { $link map } " and " { $link filter } ":"\r
+"The " { $vocab-link "concurrency.combinators" } " vocabulary provides concurrent variants of various combinators."\r
+$nl\r
+"Concurrent sequence combinators:"\r
{ $subsection parallel-each }\r
{ $subsection 2parallel-each }\r
{ $subsection parallel-map }\r
{ $subsection 2parallel-map }\r
-{ $subsection parallel-filter } ;\r
+{ $subsection parallel-filter }\r
+"Concurrent cleave combinators:"\r
+{ $subsection parallel-cleave }\r
+{ $subsection parallel-spread }\r
+{ $subsection parallel-napply } ;\r
\r
ABOUT: "concurrency.combinators"\r
IN: concurrency.combinators.tests\r
USING: concurrency.combinators tools.test random kernel math \r
-concurrency.mailboxes threads sequences accessors arrays ;\r
+concurrency.mailboxes threads sequences accessors arrays\r
+math.parser ;\r
\r
[ [ drop ] parallel-each ] must-infer\r
{ 2 0 } [ [ 2drop ] 2parallel-each ] must-infer-as\r
\r
[ { 1 4 9 } ] [ { 1 2 3 } [ sq ] parallel-map ] unit-test\r
\r
-[ { 1 4 9 } ] [ { 1 2 3 } [ 1000 random sleep sq ] parallel-map ] unit-test\r
+[ { 1 4 9 } ] [ { 1 2 3 } [ 1000000 random sleep sq ] parallel-map ] unit-test\r
\r
[ { 1 2 3 } [ dup 2 mod 0 = [ "Even" throw ] when ] parallel-map ]\r
[ error>> "Even" = ] must-fail-with\r
] unit-test\r
\r
[ { f } [ "OOPS" throw ] parallel-each ] must-fail\r
+\r
+[ "1a" "4b" "3c" ] [\r
+ 2\r
+ { [ 1- ] [ sq ] [ 1+ ] } parallel-cleave\r
+ [ number>string ] 3 parallel-napply\r
+ { [ "a" append ] [ "b" append ] [ "c" append ] } parallel-spread\r
+] unit-test\r
! Copyright (C) 2008 Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
USING: concurrency.futures concurrency.count-downs sequences\r
-kernel ;\r
+kernel macros fry combinators generalizations ;\r
IN: concurrency.combinators\r
\r
<PRIVATE\r
+\r
: (parallel-each) ( n quot -- )\r
- >r <count-down> r> keep await ; inline\r
+ [ <count-down> ] dip keep await ; inline\r
+\r
PRIVATE>\r
\r
: parallel-each ( seq quot -- )\r
over length [\r
- [ >r curry r> spawn-stage ] 2curry each\r
+ '[ _ curry _ spawn-stage ] each\r
] (parallel-each) ; inline\r
\r
: 2parallel-each ( seq1 seq2 quot -- )\r
2over min-length [\r
- [ >r 2curry r> spawn-stage ] 2curry 2each\r
+ '[ _ 2curry _ spawn-stage ] 2each\r
] (parallel-each) ; inline\r
\r
: parallel-filter ( seq quot -- newseq )\r
- over >r pusher >r each r> r> like ; inline\r
+ over [ pusher [ parallel-each ] dip ] dip like ; inline\r
\r
<PRIVATE\r
+\r
+: [future] ( quot -- quot' ) '[ _ curry future ] ; inline\r
+\r
: future-values dup [ ?future ] change-each ; inline\r
+\r
PRIVATE>\r
\r
: parallel-map ( seq quot -- newseq )\r
- [ curry future ] curry map future-values ;\r
- inline\r
+ [future] map future-values ; inline\r
\r
: 2parallel-map ( seq1 seq2 quot -- newseq )\r
- [ 2curry future ] curry 2map future-values ;\r
+ '[ _ 2curry future ] 2map future-values ;\r
+\r
+<PRIVATE\r
+\r
+: (parallel-spread) ( n -- spread-array )\r
+ [ ?future ] <repetition> ; inline\r
+\r
+: (parallel-cleave) ( quots -- quot-array spread-array )\r
+ [ [future] ] map dup length (parallel-spread) ; inline\r
+\r
+PRIVATE>\r
+\r
+MACRO: parallel-cleave ( quots -- )\r
+ (parallel-cleave) '[ _ cleave _ spread ] ;\r
+\r
+MACRO: parallel-spread ( quots -- )\r
+ (parallel-cleave) '[ _ spread _ spread ] ;\r
+\r
+MACRO: parallel-napply ( quot n -- )\r
+ [ [future] ] dip dup (parallel-spread) '[ _ _ napply _ spread ] ;\r
! Copyright (C) 2008 Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
-USING: deques threads kernel arrays sequences alarms ;\r
+USING: deques threads kernel arrays sequences alarms fry ;\r
IN: concurrency.conditions\r
\r
: notify-1 ( deque -- )\r
: queue-timeout ( queue timeout -- alarm )\r
#! Add an alarm which removes the current thread from the\r
#! queue, and resumes it, passing it a value of t.\r
- >r [ self swap push-front* ] keep [\r
- [ delete-node ] [ drop node-value ] 2bi\r
- t swap resume-with\r
- ] 2curry r> later ;\r
+ [\r
+ [ self swap push-front* ] keep '[\r
+ _ _\r
+ [ delete-node ] [ drop node-value ] 2bi\r
+ t swap resume-with\r
+ ]\r
+ ] dip later ;\r
\r
: wait ( queue timeout status -- )\r
over [\r
- >r queue-timeout [ drop ] r> suspend\r
+ [ queue-timeout [ drop ] ] dip suspend\r
[ "Timeout" throw ] [ cancel-alarm ] if\r
] [\r
- >r drop [ push-front ] curry r> suspend drop\r
+ [ drop '[ _ push-front ] ] dip suspend drop\r
] if ;\r
! Copyright (C) 2008 Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
USING: dlists kernel math concurrency.promises\r
-concurrency.mailboxes debugger accessors ;\r
+concurrency.mailboxes debugger accessors fry ;\r
IN: concurrency.count-downs\r
\r
! http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CountDownLatch.html\r
[ 1- >>n count-down-check ] if ;\r
\r
: await-timeout ( count-down timeout -- )\r
- >r promise>> r> ?promise-timeout ?linked t assert= ;\r
+ [ promise>> ] dip ?promise-timeout ?linked t assert= ;\r
\r
: await ( count-down -- )\r
f await-timeout ;\r
\r
: spawn-stage ( quot count-down -- )\r
- [ [ count-down ] curry compose ] keep\r
+ [ '[ @ _ count-down ] ] keep\r
"Count down stage"\r
swap promise>> mailbox>> spawn-linked-to drop ;\r
[ ] [
[
- receive first2 >r 3 + r> send
+ receive first2 [ 3 + ] dip send
"thread-a" unregister-process
] "Thread A" spawn
"thread-a" swap register-process
! Copyright (C) 2008 Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
-USING: kernel threads boxes accessors ;\r
+USING: kernel threads boxes accessors fry ;\r
IN: concurrency.exchangers\r
\r
! Motivated by\r
: exchange ( obj exchanger -- newobj )\r
dup thread>> occupied>> [\r
dup object>> box>\r
- >r thread>> box> resume-with r>\r
+ [ thread>> box> resume-with ] dip\r
] [\r
[ object>> >box ] keep\r
- [ thread>> >box ] curry "exchange" suspend\r
+ '[ _ thread>> >box ] "exchange" suspend\r
] if ;\r
IN: concurrency.flags.tests\r
USING: tools.test concurrency.flags concurrency.combinators\r
-kernel threads locals accessors ;\r
+kernel threads locals accessors calendar ;\r
\r
-:: flag-test-1 ( -- )\r
+:: flag-test-1 ( -- val )\r
[let | f [ <flag> ] |\r
[ f raise-flag ] "Flag test" spawn drop\r
f lower-flag\r
\r
:: flag-test-2 ( -- )\r
[let | f [ <flag> ] |\r
- [ 1000 sleep f raise-flag ] "Flag test" spawn drop\r
+ [ 1 seconds sleep f raise-flag ] "Flag test" spawn drop\r
f lower-flag\r
f value>>\r
] ;\r
\r
[ f ] [ flag-test-2 ] unit-test\r
\r
-:: flag-test-3 ( -- )\r
+:: flag-test-3 ( -- val )\r
[let | f [ <flag> ] |\r
f raise-flag\r
f value>>\r
\r
[ t ] [ flag-test-3 ] unit-test\r
\r
-:: flag-test-4 ( -- )\r
+:: flag-test-4 ( -- val )\r
[let | f [ <flag> ] |\r
[ f raise-flag ] "Flag test" spawn drop\r
f wait-for-flag\r
\r
[ t ] [ flag-test-4 ] unit-test\r
\r
-:: flag-test-5 ( -- )\r
+:: flag-test-5 ( -- val )\r
[let | f [ <flag> ] |\r
- [ 1000 sleep f raise-flag ] "Flag test" spawn drop\r
+ [ 1 seconds sleep f raise-flag ] "Flag test" spawn drop\r
f wait-for-flag\r
f value>>\r
] ;\r
\r
[ ] [\r
{ 1 2 } <flag>\r
- [ [ 1000 sleep raise-flag ] curry "Flag test" spawn drop ]\r
+ [ [ 1 seconds sleep raise-flag ] curry "Flag test" spawn drop ]\r
[ [ wait-for-flag drop ] curry parallel-each ] bi\r
] unit-test\r
dup value>> [ drop ] [ t >>value threads>> notify-all ] if ;
: wait-for-flag-timeout ( flag timeout -- )
- over value>> [ 2drop ] [ >r threads>> r> "flag" wait ] if ;
+ over value>> [ 2drop ] [ [ threads>> ] dip "flag" wait ] if ;
: wait-for-flag ( flag -- )
f wait-for-flag-timeout ;
! Copyright (C) 2005, 2008 Chris Double, Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
USING: concurrency.promises concurrency.messaging kernel arrays\r
-continuations help.markup help.syntax quotations ;\r
+continuations help.markup help.syntax quotations calendar ;\r
IN: concurrency.futures\r
\r
HELP: future\r
"The quotation begins with an empty data stack, an empty catch stack, and a name stack containing the global namespace only. This means that the only way to pass data to the quotation is to partially apply the data, for example using " { $link curry } " or " { $link compose } "." } ;\r
\r
HELP: ?future-timeout\r
-{ $values { "future" future } { "timeout" "a timeout in milliseconds or " { $link f } } { "value" object } }\r
-{ $description "Waits for a deferred computation to complete, blocking indefinitely if " { $snippet "timeout" } " is " { $link f } ", otherwise waiting up to " { $snippet "timeout" } " milliseconds." }\r
+{ $values { "future" future } { "timeout" { $maybe duration } } { "value" object } }\r
+{ $description "Waits for a deferred computation to complete, blocking indefinitely if " { $snippet "timeout" } " is " { $link f } ", otherwise waiting up to the " { $snippet "timeout" } " before throwing an error." }\r
{ $errors "Throws an error if the timeout expires before the computation completes. Also throws an error if the future quotation threw an error." } ;\r
\r
HELP: ?future\r
! Copyright (C) 2005, 2008 Chris Double, Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
USING: concurrency.promises concurrency.mailboxes kernel arrays\r
-continuations accessors ;\r
+continuations accessors fry ;\r
IN: concurrency.futures\r
\r
: future ( quot -- future )\r
<promise> [\r
- [ [ >r call r> fulfill ] 2curry "Future" ] keep\r
+ [ '[ @ _ fulfill ] "Future" ] keep\r
mailbox>> spawn-linked-to drop\r
] keep ; inline\r
\r
concurrency.messaging concurrency.mailboxes locals kernel\r
threads sequences calendar accessors ;\r
\r
-:: lock-test-0 ( -- )\r
+:: lock-test-0 ( -- v )\r
[let | v [ V{ } clone ]\r
c [ 2 <count-down> ] |\r
\r
v\r
] ;\r
\r
-:: lock-test-1 ( -- )\r
+:: lock-test-1 ( -- v )\r
[let | v [ V{ } clone ]\r
l [ <lock> ]\r
c [ 2 <count-down> ] |\r
\r
[ ] [ <rw-lock> dup [ [ ] with-read-lock ] with-write-lock ] unit-test\r
\r
-:: rw-lock-test-1 ( -- )\r
+:: rw-lock-test-1 ( -- v )\r
[let | l [ <rw-lock> ]\r
c [ 1 <count-down> ]\r
c' [ 1 <count-down> ]\r
c await\r
l [\r
4 v push\r
- 1000 sleep\r
+ 1 seconds sleep\r
5 v push\r
] with-write-lock\r
c'' count-down\r
\r
[ V{ 1 2 3 4 5 6 } ] [ rw-lock-test-1 ] unit-test\r
\r
-:: rw-lock-test-2 ( -- )\r
+:: rw-lock-test-2 ( -- v )\r
[let | l [ <rw-lock> ]\r
c [ 1 <count-down> ]\r
c' [ 2 <count-down> ]\r
l [\r
1 v push\r
c count-down\r
- 1000 sleep\r
+ 1 seconds sleep\r
2 v push\r
] with-write-lock\r
c' count-down\r
[ V{ 1 2 3 } ] [ rw-lock-test-2 ] unit-test\r
\r
! Test lock timeouts\r
-:: lock-timeout-test ( -- )\r
+:: lock-timeout-test ( -- v )\r
[let | l [ <lock> ] |\r
[\r
l [ 1 seconds sleep ] with-lock\r
thread>> name>> "Lock timeout-er" =\r
] must-fail-with\r
\r
-:: read/write-test ( -- )\r
- [let | l [ <lock> ] |\r
- [\r
- l [ 1 seconds sleep ] with-lock\r
- ] "Lock holder" spawn drop\r
-\r
- [\r
- l 1/10 seconds [ ] with-lock-timeout\r
- ] "Lock timeout-er" spawn-linked drop\r
-\r
- receive\r
- ] ;\r
-\r
[\r
<rw-lock> dup [\r
1 seconds [ ] with-write-lock-timeout\r
! Copyright (C) 2008 Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
USING: deques dlists kernel threads continuations math\r
-concurrency.conditions combinators.short-circuit accessors ;\r
+concurrency.conditions combinators.short-circuit accessors\r
+locals ;\r
IN: concurrency.locks\r
\r
! Simple critical sections\r
\r
: acquire-lock ( lock timeout -- )\r
over owner>>\r
- [ 2dup >r threads>> r> "lock" wait ] when drop\r
+ [ 2dup [ threads>> ] dip "lock" wait ] when drop\r
self >>owner drop ;\r
\r
: release-lock ( lock -- )\r
f >>owner\r
threads>> notify-1 ;\r
\r
-: do-lock ( lock timeout quot acquire release -- )\r
- >r >r pick rot r> call ! use up timeout acquire\r
- swap r> curry [ ] cleanup ; inline\r
+:: do-lock ( lock timeout quot acquire release -- )\r
+ lock timeout acquire call\r
+ quot lock release curry [ ] cleanup ; inline\r
\r
: (with-lock) ( lock timeout quot -- )\r
[ acquire-lock ] [ release-lock ] do-lock ; inline\r
\r
: acquire-read-lock ( lock timeout -- )\r
over writer>>\r
- [ 2dup >r readers>> r> "read lock" wait ] when drop\r
+ [ 2dup [ readers>> ] dip "read lock" wait ] when drop\r
add-reader ;\r
\r
: notify-writer ( lock -- )\r
\r
: acquire-write-lock ( lock timeout -- )\r
over writer>> pick reader#>> 0 > or\r
- [ 2dup >r writers>> r> "write lock" wait ] when drop\r
+ [ 2dup [ writers>> ] dip "write lock" wait ] when drop\r
self >>writer drop ;\r
\r
: release-write-lock ( lock -- )\r
USING: dlists deques threads sequences continuations\r
destructors namespaces math quotations words kernel\r
arrays assocs init system concurrency.conditions accessors\r
-debugger debugger.threads locals ;\r
+debugger debugger.threads locals fry ;\r
\r
TUPLE: mailbox threads data disposed ;\r
\r
[ threads>> notify-all ] bi yield ;\r
\r
: wait-for-mailbox ( mailbox timeout -- )\r
- >r threads>> r> "mailbox" wait ;\r
+ [ threads>> ] dip "mailbox" wait ;\r
\r
:: block-unless-pred ( mailbox timeout pred: ( message -- ? ) -- )\r
mailbox check-disposed\r
f mailbox-get-all-timeout ;\r
\r
: while-mailbox-empty ( mailbox quot -- )\r
- [ [ mailbox-empty? ] curry ] dip [ ] while ; inline\r
+ [ '[ _ mailbox-empty? ] ] dip [ ] while ; inline\r
\r
: mailbox-get-timeout? ( mailbox timeout pred -- obj )\r
[ block-unless-pred ]\r
- [ nip >r data>> r> delete-node-if ]\r
+ [ [ drop data>> ] dip delete-node-if ]\r
3bi ; inline\r
\r
: mailbox-get? ( mailbox pred -- obj )\r
[ <linked-error> ] [ supervisor>> ] bi mailbox-put ;\r
\r
: <linked-thread> ( quot name mailbox -- thread' )\r
- >r linked-thread new-thread r> >>supervisor ;\r
+ [ linked-thread new-thread ] dip >>supervisor ;\r
\r
: spawn-linked-to ( quot name mailbox -- thread )\r
<linked-thread> [ (spawn) ] keep ;\r
{ $values { "message" object }
{ "thread" thread }
}
-{ $description "Send the message to the thread by placing it in the threades mailbox. This is an asynchronous operation and will return immediately. The receving thread will act on the message the next time it retrieves that item from its mailbox (usually using the " { $link receive } " word. The message can be any Factor object. For destinations that are instances of remote-thread the message must be a serializable Factor type." }
+{ $description "Send the message to the thread by placing it in the threads mailbox. This is an asynchronous operation and will return immediately. The receving thread will act on the message the next time it retrieves that item from its mailbox (usually using the " { $link receive } " word. The message can be any Factor object. For destinations that are instances of remote-thread the message must be a serializable Factor type." }
{ $see-also receive receive-if } ;
HELP: receive
{ $values { "message" object }
}
-{ $description "Return a message from the current threades mailbox. If the box is empty, suspend the thread until another thread places an item in the mailbox (usually via the " { $link send } " word." }
+{ $description "Return a message from the current threads mailbox. If the box is empty, suspend the thread until another thread places an item in the mailbox (usually via the " { $link send } " word." }
{ $see-also send receive-if } ;
HELP: receive-if
{ $values { "pred" "a predicate with stack effect " { $snippet "( obj -- ? )" } }
{ "message" object }
}
-{ $description "Return the first message from the current threades mailbox that satisfies the predicate. To satisfy the predicate, " { $snippet "pred" } " is called with the item on the stack and the predicate should leave a boolean indicating whether it was satisfied or not. If nothing in the mailbox satisfies the predicate then the thread will block until something does." }
+{ $description "Return the first message from the current threads mailbox that satisfies the predicate. To satisfy the predicate, " { $snippet "pred" } " is called with the item on the stack and the predicate should leave a boolean indicating whether it was satisfied or not. If nothing in the mailbox satisfies the predicate then the thread will block until something does." }
{ $see-also send receive } ;
HELP: spawn-linked
{ "name" string }
{ "thread" thread }
}
-{ $description "Start a thread which runs the given quotation. If that quotation throws an error which is not caught then the error will get propagated to the thread that spawned it. This can be used to set up 'supervisor' threades that restart child threades that crash due to uncaught errors.\n" }
+{ $description "Start a thread which runs the given quotation. If that quotation throws an error which is not caught then the error will get propagated to the thread that spawned it. This can be used to set up 'supervisor' threads that restart child threads that crash due to uncaught errors.\n" }
{ $see-also spawn } ;
ARTICLE: { "concurrency" "messaging" } "Sending and receiving messages"
{ $example
"USING: concurrency.messaging kernel threads ;"
": pong-server ( -- )"
- " receive >r \"pong\" r> reply-synchronous ;"
+ " receive [ \"pong\" ] dip reply-synchronous ;"
"[ pong-server t ] \"pong-server\" spawn-server"
"\"ping\" swap send-synchronous ."
"\"pong\""
ARTICLE: { "concurrency" "exceptions" } "Linked exceptions"
"A thread can handle exceptions using the standard Factor exception handling mechanism. If an exception is uncaught the thread will terminate. For example:"
{ $code "[ 1 0 / \"This will not print\" print ] \"division-by-zero\" spawn" }
-"Processes can be linked so that a parent thread can receive the exception that caused the child thread to terminate. In this way 'supervisor' threades can be created that are notified when child threades terminate and possibly restart them."
+"Processes can be linked so that a parent thread can receive the exception that caused the child thread to terminate. In this way 'supervisor' threads can be created that are notified when child threads terminate and possibly restart them."
{ $subsection spawn-linked }
"This will create a unidirectional link, such that if an uncaught exception causes the child to terminate, the parent thread can catch it:"
{ $code "["
"Exceptions are only raised in the parent when the parent does a " { $link receive } " or " { $link receive-if } ". This is because the exception is sent from the child to the parent as a message." ;
ARTICLE: "concurrency.messaging" "Message-passing concurrency"
-"The " { $vocab-link "concurrency.messaging" } " vocabulary is based upon the style of concurrency used in systems like Erlang and Termite. It is built on top of the standard Factor lightweight thread system."
+"The " { $vocab-link "concurrency.messaging" } " vocabulary is based upon the style of concurrency used in systems like Erlang and Termite. It is built on top of " { $link "threads" } "."
$nl
-"A concurrency oriented program is one in which multiple threades run simultaneously in a single Factor image or across multiple running Factor instances. The threades can communicate with each other by asynchronous message sends."
+"A concurrency-oriented program is one in which multiple threads run simultaneously in a single Factor image or across multiple running Factor instances. The threads can communicate with each other by asynchronous message sends."
$nl
-"Although threades can share data via Factor's mutable data structures it is not recommended to mix shared state with message passing as it can lead to confusing code."
+"Although threads can share data via Factor's mutable data structures it is not recommended to mix shared state with message passing as it can lead to confusing code."
{ $subsection { "concurrency" "messaging" } }
{ $subsection { "concurrency" "synchronous-sends" } }
{ $subsection { "concurrency" "exceptions" } } ;
! Copyright (C) 2005, 2008 Chris Double, Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
-!\r
-! Concurrency library for Factor, based on Erlang/Termite style\r
-! concurrency.\r
USING: kernel threads concurrency.mailboxes continuations\r
-namespaces assocs accessors summary ;\r
+namespaces assocs accessors summary fry ;\r
IN: concurrency.messaging\r
\r
GENERIC: send ( message thread -- )\r
my-mailbox -rot mailbox-get-timeout? ?linked ; inline\r
\r
: rethrow-linked ( error process supervisor -- )\r
- >r <linked-error> r> send ;\r
+ [ <linked-error> ] dip send ;\r
\r
: spawn-linked ( quot name -- thread )\r
my-mailbox spawn-linked-to ;\r
tag>> \ reply boa ;\r
\r
: synchronous-reply? ( response synchronous -- ? )\r
- over reply?\r
- [ >r tag>> r> tag>> = ]\r
- [ 2drop f ] if ;\r
+ over reply? [ [ tag>> ] bi@ = ] [ 2drop f ] if ;\r
\r
ERROR: cannot-send-synchronous-to-self message thread ;\r
\r
dup self eq? [\r
cannot-send-synchronous-to-self\r
] [\r
- >r <synchronous> dup r> send\r
- [ synchronous-reply? ] curry receive-if\r
+ [ <synchronous> dup ] dip send\r
+ '[ _ synchronous-reply? ] receive-if\r
data>>\r
] if ;\r
\r
\r
HELP: ?promise-timeout\r
{ $values { "promise" promise } { "timeout" { $maybe duration } } { "result" object } }\r
-{ $description "Waits for another thread to fulfill a promise, returning immediately if the promise has already been fulfilled. A timeout of " { $link f } " indicates that the thread may block indefinitely, otherwise it will wait up to " { $snippet "timeout" } " milliseconds." }\r
+{ $description "Waits for another thread to fulfill a promise, returning immediately if the promise has already been fulfilled. A timeout of " { $link f } " indicates that the thread may block indefinitely, otherwise it will wait up to the " { $snippet "timeout" } " before throwing an error." }\r
{ $errors "Throws an error if the timeout expires before the promise has been fulfilled." } ;\r
\r
HELP: ?promise\r
] if ;\r
\r
: ?promise-timeout ( promise timeout -- result )\r
- >r mailbox>> r> block-if-empty mailbox-peek ;\r
+ [ mailbox>> ] dip block-if-empty mailbox-peek ;\r
\r
: ?promise ( promise -- result )\r
f ?promise-timeout ;\r
! Copyright (C) 2008 Slava Pestov.\r
! See http://factorcode.org/license.txt for BSD license.\r
USING: dlists kernel threads math concurrency.conditions\r
-continuations accessors summary ;\r
+continuations accessors summary locals fry ;\r
IN: concurrency.semaphores\r
\r
TUPLE: semaphore count threads ;\r
[ 1+ ] change-count\r
threads>> notify-1 ;\r
\r
-: with-semaphore-timeout ( semaphore timeout quot -- )\r
- pick rot acquire-timeout swap\r
- [ release ] curry [ ] cleanup ; inline\r
+:: with-semaphore-timeout ( semaphore timeout quot -- )\r
+ semaphore timeout acquire-timeout\r
+ quot [ semaphore release ] [ ] cleanup ; inline\r
\r
: with-semaphore ( semaphore quot -- )\r
- over acquire swap [ release ] curry [ ] cleanup ; inline\r
+ swap dup acquire '[ _ release ] [ ] cleanup ; inline\r
--- /dev/null
+USING: help.syntax help.markup arrays alien ;
+IN: core-foundation.arrays
+
+HELP: CF>array
+{ $values { "alien" "a " { $snippet "CFArray" } } { "array" "an array of " { $link alien } " instances" } }
+{ $description "Creates a Factor array from a Core Foundation array." } ;
+
+HELP: <CFArray>
+{ $values { "seq" "a sequence of " { $link alien } " instances" } { "alien" "a " { $snippet "CFArray" } } }
+{ $description "Creates a Core Foundation array from a Factor array." } ;
+
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax kernel sequences ;
+IN: core-foundation.arrays
+
+TYPEDEF: void* CFArrayRef
+
+FUNCTION: CFArrayRef CFArrayCreateMutable ( CFAllocatorRef allocator, CFIndex capacity, void* callbacks ) ;
+
+FUNCTION: void* CFArrayGetValueAtIndex ( CFArrayRef array, CFIndex idx ) ;
+
+FUNCTION: void CFArraySetValueAtIndex ( CFArrayRef array, CFIndex index, void* value ) ;
+
+FUNCTION: CFIndex CFArrayGetCount ( CFArrayRef array ) ;
+
+: CF>array ( alien -- array )
+ dup CFArrayGetCount [ CFArrayGetValueAtIndex ] with map ;
+
+: <CFArray> ( seq -- alien )
+ [ f swap length f CFArrayCreateMutable ] keep
+ [ length ] keep
+ [ [ dupd ] dip CFArraySetValueAtIndex ] 2each ;
--- /dev/null
+unportable
+bindings
--- /dev/null
+USING: help.syntax help.markup ;
+IN: core-foundation.bundles
+
+HELP: <CFBundle>
+{ $values { "string" "a pathname string" } { "bundle" "a " { $snippet "CFBundle" } } }
+{ $description "Creates a new " { $snippet "CFBundle" } "." } ;
+
+HELP: load-framework
+{ $values { "name" "a pathname string" } }
+{ $description "Loads a Core Foundation framework." } ;
+
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax kernel sequences core-foundation
+core-foundation.urls ;
+IN: core-foundation.bundles
+
+TYPEDEF: void* CFBundleRef
+
+FUNCTION: CFBundleRef CFBundleCreate ( CFAllocatorRef allocator, CFURLRef bundleURL ) ;
+
+FUNCTION: Boolean CFBundleLoadExecutable ( CFBundleRef bundle ) ;
+
+: <CFBundle> ( string -- bundle )
+ t <CFFileSystemURL> [
+ f swap CFBundleCreate
+ ] keep CFRelease ;
+
+: load-framework ( name -- )
+ dup <CFBundle> [
+ CFBundleLoadExecutable drop
+ ] [
+ "Cannot load bundle named " prepend throw
+ ] ?if ;
--- /dev/null
+unportable
+bindings
USING: alien strings arrays help.markup help.syntax destructors ;
IN: core-foundation
-HELP: CF>array
-{ $values { "alien" "a " { $snippet "CFArray" } } { "array" "an array of " { $link alien } " instances" } }
-{ $description "Creates a Factor array from a Core Foundation array." } ;
-
-HELP: <CFArray>
-{ $values { "seq" "a sequence of " { $link alien } " instances" } { "alien" "a " { $snippet "CFArray" } } }
-{ $description "Creates a Core Foundation array from a Factor array." } ;
-
-HELP: <CFString>
-{ $values { "string" string } { "alien" "a " { $snippet "CFString" } } }
-{ $description "Creates a Core Foundation string from a Factor string." } ;
-
-HELP: CF>string
-{ $values { "alien" "a " { $snippet "CFString" } } { "string" string } }
-{ $description "Creates a Factor string from a Core Foundation string." } ;
-
-HELP: CF>string-array
-{ $values { "alien" "a " { $snippet "CFArray" } " of " { $snippet "CFString" } " instances" } { "seq" string } }
-{ $description "Creates an array of Factor strings from a " { $snippet "CFArray" } " of " { $snippet "CFString" } "s." } ;
-
-HELP: <CFFileSystemURL>
-{ $values { "string" "a pathname string" } { "dir?" "a boolean indicating if the pathname is a directory" } { "url" "a " { $snippet "CFURL" } } }
-{ $description "Creates a new " { $snippet "CFURL" } " pointing to the given local pathname." } ;
-
-HELP: <CFURL>
-{ $values { "string" "a URL string" } { "url" "a " { $snippet "CFURL" } } }
-{ $description "Creates a new " { $snippet "CFURL" } "." } ;
-
-HELP: <CFBundle>
-{ $values { "string" "a pathname string" } { "bundle" "a " { $snippet "CFBundle" } } }
-{ $description "Creates a new " { $snippet "CFBundle" } "." } ;
-
-HELP: load-framework
-{ $values { "name" "a pathname string" } }
-{ $description "Loads a Core Foundation framework." } ;
-
HELP: &CFRelease
{ $values { "alien" "Pointer to a Core Foundation object" } }
{ $description "Marks the given Core Foundation object for unconditional release via " { $link CFRelease } " at the end of the enclosing " { $link with-destructors } " scope." } ;
{ $description "Marks the given Core Foundation object for release via " { $link CFRelease } " in the event of an error at the end of the enclosing " { $link with-destructors } " scope." } ;
{ CFRelease |CFRelease &CFRelease } related-words
-
-ARTICLE: "core-foundation" "Core foundation utilities"
-"The " { $vocab-link "core-foundation" } " vocabulary defines bindings for some frequently-used Core Foundation functions. It also provides some utility words."
-$nl
-"Strings:"
-{ $subsection <CFString> }
-{ $subsection CF>string }
-"Arrays:"
-{ $subsection <CFArray> }
-{ $subsection CF>array }
-{ $subsection CF>string-array }
-"URLs:"
-{ $subsection <CFFileSystemURL> }
-{ $subsection <CFURL> }
-"Frameworks:"
-{ $subsection load-framework }
-"Memory management:"
-{ $subsection &CFRelease }
-{ $subsection |CFRelease } ;
-
-ABOUT: "core-foundation"
! Copyright (C) 2006, 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: alien alien.c-types alien.strings alien.syntax kernel
-math sequences io.encodings.utf16 destructors accessors combinators ;
+USING: alien.syntax destructors accessors kernel ;
IN: core-foundation
-TYPEDEF: void* CFAllocatorRef
-TYPEDEF: void* CFArrayRef
-TYPEDEF: void* CFDataRef
-TYPEDEF: void* CFDictionaryRef
-TYPEDEF: void* CFMutableDictionaryRef
-TYPEDEF: void* CFNumberRef
-TYPEDEF: void* CFBundleRef
-TYPEDEF: void* CFSetRef
-TYPEDEF: void* CFStringRef
-TYPEDEF: void* CFURLRef
-TYPEDEF: void* CFUUIDRef
TYPEDEF: void* CFTypeRef
+
+TYPEDEF: void* CFAllocatorRef
+: kCFAllocatorDefault f ; inline
+
TYPEDEF: bool Boolean
TYPEDEF: long CFIndex
TYPEDEF: int SInt32
TYPEDEF: uint UInt32
TYPEDEF: ulong CFTypeID
+TYPEDEF: UInt32 CFOptionFlags
TYPEDEF: double CFTimeInterval
TYPEDEF: double CFAbsoluteTime
-TYPEDEF: int CFNumberType
-: kCFNumberSInt8Type 1 ; inline
-: kCFNumberSInt16Type 2 ; inline
-: kCFNumberSInt32Type 3 ; inline
-: kCFNumberSInt64Type 4 ; inline
-: kCFNumberFloat32Type 5 ; inline
-: kCFNumberFloat64Type 6 ; inline
-: kCFNumberCharType 7 ; inline
-: kCFNumberShortType 8 ; inline
-: kCFNumberIntType 9 ; inline
-: kCFNumberLongType 10 ; inline
-: kCFNumberLongLongType 11 ; inline
-: kCFNumberFloatType 12 ; inline
-: kCFNumberDoubleType 13 ; inline
-: kCFNumberCFIndexType 14 ; inline
-: kCFNumberNSIntegerType 15 ; inline
-: kCFNumberCGFloatType 16 ; inline
-: kCFNumberMaxType 16 ; inline
-
-TYPEDEF: int CFPropertyListMutabilityOptions
-: kCFPropertyListImmutable 0 ; inline
-: kCFPropertyListMutableContainers 1 ; inline
-: kCFPropertyListMutableContainersAndLeaves 2 ; inline
-
-FUNCTION: CFArrayRef CFArrayCreateMutable ( CFAllocatorRef allocator, CFIndex capacity, void* callbacks ) ;
-
-FUNCTION: void* CFArrayGetValueAtIndex ( CFArrayRef array, CFIndex idx ) ;
-
-FUNCTION: void CFArraySetValueAtIndex ( CFArrayRef array, CFIndex index, void* value ) ;
-
-FUNCTION: CFIndex CFArrayGetCount ( CFArrayRef array ) ;
-
-: kCFURLPOSIXPathStyle 0 ; inline
-: kCFAllocatorDefault f ; inline
-
-FUNCTION: CFURLRef CFURLCreateWithFileSystemPath ( CFAllocatorRef allocator, CFStringRef filePath, int pathStyle, Boolean isDirectory ) ;
-
-FUNCTION: CFURLRef CFURLCreateWithString ( CFAllocatorRef allocator, CFStringRef string, CFURLRef base ) ;
-
-FUNCTION: CFURLRef CFURLCopyFileSystemPath ( CFURLRef url, int pathStyle ) ;
-
-FUNCTION: CFStringRef CFStringCreateWithCharacters ( CFAllocatorRef allocator, wchar_t* cStr, CFIndex numChars ) ;
-
-FUNCTION: CFIndex CFStringGetLength ( CFStringRef theString ) ;
-
-FUNCTION: void CFStringGetCharacters ( void* theString, CFIndex start, CFIndex length, void* buffer ) ;
-
-FUNCTION: CFNumberRef CFNumberCreate ( CFAllocatorRef allocator, CFNumberType theType, void* valuePtr ) ;
-
-FUNCTION: CFDataRef CFDataCreate ( CFAllocatorRef allocator, uchar* bytes, CFIndex length ) ;
-
-FUNCTION: CFBundleRef CFBundleCreate ( CFAllocatorRef allocator, CFURLRef bundleURL ) ;
-
-FUNCTION: Boolean CFBundleLoadExecutable ( CFBundleRef bundle ) ;
-
FUNCTION: CFTypeRef CFRetain ( CFTypeRef cf ) ;
-FUNCTION: void CFRelease ( CFTypeRef cf ) ;
-
-FUNCTION: CFTypeID CFGetTypeID ( CFTypeRef cf ) ;
-
-: CF>array ( alien -- array )
- dup CFArrayGetCount [ CFArrayGetValueAtIndex ] with map ;
-
-: <CFArray> ( seq -- alien )
- [ f swap length f CFArrayCreateMutable ] keep
- [ length ] keep
- [ >r dupd r> CFArraySetValueAtIndex ] 2each ;
-
-: <CFString> ( string -- alien )
- f swap dup length CFStringCreateWithCharacters ;
-
-: CF>string ( alien -- string )
- dup CFStringGetLength 1+ "ushort" <c-array> [
- >r 0 over CFStringGetLength r> CFStringGetCharacters
- ] keep utf16n alien>string ;
-
-: CF>string-array ( alien -- seq )
- CF>array [ CF>string ] map ;
-: <CFStringArray> ( seq -- alien )
- [ <CFString> ] map dup <CFArray> swap [ CFRelease ] each ;
-
-: <CFFileSystemURL> ( string dir? -- url )
- >r <CFString> f over kCFURLPOSIXPathStyle
- r> CFURLCreateWithFileSystemPath swap CFRelease ;
-
-: <CFURL> ( string -- url )
- <CFString>
- [ f swap f CFURLCreateWithString ] keep
- CFRelease ;
-
-: <CFBundle> ( string -- bundle )
- t <CFFileSystemURL> [
- f swap CFBundleCreate
- ] keep CFRelease ;
-
-GENERIC: <CFNumber> ( number -- alien )
-M: integer <CFNumber>
- [ f kCFNumberLongLongType ] dip <longlong> CFNumberCreate ;
-M: float <CFNumber>
- [ f kCFNumberDoubleType ] dip <double> CFNumberCreate ;
-M: t <CFNumber>
- drop f kCFNumberIntType 1 <int> CFNumberCreate ;
-M: f <CFNumber>
- drop f kCFNumberIntType 0 <int> CFNumberCreate ;
-
-: <CFData> ( byte-array -- alien )
- [ f ] dip dup length CFDataCreate ;
-
-: load-framework ( name -- )
- dup <CFBundle> [
- CFBundleLoadExecutable drop
- ] [
- "Cannot load bundle named " prepend throw
- ] ?if ;
+FUNCTION: void CFRelease ( CFTypeRef cf ) ;
TUPLE: CFRelease-destructor alien disposed ;
+
M: CFRelease-destructor dispose* alien>> CFRelease ;
+
: &CFRelease ( alien -- alien )
dup f CFRelease-destructor boa &dispose drop ; inline
+
: |CFRelease ( alien -- alien )
dup f CFRelease-destructor boa |dispose drop ; inline
--- /dev/null
+! Copyright (C) 2008 Joe Groff.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax alien.c-types sequences kernel math ;
+IN: core-foundation.data
+
+TYPEDEF: void* CFDataRef
+TYPEDEF: void* CFDictionaryRef
+TYPEDEF: void* CFMutableDictionaryRef
+TYPEDEF: void* CFNumberRef
+TYPEDEF: void* CFSetRef
+TYPEDEF: void* CFUUIDRef
+
+TYPEDEF: int CFNumberType
+: kCFNumberSInt8Type 1 ; inline
+: kCFNumberSInt16Type 2 ; inline
+: kCFNumberSInt32Type 3 ; inline
+: kCFNumberSInt64Type 4 ; inline
+: kCFNumberFloat32Type 5 ; inline
+: kCFNumberFloat64Type 6 ; inline
+: kCFNumberCharType 7 ; inline
+: kCFNumberShortType 8 ; inline
+: kCFNumberIntType 9 ; inline
+: kCFNumberLongType 10 ; inline
+: kCFNumberLongLongType 11 ; inline
+: kCFNumberFloatType 12 ; inline
+: kCFNumberDoubleType 13 ; inline
+: kCFNumberCFIndexType 14 ; inline
+: kCFNumberNSIntegerType 15 ; inline
+: kCFNumberCGFloatType 16 ; inline
+: kCFNumberMaxType 16 ; inline
+
+TYPEDEF: int CFPropertyListMutabilityOptions
+: kCFPropertyListImmutable 0 ; inline
+: kCFPropertyListMutableContainers 1 ; inline
+: kCFPropertyListMutableContainersAndLeaves 2 ; inline
+
+FUNCTION: CFNumberRef CFNumberCreate ( CFAllocatorRef allocator, CFNumberType theType, void* valuePtr ) ;
+
+FUNCTION: CFDataRef CFDataCreate ( CFAllocatorRef allocator, uchar* bytes, CFIndex length ) ;
+
+FUNCTION: CFTypeID CFGetTypeID ( CFTypeRef cf ) ;
+
+GENERIC: <CFNumber> ( number -- alien )
+
+M: integer <CFNumber>
+ [ f kCFNumberLongLongType ] dip <longlong> CFNumberCreate ;
+
+M: float <CFNumber>
+ [ f kCFNumberDoubleType ] dip <double> CFNumberCreate ;
+
+M: t <CFNumber>
+ drop f kCFNumberIntType 1 <int> CFNumberCreate ;
+
+M: f <CFNumber>
+ drop f kCFNumberIntType 0 <int> CFNumberCreate ;
+
+: <CFData> ( byte-array -- alien )
+ [ f ] dip dup length CFDataCreate ;
--- /dev/null
+unportable
+bindings
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax kernel math.bitwise core-foundation ;
+IN: core-foundation.file-descriptors
+
+TYPEDEF: void* CFFileDescriptorRef
+TYPEDEF: int CFFileDescriptorNativeDescriptor
+TYPEDEF: void* CFFileDescriptorCallBack
+
+FUNCTION: CFFileDescriptorRef CFFileDescriptorCreate (
+ CFAllocatorRef allocator,
+ CFFileDescriptorNativeDescriptor fd,
+ Boolean closeOnInvalidate,
+ CFFileDescriptorCallBack callout,
+ CFFileDescriptorContext* context
+) ;
+
+: kCFFileDescriptorReadCallBack 1 ; inline
+: kCFFileDescriptorWriteCallBack 2 ; inline
+
+FUNCTION: void CFFileDescriptorEnableCallBacks (
+ CFFileDescriptorRef f,
+ CFOptionFlags callBackTypes
+) ;
+
+: enable-all-callbacks ( fd -- )
+ { kCFFileDescriptorReadCallBack kCFFileDescriptorWriteCallBack } flags
+ CFFileDescriptorEnableCallBacks ;
+
+: <CFFileDescriptor> ( fd callback -- handle )
+ [ f swap ] [ t swap ] bi* f CFFileDescriptorCreate
+ [ "CFFileDescriptorCreate failed" throw ] unless* ;
--- /dev/null
+unportable
+bindings
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types alien.strings alien.syntax kernel
math sequences namespaces make assocs init accessors
-continuations combinators core-foundation
-core-foundation.run-loop core-foundation.run-loop.thread
-io.encodings.utf8 destructors ;
+continuations combinators io.encodings.utf8 destructors locals
+arrays specialized-arrays.direct.alien
+specialized-arrays.direct.int specialized-arrays.direct.longlong
+core-foundation core-foundation.run-loop core-foundation.strings ;
IN: core-foundation.fsevents
: kFSEventStreamCreateFlagUseCFTypes 2 ; inline
"FSEventStreamContext" <c-object>
[ set-FSEventStreamContext-info ] keep ;
-: <FSEventStream> ( callback info paths latency flags -- event-stream )
- >r >r >r >r >r
+:: <FSEventStream> ( callback info paths latency flags -- event-stream )
f ! allocator
- r> ! callback
- r> make-FSEventStreamContext
- r> <CFStringArray> ! paths
+ callback
+ info make-FSEventStreamContext
+ paths <CFStringArray>
FSEventStreamEventIdSinceNow ! sinceWhen
- r> ! latency
- r> ! flags
+ latency
+ flags
FSEventStreamCreate ;
: kCFRunLoopCommonModes ( -- string )
- "kCFRunLoopCommonModes" f dlsym *void* ;
+ &: kCFRunLoopCommonModes *void* ;
: schedule-event-stream ( event-stream -- )
CFRunLoopGetMain
: remove-event-source-callback ( id -- )
event-stream-callbacks get delete-at ;
-: >event-triple ( n eventPaths eventFlags eventIds -- triple )
- [
- >r >r >r dup dup
- r> void*-nth utf8 alien>string ,
- r> int-nth ,
- r> longlong-nth ,
- ] { } make ;
+:: (master-event-source-callback) ( eventStream info numEvents eventPaths eventFlags eventIds -- )
+ eventPaths numEvents <direct-void*-array> [ utf8 alien>string ] { } map-as
+ eventFlags numEvents <direct-int-array>
+ eventIds numEvents <direct-longlong-array>
+ 3array flip
+ info event-stream-callbacks get at [ drop ] or call ;
: master-event-source-callback ( -- alien )
"void"
"FSEventStreamEventFlags*"
"FSEventStreamEventId*"
}
- "cdecl" [
- [ >event-triple ] 3curry map
- swap event-stream-callbacks get at
- dup [ call drop ] [ 3drop ] if
- ] alien-callback ;
+ "cdecl" [ (master-event-source-callback) ] alien-callback ;
TUPLE: event-stream info handle disposed ;
: <event-stream> ( quot paths latency flags -- event-stream )
- >r >r >r
- add-event-source-callback dup
- >r master-event-source-callback r>
- r> r> r> <FSEventStream>
+ [
+ add-event-source-callback dup
+ [ master-event-source-callback ] dip
+ ] 3dip <FSEventStream>
dup enable-event-stream
f event-stream boa ;
! Copyright (C) 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.syntax kernel threads init namespaces alien
-core-foundation ;
+USING: alien alien.syntax kernel namespaces core-foundation
+core-foundation.strings core-foundation.file-descriptors
+core-foundation.timers ;
IN: core-foundation.run-loop
: kCFRunLoopRunFinished 1 ; inline
: kCFRunLoopRunHandledSource 4 ; inline
TYPEDEF: void* CFRunLoopRef
+TYPEDEF: void* CFRunLoopSourceRef
FUNCTION: CFRunLoopRef CFRunLoopGetMain ( ) ;
FUNCTION: CFRunLoopRef CFRunLoopGetCurrent ( ) ;
Boolean returnAfterSourceHandled
) ;
+FUNCTION: CFRunLoopSourceRef CFFileDescriptorCreateRunLoopSource (
+ CFAllocatorRef allocator,
+ CFFileDescriptorRef f,
+ CFIndex order
+) ;
+
+FUNCTION: void CFRunLoopAddSource (
+ CFRunLoopRef rl,
+ CFRunLoopSourceRef source,
+ CFStringRef mode
+) ;
+
+FUNCTION: void CFRunLoopRemoveSource (
+ CFRunLoopRef rl,
+ CFRunLoopSourceRef source,
+ CFStringRef mode
+) ;
+
+FUNCTION: void CFRunLoopAddTimer (
+ CFRunLoopRef rl,
+ CFRunLoopTimerRef timer,
+ CFStringRef mode
+) ;
+
+FUNCTION: void CFRunLoopRemoveTimer (
+ CFRunLoopRef rl,
+ CFRunLoopTimerRef timer,
+ CFStringRef mode
+) ;
+
: CFRunLoopDefaultMode ( -- alien )
#! Ugly, but we don't have static NSStrings
\ CFRunLoopDefaultMode get-global dup expired? [
"kCFRunLoopDefaultMode" <CFString>
dup \ CFRunLoopDefaultMode set-global
] when ;
-
-: run-loop-thread ( -- )
- CFRunLoopDefaultMode 0 f CFRunLoopRunInMode
- kCFRunLoopRunHandledSource = [ 1000 sleep ] unless
- run-loop-thread ;
-
-: start-run-loop-thread ( -- )
- [ run-loop-thread t ] "CFRunLoop dispatcher" spawn-server drop ;
+++ /dev/null
-Slava Pestov
+++ /dev/null
-Vocabulary with init hook for running CoreFoundation event loop
+++ /dev/null
-unportable
+++ /dev/null
-! Copyright (C) 2008 Slava Pestov
-! See http://factorcode.org/license.txt for BSD license.
-USING: init core-foundation.run-loop ;
-IN: core-foundation.run-loop.thread
-
-! Load this vocabulary if you need a run loop running.
-
-[ start-run-loop-thread ] "core-foundation.run-loop.thread" add-init-hook
--- /dev/null
+USING: help.syntax help.markup strings ;
+IN: core-foundation.strings
+
+HELP: <CFString>
+{ $values { "string" string } { "alien" "a " { $snippet "CFString" } } }
+{ $description "Creates a Core Foundation string from a Factor string." } ;
+
+HELP: CF>string
+{ $values { "alien" "a " { $snippet "CFString" } } { "string" string } }
+{ $description "Creates a Factor string from a Core Foundation string." } ;
+
+HELP: CF>string-array
+{ $values { "alien" "a " { $snippet "CFArray" } " of " { $snippet "CFString" } " instances" } { "seq" string } }
+{ $description "Creates an array of Factor strings from a " { $snippet "CFArray" } " of " { $snippet "CFString" } "s." } ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: core-foundation.strings core-foundation tools.test kernel ;
+IN: core-foundation
+
+[ ] [ "Hello" <CFString> CFRelease ] unit-test
+[ "Hello" ] [ "Hello" <CFString> [ CF>string ] [ CFRelease ] bi ] unit-test
+[ "Hello\u003456" ] [ "Hello\u003456" <CFString> [ CF>string ] [ CFRelease ] bi ] unit-test
+[ "Hello\u013456" ] [ "Hello\u013456" <CFString> [ CF>string ] [ CFRelease ] bi ] unit-test
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax alien.strings kernel sequences byte-arrays
+io.encodings.utf8 math core-foundation core-foundation.arrays ;
+IN: core-foundation.strings
+
+TYPEDEF: void* CFStringRef
+
+TYPEDEF: int CFStringEncoding
+: kCFStringEncodingMacRoman HEX: 0 ;
+: kCFStringEncodingWindowsLatin1 HEX: 0500 ;
+: kCFStringEncodingISOLatin1 HEX: 0201 ;
+: kCFStringEncodingNextStepLatin HEX: 0B01 ;
+: kCFStringEncodingASCII HEX: 0600 ;
+: kCFStringEncodingUnicode HEX: 0100 ;
+: kCFStringEncodingUTF8 HEX: 08000100 ;
+: kCFStringEncodingNonLossyASCII HEX: 0BFF ;
+: kCFStringEncodingUTF16 HEX: 0100 ;
+: kCFStringEncodingUTF16BE HEX: 10000100 ;
+: kCFStringEncodingUTF16LE HEX: 14000100 ;
+: kCFStringEncodingUTF32 HEX: 0c000100 ;
+: kCFStringEncodingUTF32BE HEX: 18000100 ;
+: kCFStringEncodingUTF32LE HEX: 1c000100 ;
+
+FUNCTION: CFStringRef CFStringCreateWithBytes (
+ CFAllocatorRef alloc,
+ UInt8* bytes,
+ CFIndex numBytes,
+ CFStringEncoding encoding,
+ Boolean isExternalRepresentation
+) ;
+
+FUNCTION: CFIndex CFStringGetLength ( CFStringRef theString ) ;
+
+FUNCTION: void CFStringGetCharacters ( void* theString, CFIndex start, CFIndex length, void* buffer ) ;
+
+FUNCTION: Boolean CFStringGetCString (
+ CFStringRef theString,
+ char* buffer,
+ CFIndex bufferSize,
+ CFStringEncoding encoding
+) ;
+
+FUNCTION: CFStringRef CFStringCreateWithCString (
+ CFAllocatorRef alloc,
+ char* cStr,
+ CFStringEncoding encoding
+) ;
+
+: <CFString> ( string -- alien )
+ f swap utf8 string>alien kCFStringEncodingUTF8 CFStringCreateWithCString
+ [ "CFStringCreateWithCString failed" throw ] unless* ;
+
+: CF>string ( alien -- string )
+ dup CFStringGetLength 4 * 1 + <byte-array> [
+ dup length
+ kCFStringEncodingUTF8
+ CFStringGetCString
+ [ "CFStringGetCString failed" throw ] unless
+ ] keep utf8 alien>string ;
+
+: CF>string-array ( alien -- seq )
+ CF>array [ CF>string ] map ;
+
+: <CFStringArray> ( seq -- alien )
+ [ <CFString> ] map [ <CFArray> ] [ [ CFRelease ] each ] bi ;
--- /dev/null
+unportable
+bindings
--- /dev/null
+unportable
+bindings
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax system math kernel core-foundation ;
+IN: core-foundation.timers
+
+TYPEDEF: void* CFRunLoopTimerRef
+TYPEDEF: void* CFRunLoopTimerCallBack
+TYPEDEF: void* CFRunLoopTimerContext
+
+FUNCTION: CFRunLoopTimerRef CFRunLoopTimerCreate (
+ CFAllocatorRef allocator,
+ CFAbsoluteTime fireDate,
+ CFTimeInterval interval,
+ CFOptionFlags flags,
+ CFIndex order,
+ CFRunLoopTimerCallBack callout,
+ CFRunLoopTimerContext* context
+) ;
+
+: <CFTimer> ( callback -- timer )
+ [ f millis 1000 /f 60 0 0 ] dip f CFRunLoopTimerCreate ;
+
+FUNCTION: void CFRunLoopTimerInvalidate (
+ CFRunLoopTimerRef timer
+) ;
+
+FUNCTION: void CFRunLoopTimerSetNextFireDate (
+ CFRunLoopTimerRef timer,
+ CFAbsoluteTime fireDate
+) ;
--- /dev/null
+unportable
+bindings
--- /dev/null
+USING: help.syntax help.markup ;
+IN: core-foundation.urls
+
+HELP: <CFFileSystemURL>
+{ $values { "string" "a pathname string" } { "dir?" "a boolean indicating if the pathname is a directory" } { "url" "a " { $snippet "CFURL" } } }
+{ $description "Creates a new " { $snippet "CFURL" } " pointing to the given local pathname." } ;
+
+HELP: <CFURL>
+{ $values { "string" "a URL string" } { "url" "a " { $snippet "CFURL" } } }
+{ $description "Creates a new " { $snippet "CFURL" } "." } ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax kernel core-foundation.strings
+core-foundation ;
+IN: core-foundation.urls
+
+: kCFURLPOSIXPathStyle 0 ; inline
+
+TYPEDEF: void* CFURLRef
+
+FUNCTION: CFURLRef CFURLCreateWithFileSystemPath ( CFAllocatorRef allocator, CFStringRef filePath, int pathStyle, Boolean isDirectory ) ;
+
+FUNCTION: CFURLRef CFURLCreateWithString ( CFAllocatorRef allocator, CFStringRef string, CFURLRef base ) ;
+
+FUNCTION: CFURLRef CFURLCopyFileSystemPath ( CFURLRef url, int pathStyle ) ;
+
+: <CFFileSystemURL> ( string dir? -- url )
+ [ <CFString> f over kCFURLPOSIXPathStyle ] dip
+ CFURLCreateWithFileSystemPath swap CFRelease ;
+
+: <CFURL> ( string -- url )
+ <CFString>
+ [ f swap f CFURLCreateWithString ] keep
+ CFRelease ;
HOOK: %set-slot-imm cpu ( src obj slot tag -- )
HOOK: %string-nth cpu ( dst obj index temp -- )
+HOOK: %set-string-nth-fast cpu ( ch obj index temp -- )
HOOK: %add cpu ( dst src1 src2 -- )
HOOK: %add-imm cpu ( dst src1 src2 -- )
HOOK: %shr-imm cpu ( dst src1 src2 -- )
HOOK: %sar-imm cpu ( dst src1 src2 -- )
HOOK: %not cpu ( dst src -- )
+HOOK: %log2 cpu ( dst src -- )
+
+HOOK: %fixnum-add cpu ( src1 src2 -- )
+HOOK: %fixnum-add-tail cpu ( src1 src2 -- )
+HOOK: %fixnum-sub cpu ( src1 src2 -- )
+HOOK: %fixnum-sub-tail cpu ( src1 src2 -- )
+HOOK: %fixnum-mul cpu ( src1 src2 temp1 temp2 -- )
+HOOK: %fixnum-mul-tail cpu ( src1 src2 temp1 temp2 -- )
HOOK: %integer>bignum cpu ( dst src temp -- )
HOOK: %bignum>integer cpu ( dst src temp -- )
HOOK: %set-alien-float cpu ( ptr value -- )
HOOK: %set-alien-double cpu ( ptr value -- )
+HOOK: %alien-global cpu ( dst symbol library -- )
+
HOOK: %allot cpu ( dst size class temp -- )
HOOK: %write-barrier cpu ( src card# table -- )
HOOK: %gc cpu ( -- )
HOOK: %prologue cpu ( n -- )
HOOK: %epilogue cpu ( n -- )
-HOOK: %compare cpu ( dst cc src1 src2 -- )
-HOOK: %compare-imm cpu ( dst cc src1 src2 -- )
-HOOK: %compare-float cpu ( dst cc src1 src2 -- )
+HOOK: %compare cpu ( dst temp cc src1 src2 -- )
+HOOK: %compare-imm cpu ( dst temp cc src1 src2 -- )
+HOOK: %compare-float cpu ( dst temp cc src1 src2 -- )
HOOK: %compare-branch cpu ( label cc src1 src2 -- )
HOOK: %compare-imm-branch cpu ( label cc src1 src2 -- )
HOOK: small-enough? cpu ( n -- ? )
! Is this structure small enough to be returned in registers?
-HOOK: struct-small-enough? cpu ( heap-size -- ? )
+HOOK: struct-small-enough? cpu ( c-type -- ? )
-! Do we pass value structs by value or hidden reference?
-HOOK: value-structs? cpu ( -- ? )
+! Do we pass this struct by value or hidden reference?
+HOOK: value-struct? cpu ( c-type -- ? )
! If t, all parameters are shadowed by dummy stack parameters
HOOK: dummy-stack-params? cpu ( -- ? )
M: stack-params param-reg drop ;
M: stack-params param-regs drop f ;
-
-: if-small-struct ( n size true false -- ? )
- [ 2dup [ not ] [ struct-small-enough? ] bi* and ] 2dip
- [ '[ nip @ ] ] dip if ;
- inline
-
-: %unbox-struct ( n c-type -- )
- [ %unbox-small-struct ] [ %unbox-large-struct ] if-small-struct ;
-
-: %box-struct ( n c-type -- )
- [ %box-small-struct ] [ %box-large-struct ] if-small-struct ;
\r
[\r
0 6 LOAD32\r
- 6 dup 0 LWZ\r
11 6 profile-count-offset LWZ\r
11 11 1 tag-fixnum ADDI\r
11 6 profile-count-offset STW\r
11 11 compiled-header-size ADDI\r
11 MTCTR\r
BCTR\r
-] rc-absolute-ppc-2/2 rt-literal 1 jit-profiling jit-define\r
+] rc-absolute-ppc-2/2 rt-immediate 1 jit-profiling jit-define\r
\r
[\r
0 6 LOAD32\r
0 1 lr-save stack-frame + STW\r
] rc-absolute-ppc-2/2 rt-label 1 jit-prolog jit-define\r
\r
-[\r
- 0 6 LOAD32\r
- 6 dup 0 LWZ\r
- 6 ds-reg 4 STWU\r
-] rc-absolute-ppc-2/2 rt-literal 1 jit-push-literal jit-define\r
-\r
[\r
0 6 LOAD32\r
6 ds-reg 4 STWU\r
\r
[ 0 B ] rc-relative-ppc-3 rt-xt 0 jit-word-jump jit-define\r
\r
-: jit-call-quot ( -- )\r
+[\r
+ 3 ds-reg 0 LWZ\r
+ ds-reg dup 4 SUBI\r
+ 0 3 \ f tag-number CMPI\r
+ 2 BEQ\r
+ 0 B\r
+] rc-relative-ppc-3 rt-xt 4 jit-if-1 jit-define\r
+\r
+[\r
+ 0 B\r
+] rc-relative-ppc-3 rt-xt 0 jit-if-2 jit-define\r
+\r
+: jit-jump-quot ( -- )\r
4 3 quot-xt-offset LWZ\r
4 MTCTR\r
BCTR ;\r
[\r
0 3 LOAD32\r
6 ds-reg 0 LWZ\r
- 0 6 \ f tag-number CMPI\r
- 2 BNE\r
- 3 3 4 ADDI\r
- 3 3 0 LWZ\r
- ds-reg dup 4 SUBI\r
- jit-call-quot\r
-] rc-absolute-ppc-2/2 rt-literal 1 jit-if-jump jit-define\r
-\r
-[\r
- 0 3 LOAD32\r
- 3 3 0 LWZ\r
- 6 ds-reg 0 LWZ\r
6 6 1 SRAWI\r
3 3 6 ADD\r
3 3 array-start-offset LWZ\r
ds-reg dup 4 SUBI\r
- jit-call-quot\r
-] rc-absolute-ppc-2/2 rt-literal 1 jit-dispatch jit-define\r
+ jit-jump-quot\r
+] rc-absolute-ppc-2/2 rt-immediate 1 jit-dispatch jit-define\r
+\r
+: jit->r ( -- )\r
+ 4 ds-reg 0 LWZ\r
+ ds-reg dup 4 SUBI\r
+ 4 rs-reg 4 STWU ;\r
+\r
+: jit-2>r ( -- )\r
+ 4 ds-reg 0 LWZ\r
+ 5 ds-reg -4 LWZ\r
+ ds-reg dup 8 SUBI\r
+ rs-reg dup 8 ADDI\r
+ 4 rs-reg 0 STW\r
+ 5 rs-reg -4 STW ;\r
+\r
+: jit-3>r ( -- )\r
+ 4 ds-reg 0 LWZ\r
+ 5 ds-reg -4 LWZ\r
+ 6 ds-reg -8 LWZ\r
+ ds-reg dup 12 SUBI\r
+ rs-reg dup 12 ADDI\r
+ 4 rs-reg 0 STW\r
+ 5 rs-reg -4 STW\r
+ 6 rs-reg -8 STW ;\r
+\r
+: jit-r> ( -- )\r
+ 4 rs-reg 0 LWZ\r
+ rs-reg dup 4 SUBI\r
+ 4 ds-reg 4 STWU ;\r
+\r
+: jit-2r> ( -- )\r
+ 4 rs-reg 0 LWZ\r
+ 5 rs-reg -4 LWZ\r
+ rs-reg dup 8 SUBI\r
+ ds-reg dup 8 ADDI\r
+ 4 ds-reg 0 STW\r
+ 5 ds-reg -4 STW ;\r
+\r
+: jit-3r> ( -- )\r
+ 4 rs-reg 0 LWZ\r
+ 5 rs-reg -4 LWZ\r
+ 6 rs-reg -8 LWZ\r
+ rs-reg dup 12 SUBI\r
+ ds-reg dup 12 ADDI\r
+ 4 ds-reg 0 STW\r
+ 5 ds-reg -4 STW\r
+ 6 ds-reg -8 STW ;\r
+\r
+[\r
+ jit->r\r
+ 0 BL\r
+ jit-r>\r
+] rc-relative-ppc-3 rt-xt 3 jit-dip jit-define\r
+\r
+[\r
+ jit-2>r\r
+ 0 BL\r
+ jit-2r>\r
+] rc-relative-ppc-3 rt-xt 6 jit-2dip jit-define\r
+\r
+[\r
+ jit-3>r\r
+ 0 BL\r
+ jit-3r>\r
+] rc-relative-ppc-3 rt-xt 8 jit-3dip jit-define\r
\r
[\r
0 1 lr-save stack-frame + LWZ\r
[\r
3 ds-reg 0 LWZ\r
ds-reg dup 4 SUBI\r
- jit-call-quot\r
+ jit-jump-quot\r
] f f f \ (call) define-sub-primitive\r
\r
[\r
4 ds-reg 0 STW\r
] f f f \ -rot define-sub-primitive\r
\r
-[\r
- 3 ds-reg 0 LWZ\r
- ds-reg dup 4 SUBI\r
- 3 rs-reg 4 STWU\r
-] f f f \ >r define-sub-primitive\r
+[ jit->r ] f f f \ >r define-sub-primitive\r
\r
-[\r
- 3 rs-reg 0 LWZ\r
- rs-reg dup 4 SUBI\r
- 3 ds-reg 4 STWU\r
-] f f f \ r> define-sub-primitive\r
+[ jit-r> ] f f f \ r> define-sub-primitive\r
\r
! Comparisons\r
: jit-compare ( insn -- )\r
0 3 LOAD32\r
- 3 3 0 LWZ\r
4 ds-reg 0 LWZ\r
5 ds-reg -4 LWZU\r
5 0 4 CMP\r
3 ds-reg 0 STW ;\r
\r
: define-jit-compare ( insn word -- )\r
- [ [ jit-compare ] curry rc-absolute-ppc-2/2 rt-literal 1 ] dip\r
+ [ [ jit-compare ] curry rc-absolute-ppc-2/2 rt-immediate 1 ] dip\r
define-sub-primitive ;\r
\r
\ BEQ \ eq? define-jit-compare\r
\ BLT \ fixnum< define-jit-compare\r
\r
! Math\r
+[\r
+ 3 ds-reg 0 LWZ\r
+ ds-reg ds-reg 4 SUBI\r
+ 4 ds-reg 0 LWZ\r
+ 3 3 4 OR\r
+ 3 3 tag-mask get ANDI\r
+ \ f tag-number 4 LI\r
+ 0 3 0 CMPI\r
+ 2 BNE\r
+ 1 tag-fixnum 4 LI\r
+ 4 ds-reg 0 STW\r
+] f f f \ both-fixnums? define-sub-primitive\r
+\r
: jit-math ( insn -- )\r
3 ds-reg 0 LWZ\r
4 ds-reg -4 LWZU\r
7 ds-reg 0 STW\r
] f f f \ fixnum-mod define-sub-primitive\r
\r
+[\r
+ 3 ds-reg 0 LWZ\r
+ ds-reg ds-reg 4 SUBI\r
+ 4 ds-reg 0 LWZ\r
+ 5 4 3 DIVW\r
+ 5 5 tag-bits get SLWI\r
+ 5 ds-reg 0 STW\r
+] f f f \ fixnum/i-fast define-sub-primitive\r
+\r
+[\r
+ 3 ds-reg 0 LWZ\r
+ 4 ds-reg -4 LWZ\r
+ 5 4 3 DIVW\r
+ 6 5 3 MULLW\r
+ 7 6 4 SUBF\r
+ 5 5 tag-bits get SLWI\r
+ 5 ds-reg -4 STW\r
+ 7 ds-reg 0 STW\r
+] f f f \ fixnum/mod-fast define-sub-primitive\r
+\r
[\r
3 ds-reg 0 LWZ\r
3 3 1 SRAWI\r
- 4 4 LI\r
- 4 3 4 SUBF\r
- rs-reg 3 4 LWZX\r
+ rs-reg 3 3 LWZX\r
3 ds-reg 0 STW\r
] f f f \ get-local define-sub-primitive\r
\r
M: float-regs param-regs drop { 1 2 3 4 5 6 7 8 } ;
-M: ppc value-structs? f ;
+M: ppc value-struct? drop f ;
M: ppc dummy-stack-params? f ;
M: float-regs param-regs drop { 1 2 3 4 5 6 7 8 9 10 11 12 13 } ;
-M: ppc value-structs? t ;
+M: ppc value-struct? drop t ;
M: ppc dummy-stack-params? t ;
M: ppc %load-immediate ( reg n -- ) swap LOAD ;
-M:: ppc %load-indirect ( reg obj -- )
- 0 reg LOAD32
- obj rc-absolute-ppc-2/2 rel-literal
- reg reg 0 LWZ ;
+M: ppc %load-indirect ( reg obj -- )
+ [ 0 swap LOAD32 ] [ rc-absolute-ppc-2/2 rel-immediate ] bi* ;
+
+M: ppc %alien-global ( register symbol dll -- )
+ [ 0 swap LOAD32 ] 2dip rc-absolute-ppc-2/2 rel-dlsym ;
: ds-reg 29 ; inline
: rs-reg 30 ; inline
"end" define-label
temp src index ADD
dst temp string-offset LBZ
+ 0 dst HEX: 80 CMPI
+ "end" get BLT
temp src string-aux-offset LWZ
- 0 temp \ f tag-number CMPI
- "end" get BEQ
temp temp index ADD
temp temp index ADD
temp temp byte-array-offset LHZ
- temp temp 8 SLWI
- dst dst temp OR
+ temp temp 7 SLWI
+ dst dst temp XOR
"end" resolve-label
] with-scope ;
+M:: ppc %set-string-nth-fast ( ch obj index temp -- )
+ temp obj index ADD
+ ch temp string-offset STB ;
+
M: ppc %add ADD ;
M: ppc %add-imm ADDI ;
M: ppc %sub swap SUBF ;
M: ppc %sar-imm SRAWI ;
M: ppc %not NOT ;
+: %alien-invoke-tail ( func dll -- )
+ [ scratch-reg ] 2dip %alien-global scratch-reg MTCTR BCTR ;
+
+:: exchange-regs ( r1 r2 -- )
+ scratch-reg r1 MR
+ r1 r2 MR
+ r2 scratch-reg MR ;
+
+: ?MR ( r1 r2 -- ) 2dup = [ 2drop ] [ MR ] if ;
+
+:: move>args ( src1 src2 -- )
+ {
+ { [ src1 4 = ] [ 3 src2 ?MR 3 4 exchange-regs ] }
+ { [ src1 3 = ] [ 4 src2 ?MR ] }
+ { [ src2 3 = ] [ 4 src1 ?MR 3 4 exchange-regs ] }
+ { [ src2 4 = ] [ 3 src1 ?MR ] }
+ [ 3 src1 MR 4 src2 MR ]
+ } cond ;
+
+: clear-xer ( -- )
+ 0 0 LI
+ 0 MTXER ; inline
+
+:: overflow-template ( src1 src2 insn func -- )
+ "no-overflow" define-label
+ clear-xer
+ scratch-reg src2 src1 insn call
+ scratch-reg ds-reg 0 STW
+ "no-overflow" get BNO
+ src1 src2 move>args
+ %prepare-alien-invoke
+ func f %alien-invoke
+ "no-overflow" resolve-label ; inline
+
+:: overflow-template-tail ( src1 src2 insn func -- )
+ "overflow" define-label
+ clear-xer
+ scratch-reg src2 src1 insn call
+ "overflow" get BO
+ scratch-reg ds-reg 0 STW
+ BLR
+ "overflow" resolve-label
+ src1 src2 move>args
+ %prepare-alien-invoke
+ func f %alien-invoke-tail ; inline
+
+M: ppc %fixnum-add ( src1 src2 -- )
+ [ ADDO. ] "overflow_fixnum_add" overflow-template ;
+
+M: ppc %fixnum-add-tail ( src1 src2 -- )
+ [ ADDO. ] "overflow_fixnum_add" overflow-template-tail ;
+
+M: ppc %fixnum-sub ( src1 src2 -- )
+ [ SUBFO. ] "overflow_fixnum_subtract" overflow-template ;
+
+M: ppc %fixnum-sub-tail ( src1 src2 -- )
+ [ SUBFO. ] "overflow_fixnum_subtract" overflow-template-tail ;
+
+M:: ppc %fixnum-mul ( src1 src2 temp1 temp2 -- )
+ "no-overflow" define-label
+ clear-xer
+ temp1 src1 tag-bits get SRAWI
+ temp2 temp1 src2 MULLWO.
+ temp2 ds-reg 0 STW
+ "no-overflow" get BNO
+ src2 src2 tag-bits get SRAWI
+ temp1 src2 move>args
+ %prepare-alien-invoke
+ "overflow_fixnum_multiply" f %alien-invoke
+ "no-overflow" resolve-label ;
+
+M:: ppc %fixnum-mul-tail ( src1 src2 temp1 temp2 -- )
+ "overflow" define-label
+ clear-xer
+ temp1 src1 tag-bits get SRAWI
+ temp2 temp1 src2 MULLWO.
+ "overflow" get BO
+ temp2 ds-reg 0 STW
+ BLR
+ "overflow" resolve-label
+ src2 src2 tag-bits get SRAWI
+ temp1 src2 move>args
+ %prepare-alien-invoke
+ "overflow_fixnum_multiply" f %alien-invoke-tail ;
+
: bignum@ ( n -- offset ) cells bignum tag-number - ; inline
M:: ppc %integer>bignum ( dst src temp -- )
M: ppc %set-alien-float swap 0 STFS ;
M: ppc %set-alien-double swap 0 STFD ;
-: %load-dlsym ( symbol dll register -- )
- 0 swap LOAD32 rc-absolute-ppc-2/2 rel-dlsym ;
-
: load-zone-ptr ( reg -- )
- [ "nursery" f ] dip %load-dlsym ;
+ "nursery" f %alien-global ;
: load-allot-ptr ( nursery-ptr allot-ptr -- )
[ drop load-zone-ptr ] [ swap 4 LWZ ] 2bi ;
dst class store-header
dst class store-tagged ;
-: %alien-global ( dst name -- )
- [ f rot %load-dlsym ] [ drop dup 0 LWZ ] 2bi ;
-
: load-cards-offset ( dst -- )
- "cards_offset" %alien-global ;
+ [ "cards_offset" f %alien-global ] [ dup 0 LWZ ] bi ;
: load-decks-offset ( dst -- )
- "decks_offset" %alien-global ;
+ [ "decks_offset" f %alien-global ] [ dup 0 LWZ ] bi ;
M:: ppc %write-barrier ( src card# table -- )
card-mark scratch-reg LI
1 1 rot ADDI
0 MTLR ;
-:: (%boolean) ( dst word -- )
+:: (%boolean) ( dst temp word -- )
"end" define-label
dst \ f tag-number %load-immediate
"end" get word execute
dst \ t %load-indirect
"end" get resolve-label ; inline
-: %boolean ( dst cc -- )
+: %boolean ( dst temp cc -- )
negate-cc {
{ cc< [ \ BLT (%boolean) ] }
{ cc<= [ \ BLE (%boolean) ] }
#! Save Factor stack pointers in case the C code calls a
#! callback which does a GC, which must reliably trace
#! all roots.
- "stack_chain" f 11 %load-dlsym
- 11 11 0 LWZ
- 1 11 0 STW
- ds-reg 11 8 STW
- rs-reg 11 12 STW ;
+ scratch-reg "stack_chain" f %alien-global
+ scratch-reg scratch-reg 0 LWZ
+ 1 scratch-reg 0 STW
+ ds-reg scratch-reg 8 STW
+ rs-reg scratch-reg 12 STW ;
M: ppc %alien-invoke ( symbol dll -- )
- 11 %load-dlsym 11 MTLR BLRL ;
+ [ 11 ] 2dip %alien-global 11 MTLR BLRL ;
M: ppc %alien-callback ( quot -- )
3 swap %load-indirect "c_to_factor" f %alien-invoke ;
M: x86.32 ds-reg ESI ;
M: x86.32 rs-reg EDI ;
M: x86.32 stack-reg ESP ;
-M: x86.32 temp-reg-1 EAX ;
-M: x86.32 temp-reg-2 ECX ;
+M: x86.32 temp-reg-1 ECX ;
+M: x86.32 temp-reg-2 EDX ;
M:: x86.32 %dispatch ( src temp offset -- )
! Load jump table base.
[ align-code ]
bi ;
-M: x86.32 reserved-area-size 0 ;
+! Registers for fastcall
+M: x86.32 param-reg-1 EAX ;
+M: x86.32 param-reg-2 EDX ;
-M: x86.32 %alien-global 0 [] MOV rc-absolute-cell rel-dlsym ;
+M: x86.32 reserved-area-size 0 ;
M: x86.32 %alien-invoke (CALL) rel-dlsym ;
+M: x86.32 %alien-invoke-tail (JMP) rel-dlsym ;
+
M: x86.32 struct-small-enough? ( size -- ? )
heap-size { 1 2 4 8 } member?
os { linux netbsd solaris } member? not and ;
[ [ align-sub ] [ call ] bi* ]
[ [ align-add ] [ drop ] bi* ] 2bi ; inline
-M: x86.32 rel-literal-x86 rc-absolute-cell rel-literal ;
-
M: x86.32 %prologue ( n -- )
dup PUSH
0 PUSH rc-absolute-cell rel-this
: sse2? ( -- ? )
check_sse2 ;
-"-no-sse2" cli-args member? [
+"-no-sse2" (command-line) member? [
[ optimized-recompile-hook ] recompile-hook
[ { check_sse2 } compile ] with-variable
: shift-arg ( -- reg ) ECX ;
: div-arg ( -- reg ) EAX ;
: mod-arg ( -- reg ) EDX ;
-: arg0 ( -- reg ) EAX ;
-: arg1 ( -- reg ) EDX ;
-: temp-reg ( -- reg ) EBX ;
+: arg ( -- reg ) EAX ;
+: temp0 ( -- reg ) EAX ;
+: temp1 ( -- reg ) EDX ;
+: temp2 ( -- reg ) ECX ;
+: temp3 ( -- reg ) EBX ;
: stack-reg ( -- reg ) ESP ;
: ds-reg ( -- reg ) ESI ;
: rs-reg ( -- reg ) EDI ;
-: fixnum>slot@ ( -- ) arg0 1 SAR ;
+: fixnum>slot@ ( -- ) temp0 1 SAR ;
: rex-length ( -- n ) 0 ;
[
- arg0 0 [] MOV ! load stack_chain
- arg0 [] stack-reg MOV ! save stack pointer
+ temp0 0 [] MOV ! load stack_chain
+ temp0 [] stack-reg MOV ! save stack pointer
] rc-absolute-cell rt-stack-chain 2 jit-save-stack jit-define
[
M: x86.64 ds-reg R14 ;
M: x86.64 rs-reg R15 ;
M: x86.64 stack-reg RSP ;
-M: x86.64 temp-reg-1 RAX ;
-M: x86.64 temp-reg-2 RCX ;
M:: x86.64 %dispatch ( src temp offset -- )
! Load jump table base.
[ align-code ]
bi ;
-: param-reg-1 int-regs param-regs first ; inline
-: param-reg-2 int-regs param-regs second ; inline
+M: x86.64 param-reg-1 int-regs param-regs first ;
+M: x86.64 param-reg-2 int-regs param-regs second ;
: param-reg-3 int-regs param-regs third ; inline
M: int-regs return-reg drop RAX ;
M: float-regs return-reg drop XMM0 ;
-M: x86.64 rel-literal-x86 rc-relative rel-literal ;
-
M: x86.64 %prologue ( n -- )
temp-reg-1 0 MOV rc-absolute-cell rel-this
dup PUSH
M: x86.64 %prepare-var-args RAX RAX XOR ;
-M: x86.64 %alien-global
- [ 0 MOV rc-absolute-cell rel-dlsym ] [ dup [] MOV ] bi ;
-
M: x86.64 %alien-invoke
R11 0 MOV
rc-absolute-cell rel-dlsym
R11 CALL ;
+M: x86.64 %alien-invoke-tail
+ R11 0 MOV
+ rc-absolute-cell rel-dlsym
+ R11 JMP ;
+
M: x86.64 %prepare-alien-indirect ( -- )
"unbox_alien" f %alien-invoke
RBP RAX MOV ;
: shift-arg ( -- reg ) RCX ;
: div-arg ( -- reg ) RAX ;
: mod-arg ( -- reg ) RDX ;
-: temp-reg ( -- reg ) RBX ;
+: temp0 ( -- reg ) RDI ;
+: temp1 ( -- reg ) RSI ;
+: temp2 ( -- reg ) RDX ;
+: temp3 ( -- reg ) RBX ;
: stack-reg ( -- reg ) RSP ;
: ds-reg ( -- reg ) R14 ;
: rs-reg ( -- reg ) R15 ;
: rex-length ( -- n ) 1 ;
[
- arg0 0 MOV ! load stack_chain
- arg0 arg0 [] MOV
- arg0 [] stack-reg MOV ! save stack pointer
+ temp0 0 MOV ! load stack_chain
+ temp0 temp0 [] MOV
+ temp0 [] stack-reg MOV ! save stack pointer
] rc-absolute-cell rt-stack-chain 1 rex-length + jit-save-stack jit-define
[
- arg1 0 MOV ! load XT
- arg1 JMP ! go
+ temp1 0 MOV ! load XT
+ temp1 JMP ! go
] rc-absolute-cell rt-primitive 1 rex-length + jit-primitive jit-define
<< "resource:basis/cpu/x86/bootstrap.factor" parse-file parsed >>
IN: bootstrap.x86
: stack-frame-size ( -- n ) 4 bootstrap-cells ;
-: arg0 ( -- reg ) RDI ;
-: arg1 ( -- reg ) RSI ;
+: arg ( -- reg ) RDI ;
<< "resource:basis/cpu/x86/64/bootstrap.factor" parse-file parsed >>
call
M: x86.64 dummy-int-params? f ;
M: x86.64 dummy-fp-params? f ;
+
+M: x86.64 temp-reg-1 R8 ;
+
+M: x86.64 temp-reg-2 R9 ;
IN: bootstrap.x86
: stack-frame-size ( -- n ) 8 bootstrap-cells ;
-: arg0 ( -- reg ) RCX ;
-: arg1 ( -- reg ) RDX ;
+: arg ( -- reg ) RCX ;
<< "resource:basis/cpu/x86/64/bootstrap.factor" parse-file parsed >>
call
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel layouts system math alien.c-types
+USING: kernel layouts system math alien.c-types sequences
compiler.cfg.registers cpu.architecture cpu.x86.assembler cpu.x86 ;
IN: cpu.x86.64.winnt
M: x86.64 reserved-area-size 4 cells ;
-M: x86.64 struct-small-enough? ( size -- ? )
- heap-size cell <= ;
+M: x86.64 struct-small-enough? heap-size { 1 2 4 8 } member? ;
+
+M: x86.64 value-struct? heap-size { 1 2 4 8 } member? ;
M: x86.64 dummy-stack-params? f ;
M: x86.64 dummy-fp-params? t ;
+M: x86.64 temp-reg-1 RAX ;
+
+M: x86.64 temp-reg-2 RCX ;
+
<<
"longlong" "ptrdiff_t" typedef
-"int" "long" typedef
-"uint" "ulong" typedef
+"longlong" "intptr_t" typedef
+"int" c-type "long" define-primitive-type
+"uint" c-type "ulong" define-primitive-type
>>
GENERIC# n, 1 ( value n -- )
M: integer n, >le % ;
-M: byte n, >r value>> r> n, ;
+M: byte n, [ value>> ] dip n, ;
: 1, ( n -- ) 1 n, ; inline
: 4, ( n -- ) 4 n, ; inline
: 2, ( n -- ) 2 n, ; inline
: short-operand ( reg rex.w n -- )
#! Some instructions encode their single operand as part of
#! the opcode.
- >r dupd prefix-1 reg-code r> + , ;
+ [ dupd prefix-1 reg-code ] dip + , ;
: opcode, ( opcode -- ) dup array? [ % ] [ , ] if ;
: 1-operand ( op reg,rex.w,opcode -- )
#! The 'reg' is not really a register, but a value for the
#! 'reg' field of the mod-r/m byte.
- first3 >r >r over r> prefix-1 r> opcode, swap addressing ;
+ first3 [ [ over ] dip prefix-1 ] dip opcode, swap addressing ;
: immediate-operand-size-bit ( imm dst reg,rex.w,opcode -- imm dst reg,rex.w,opcode )
pick integer? [ first3 BIN: 1 opcode-or 3array ] when ;
] if ;
: (2-operand) ( dst src op -- )
- >r 2dup t rex-prefix r> opcode,
+ [ 2dup t rex-prefix ] dip opcode,
reg-code swap addressing ;
: direction-bit ( dst src op -- dst' src' op' )
PRIVATE>
: [] ( reg/displacement -- indirect )
- dup integer? [ >r f f f r> ] [ f f f ] if <indirect> ;
+ dup integer? [ [ f f f ] dip ] [ f f f ] if <indirect> ;
: [+] ( reg displacement -- indirect )
dup integer?
- [ dup zero? [ drop f ] when >r f f r> ]
+ [ dup zero? [ drop f ] when [ f f ] dip ]
[ f f ] if
<indirect> ;
GENERIC: MOV ( dst src -- )
M: immediate MOV swap (MOV-I) ;
-M: callable MOV 0 rot (MOV-I) rc-absolute-cell rel-word ;
+M: callable MOV [ 0 ] 2dip (MOV-I) rc-absolute-cell rel-word ;
M: operand MOV HEX: 88 2-operand ;
: LEA ( dst src -- ) swap HEX: 8d 2-operand ;
! Control flow
GENERIC: JMP ( op -- )
: (JMP) ( -- rel-class ) HEX: e9 , 0 4, rc-relative ;
+M: f JMP (JMP) 2drop ;
M: callable JMP (JMP) rel-word ;
M: label JMP (JMP) label-fixup ;
M: operand JMP { BIN: 100 t HEX: ff } 1-operand ;
GENERIC: CALL ( op -- )
: (CALL) ( -- rel-class ) HEX: e8 , 0 4, rc-relative ;
+M: f CALL (CALL) 2drop ;
M: callable CALL (CALL) rel-word ;
M: label CALL (CALL) label-fixup ;
M: operand CALL { BIN: 010 t HEX: ff } 1-operand ;
GENERIC# JUMPcc 1 ( addr opcode -- )
: (JUMPcc) ( n -- rel-class ) extended-opcode, 0 4, rc-relative ;
+M: f JUMPcc nip (JUMPcc) drop ;
M: callable JUMPcc (JUMPcc) rel-word ;
M: label JUMPcc (JUMPcc) label-fixup ;
: LEAVE ( -- ) HEX: c9 , ;
: RET ( n -- )
- dup zero? [ drop HEX: c3 , ] [ HEX: C2 , 2, ] if ;
+ dup zero? [ drop HEX: c3 , ] [ HEX: c2 , 2, ] if ;
! Arithmetic
: XCHG ( dst src -- ) OCT: 207 2-operand ;
+: BSR ( dst src -- ) swap { HEX: 0f HEX: bd } (2-operand) ;
+
: NOT ( dst -- ) { BIN: 010 t HEX: f7 } 1-operand ;
: NEG ( dst -- ) { BIN: 011 t HEX: f7 } 1-operand ;
: MUL ( dst -- ) { BIN: 100 t HEX: f7 } 1-operand ;
IN: cpu.x86.assembler.syntax
: define-register ( name num size -- )
- >r >r "cpu.x86.assembler" create dup define-symbol r> r>
- >r dupd "register" set-word-prop r>
+ [ "cpu.x86.assembler" create dup define-symbol ] 2dip
+ [ dupd "register" set-word-prop ] dip
"register-size" set-word-prop ;
: define-registers ( names size -- )
[
! Load word
- temp-reg 0 MOV
- temp-reg dup [] MOV
+ temp0 0 MOV
! Bump profiling counter
- temp-reg profile-count-offset [+] 1 tag-fixnum ADD
+ temp0 profile-count-offset [+] 1 tag-fixnum ADD
! Load word->code
- temp-reg temp-reg word-code-offset [+] MOV
+ temp0 temp0 word-code-offset [+] MOV
! Compute word XT
- temp-reg compiled-header-size ADD
+ temp0 compiled-header-size ADD
! Jump to XT
- temp-reg JMP
-] rc-absolute-cell rt-literal 1 rex-length + jit-profiling jit-define
-
-[
- temp-reg 0 MOV ! load XT
- stack-frame-size PUSH ! save stack frame size
- temp-reg PUSH ! push XT
- stack-reg stack-frame-size 3 bootstrap-cells - SUB ! alignment
+ temp0 JMP
+] rc-absolute-cell rt-immediate 1 rex-length + jit-profiling jit-define
+
+[
+ ! load XT
+ temp0 0 MOV
+ ! save stack frame size
+ stack-frame-size PUSH
+ ! push XT
+ temp0 PUSH
+ ! alignment
+ stack-reg stack-frame-size 3 bootstrap-cells - SUB
] rc-absolute-cell rt-label 1 rex-length + jit-prolog jit-define
[
- arg0 0 MOV ! load literal
- arg0 dup [] MOV
- ds-reg bootstrap-cell ADD ! increment datastack pointer
- ds-reg [] arg0 MOV ! store literal on datastack
-] rc-absolute-cell rt-literal 1 rex-length + jit-push-literal jit-define
-
-[
- arg0 0 MOV ! load literal
- ds-reg bootstrap-cell ADD ! increment datastack pointer
- ds-reg [] arg0 MOV ! store literal on datastack
+ ! load literal
+ temp0 0 MOV
+ ! increment datastack pointer
+ ds-reg bootstrap-cell ADD
+ ! store literal on datastack
+ ds-reg [] temp0 MOV
] rc-absolute-cell rt-immediate 1 rex-length + jit-push-immediate jit-define
[
- (JMP) drop
+ f JMP
] rc-relative rt-xt 1 jit-word-jump jit-define
[
- (CALL) drop
+ f CALL
] rc-relative rt-xt 1 jit-word-call jit-define
[
- arg1 0 MOV ! load addr of true quotation
- arg0 ds-reg [] MOV ! load boolean
- ds-reg bootstrap-cell SUB ! pop boolean
- arg0 \ f tag-number CMP ! compare it with f
- arg0 arg1 [] CMOVNE ! load true branch if not equal
- arg0 arg1 bootstrap-cell [+] CMOVE ! load false branch if equal
- arg0 quot-xt-offset [+] JMP ! jump to quotation-xt
-] rc-absolute-cell rt-literal 1 rex-length + jit-if-jump jit-define
+ ! load boolean
+ temp0 ds-reg [] MOV
+ ! pop boolean
+ ds-reg bootstrap-cell SUB
+ ! compare boolean with f
+ temp0 \ f tag-number CMP
+ ! jump to true branch if not equal
+ f JNE
+] rc-relative rt-xt 10 rex-length 3 * + jit-if-1 jit-define
+
+[
+ ! jump to false branch if equal
+ f JMP
+] rc-relative rt-xt 1 jit-if-2 jit-define
+
+[
+ ! load dispatch table
+ temp1 0 MOV
+ ! load index
+ temp0 ds-reg [] MOV
+ ! turn it into an array offset
+ fixnum>slot@
+ ! pop index
+ ds-reg bootstrap-cell SUB
+ ! compute quotation location
+ temp0 temp1 ADD
+ ! load quotation
+ temp0 temp0 array-start-offset [+] MOV
+ ! execute branch
+ temp0 quot-xt-offset [+] JMP
+] rc-absolute-cell rt-immediate 1 rex-length + jit-dispatch jit-define
+
+: jit->r ( -- )
+ rs-reg bootstrap-cell ADD
+ temp0 ds-reg [] MOV
+ ds-reg bootstrap-cell SUB
+ rs-reg [] temp0 MOV ;
+
+: jit-2>r ( -- )
+ rs-reg 2 bootstrap-cells ADD
+ temp0 ds-reg [] MOV
+ temp1 ds-reg -1 bootstrap-cells [+] MOV
+ ds-reg 2 bootstrap-cells SUB
+ rs-reg [] temp0 MOV
+ rs-reg -1 bootstrap-cells [+] temp1 MOV ;
+
+: jit-3>r ( -- )
+ rs-reg 3 bootstrap-cells ADD
+ temp0 ds-reg [] MOV
+ temp1 ds-reg -1 bootstrap-cells [+] MOV
+ temp2 ds-reg -2 bootstrap-cells [+] MOV
+ ds-reg 3 bootstrap-cells SUB
+ rs-reg [] temp0 MOV
+ rs-reg -1 bootstrap-cells [+] temp1 MOV
+ rs-reg -2 bootstrap-cells [+] temp2 MOV ;
+
+: jit-r> ( -- )
+ ds-reg bootstrap-cell ADD
+ temp0 rs-reg [] MOV
+ rs-reg bootstrap-cell SUB
+ ds-reg [] temp0 MOV ;
+
+: jit-2r> ( -- )
+ ds-reg 2 bootstrap-cells ADD
+ temp0 rs-reg [] MOV
+ temp1 rs-reg -1 bootstrap-cells [+] MOV
+ rs-reg 2 bootstrap-cells SUB
+ ds-reg [] temp0 MOV
+ ds-reg -1 bootstrap-cells [+] temp1 MOV ;
+
+: jit-3r> ( -- )
+ ds-reg 3 bootstrap-cells ADD
+ temp0 rs-reg [] MOV
+ temp1 rs-reg -1 bootstrap-cells [+] MOV
+ temp2 rs-reg -2 bootstrap-cells [+] MOV
+ rs-reg 3 bootstrap-cells SUB
+ ds-reg [] temp0 MOV
+ ds-reg -1 bootstrap-cells [+] temp1 MOV
+ ds-reg -2 bootstrap-cells [+] temp2 MOV ;
+
+[
+ jit->r
+ f CALL
+ jit-r>
+] rc-relative rt-xt 11 rex-length 4 * + jit-dip jit-define
[
- arg1 0 MOV ! load dispatch table
- arg1 dup [] MOV
- arg0 ds-reg [] MOV ! load index
- fixnum>slot@ ! turn it into an array offset
- ds-reg bootstrap-cell SUB ! pop index
- arg0 arg1 ADD ! compute quotation location
- arg0 arg0 array-start-offset [+] MOV ! load quotation
- arg0 quot-xt-offset [+] JMP ! execute branch
-] rc-absolute-cell rt-literal 1 rex-length + jit-dispatch jit-define
+ jit-2>r
+ f CALL
+ jit-2r>
+] rc-relative rt-xt 17 rex-length 6 * + jit-2dip jit-define
[
- stack-reg stack-frame-size bootstrap-cell - ADD ! unwind stack frame
+ jit-3>r
+ f CALL
+ jit-3r>
+] rc-relative rt-xt 23 rex-length 8 * + jit-3dip jit-define
+
+[
+ ! unwind stack frame
+ stack-reg stack-frame-size bootstrap-cell - ADD
] f f f jit-epilog jit-define
[ 0 RET ] f f f jit-return jit-define
! Quotations and words
[
- arg0 ds-reg [] MOV ! load from stack
- ds-reg bootstrap-cell SUB ! pop stack
- arg0 quot-xt-offset [+] JMP ! call quotation
+ ! load from stack
+ arg ds-reg [] MOV
+ ! pop stack
+ ds-reg bootstrap-cell SUB
+ ! call quotation
+ arg quot-xt-offset [+] JMP
] f f f \ (call) define-sub-primitive
[
- arg0 ds-reg [] MOV ! load from stack
- ds-reg bootstrap-cell SUB ! pop stack
- arg0 word-xt-offset [+] JMP ! execute word
+ ! load from stack
+ temp0 ds-reg [] MOV
+ ! pop stack
+ ds-reg bootstrap-cell SUB
+ ! execute word
+ temp0 word-xt-offset [+] JMP
] f f f \ (execute) define-sub-primitive
! Objects
[
- arg1 ds-reg [] MOV ! load from stack
- arg1 tag-mask get AND ! compute tag
- arg1 tag-bits get SHL ! tag the tag
- ds-reg [] arg1 MOV ! push to stack
+ ! load from stack
+ temp0 ds-reg [] MOV
+ ! compute tag
+ temp0 tag-mask get AND
+ ! tag the tag
+ temp0 tag-bits get SHL
+ ! push to stack
+ ds-reg [] temp0 MOV
] f f f \ tag define-sub-primitive
[
- arg0 ds-reg [] MOV ! load slot number
- ds-reg bootstrap-cell SUB ! adjust stack pointer
- arg1 ds-reg [] MOV ! load object
- fixnum>slot@ ! turn slot number into offset
- arg1 tag-bits get SHR ! mask off tag
- arg1 tag-bits get SHL
- arg0 arg1 arg0 [+] MOV ! load slot value
- ds-reg [] arg0 MOV ! push to stack
+ ! load slot number
+ temp0 ds-reg [] MOV
+ ! adjust stack pointer
+ ds-reg bootstrap-cell SUB
+ ! load object
+ temp1 ds-reg [] MOV
+ ! turn slot number into offset
+ fixnum>slot@
+ ! mask off tag
+ temp1 tag-bits get SHR
+ temp1 tag-bits get SHL
+ ! load slot value
+ temp0 temp1 temp0 [+] MOV
+ ! push to stack
+ ds-reg [] temp0 MOV
] f f f \ slot define-sub-primitive
! Shufflers
] f f f \ 3drop define-sub-primitive
[
- arg0 ds-reg [] MOV
+ temp0 ds-reg [] MOV
ds-reg bootstrap-cell ADD
- ds-reg [] arg0 MOV
+ ds-reg [] temp0 MOV
] f f f \ dup define-sub-primitive
[
- arg0 ds-reg [] MOV
- arg1 ds-reg bootstrap-cell neg [+] MOV
+ temp0 ds-reg [] MOV
+ temp1 ds-reg bootstrap-cell neg [+] MOV
ds-reg 2 bootstrap-cells ADD
- ds-reg [] arg0 MOV
- ds-reg bootstrap-cell neg [+] arg1 MOV
+ ds-reg [] temp0 MOV
+ ds-reg bootstrap-cell neg [+] temp1 MOV
] f f f \ 2dup define-sub-primitive
[
- arg0 ds-reg [] MOV
- arg1 ds-reg -1 bootstrap-cells [+] MOV
- temp-reg ds-reg -2 bootstrap-cells [+] MOV
+ temp0 ds-reg [] MOV
+ temp1 ds-reg -1 bootstrap-cells [+] MOV
+ temp3 ds-reg -2 bootstrap-cells [+] MOV
ds-reg 3 bootstrap-cells ADD
- ds-reg [] arg0 MOV
- ds-reg -1 bootstrap-cells [+] arg1 MOV
- ds-reg -2 bootstrap-cells [+] temp-reg MOV
+ ds-reg [] temp0 MOV
+ ds-reg -1 bootstrap-cells [+] temp1 MOV
+ ds-reg -2 bootstrap-cells [+] temp3 MOV
] f f f \ 3dup define-sub-primitive
[
- arg0 ds-reg [] MOV
+ temp0 ds-reg [] MOV
ds-reg bootstrap-cell SUB
- ds-reg [] arg0 MOV
+ ds-reg [] temp0 MOV
] f f f \ nip define-sub-primitive
[
- arg0 ds-reg [] MOV
+ temp0 ds-reg [] MOV
ds-reg 2 bootstrap-cells SUB
- ds-reg [] arg0 MOV
+ ds-reg [] temp0 MOV
] f f f \ 2nip define-sub-primitive
[
- arg0 ds-reg -1 bootstrap-cells [+] MOV
+ temp0 ds-reg -1 bootstrap-cells [+] MOV
ds-reg bootstrap-cell ADD
- ds-reg [] arg0 MOV
+ ds-reg [] temp0 MOV
] f f f \ over define-sub-primitive
[
- arg0 ds-reg -2 bootstrap-cells [+] MOV
+ temp0 ds-reg -2 bootstrap-cells [+] MOV
ds-reg bootstrap-cell ADD
- ds-reg [] arg0 MOV
+ ds-reg [] temp0 MOV
] f f f \ pick define-sub-primitive
[
- arg0 ds-reg [] MOV
- arg1 ds-reg -1 bootstrap-cells [+] MOV
- ds-reg [] arg1 MOV
+ temp0 ds-reg [] MOV
+ temp1 ds-reg -1 bootstrap-cells [+] MOV
+ ds-reg [] temp1 MOV
ds-reg bootstrap-cell ADD
- ds-reg [] arg0 MOV
+ ds-reg [] temp0 MOV
] f f f \ dupd define-sub-primitive
[
- arg0 ds-reg [] MOV
- arg1 ds-reg -1 bootstrap-cells [+] MOV
+ temp0 ds-reg [] MOV
+ temp1 ds-reg -1 bootstrap-cells [+] MOV
ds-reg bootstrap-cell ADD
- ds-reg [] arg0 MOV
- ds-reg -1 bootstrap-cells [+] arg1 MOV
- ds-reg -2 bootstrap-cells [+] arg0 MOV
+ ds-reg [] temp0 MOV
+ ds-reg -1 bootstrap-cells [+] temp1 MOV
+ ds-reg -2 bootstrap-cells [+] temp0 MOV
] f f f \ tuck define-sub-primitive
[
- arg0 ds-reg [] MOV
- arg1 ds-reg bootstrap-cell neg [+] MOV
- ds-reg bootstrap-cell neg [+] arg0 MOV
- ds-reg [] arg1 MOV
+ temp0 ds-reg [] MOV
+ temp1 ds-reg bootstrap-cell neg [+] MOV
+ ds-reg bootstrap-cell neg [+] temp0 MOV
+ ds-reg [] temp1 MOV
] f f f \ swap define-sub-primitive
[
- arg0 ds-reg -1 bootstrap-cells [+] MOV
- arg1 ds-reg -2 bootstrap-cells [+] MOV
- ds-reg -2 bootstrap-cells [+] arg0 MOV
- ds-reg -1 bootstrap-cells [+] arg1 MOV
+ temp0 ds-reg -1 bootstrap-cells [+] MOV
+ temp1 ds-reg -2 bootstrap-cells [+] MOV
+ ds-reg -2 bootstrap-cells [+] temp0 MOV
+ ds-reg -1 bootstrap-cells [+] temp1 MOV
] f f f \ swapd define-sub-primitive
[
- arg0 ds-reg [] MOV
- arg1 ds-reg -1 bootstrap-cells [+] MOV
- temp-reg ds-reg -2 bootstrap-cells [+] MOV
- ds-reg -2 bootstrap-cells [+] arg1 MOV
- ds-reg -1 bootstrap-cells [+] arg0 MOV
- ds-reg [] temp-reg MOV
+ temp0 ds-reg [] MOV
+ temp1 ds-reg -1 bootstrap-cells [+] MOV
+ temp3 ds-reg -2 bootstrap-cells [+] MOV
+ ds-reg -2 bootstrap-cells [+] temp1 MOV
+ ds-reg -1 bootstrap-cells [+] temp0 MOV
+ ds-reg [] temp3 MOV
] f f f \ rot define-sub-primitive
[
- arg0 ds-reg [] MOV
- arg1 ds-reg -1 bootstrap-cells [+] MOV
- temp-reg ds-reg -2 bootstrap-cells [+] MOV
- ds-reg -2 bootstrap-cells [+] arg0 MOV
- ds-reg -1 bootstrap-cells [+] temp-reg MOV
- ds-reg [] arg1 MOV
+ temp0 ds-reg [] MOV
+ temp1 ds-reg -1 bootstrap-cells [+] MOV
+ temp3 ds-reg -2 bootstrap-cells [+] MOV
+ ds-reg -2 bootstrap-cells [+] temp0 MOV
+ ds-reg -1 bootstrap-cells [+] temp3 MOV
+ ds-reg [] temp1 MOV
] f f f \ -rot define-sub-primitive
-[
- rs-reg bootstrap-cell ADD
- arg0 ds-reg [] MOV
- ds-reg bootstrap-cell SUB
- rs-reg [] arg0 MOV
-] f f f \ >r define-sub-primitive
+[ jit->r ] f f f \ >r define-sub-primitive
-[
- ds-reg bootstrap-cell ADD
- arg0 rs-reg [] MOV
- rs-reg bootstrap-cell SUB
- ds-reg [] arg0 MOV
-] f f f \ r> define-sub-primitive
+[ jit-r> ] f f f \ r> define-sub-primitive
! Comparisons
: jit-compare ( insn -- )
- arg1 0 MOV ! load t
- arg1 dup [] MOV
- temp-reg \ f tag-number MOV ! load f
- arg0 ds-reg [] MOV ! load first value
- ds-reg bootstrap-cell SUB ! adjust stack pointer
- ds-reg [] arg0 CMP ! compare with second value
- [ arg1 temp-reg ] dip execute ! move t if true
- ds-reg [] arg1 MOV ! store
- ;
+ ! load t
+ temp3 0 MOV
+ ! load f
+ temp1 \ f tag-number MOV
+ ! load first value
+ temp0 ds-reg [] MOV
+ ! adjust stack pointer
+ ds-reg bootstrap-cell SUB
+ ! compare with second value
+ ds-reg [] temp0 CMP
+ ! move t if true
+ [ temp1 temp3 ] dip execute
+ ! store
+ ds-reg [] temp1 MOV ;
: define-jit-compare ( insn word -- )
- [ [ jit-compare ] curry rc-absolute-cell rt-literal 1 rex-length + ] dip
+ [ [ jit-compare ] curry rc-absolute-cell rt-immediate 1 rex-length + ] dip
define-sub-primitive ;
-\ CMOVNE \ eq? define-jit-compare
-\ CMOVL \ fixnum>= define-jit-compare
-\ CMOVG \ fixnum<= define-jit-compare
-\ CMOVLE \ fixnum> define-jit-compare
-\ CMOVGE \ fixnum< define-jit-compare
+\ CMOVE \ eq? define-jit-compare
+\ CMOVGE \ fixnum>= define-jit-compare
+\ CMOVLE \ fixnum<= define-jit-compare
+\ CMOVG \ fixnum> define-jit-compare
+\ CMOVL \ fixnum< define-jit-compare
! Math
: jit-math ( insn -- )
- arg0 ds-reg [] MOV ! load second input
- ds-reg bootstrap-cell SUB ! pop stack
- [ ds-reg [] arg0 ] dip execute ! compute result
- ;
+ ! load second input
+ temp0 ds-reg [] MOV
+ ! pop stack
+ ds-reg bootstrap-cell SUB
+ ! compute result
+ [ ds-reg [] temp0 ] dip execute ;
[ \ ADD jit-math ] f f f \ fixnum+fast define-sub-primitive
[ \ SUB jit-math ] f f f \ fixnum-fast define-sub-primitive
[
- arg0 ds-reg [] MOV ! load second input
- ds-reg bootstrap-cell SUB ! pop stack
- arg1 ds-reg [] MOV ! load first input
- arg0 tag-bits get SAR ! untag second input
- arg0 arg1 IMUL2 ! multiply
- ds-reg [] arg1 MOV ! push result
+ ! load second input
+ temp0 ds-reg [] MOV
+ ! pop stack
+ ds-reg bootstrap-cell SUB
+ ! load first input
+ temp1 ds-reg [] MOV
+ ! untag second input
+ temp0 tag-bits get SAR
+ ! multiply
+ temp0 temp1 IMUL2
+ ! push result
+ ds-reg [] temp1 MOV
] f f f \ fixnum*fast define-sub-primitive
[ \ AND jit-math ] f f f \ fixnum-bitand define-sub-primitive
[ \ XOR jit-math ] f f f \ fixnum-bitxor define-sub-primitive
[
- ds-reg [] NOT ! complement
- ds-reg [] tag-mask get XOR ! clear tag bits
+ ! complement
+ ds-reg [] NOT
+ ! clear tag bits
+ ds-reg [] tag-mask get XOR
] f f f \ fixnum-bitnot define-sub-primitive
[
- shift-arg ds-reg [] MOV ! load shift count
- shift-arg tag-bits get SAR ! untag shift count
- ds-reg bootstrap-cell SUB ! adjust stack pointer
- temp-reg ds-reg [] MOV ! load value
- arg1 temp-reg MOV ! make a copy
- arg1 CL SHL ! compute positive shift value in arg1
- shift-arg NEG ! compute negative shift value in arg0
- temp-reg CL SAR
- temp-reg tag-mask get bitnot AND
- shift-arg 0 CMP ! if shift count was negative, move arg0 to arg1
- arg1 temp-reg CMOVGE
- ds-reg [] arg1 MOV ! push to stack
+ ! load shift count
+ shift-arg ds-reg [] MOV
+ ! untag shift count
+ shift-arg tag-bits get SAR
+ ! adjust stack pointer
+ ds-reg bootstrap-cell SUB
+ ! load value
+ temp3 ds-reg [] MOV
+ ! make a copy
+ temp1 temp3 MOV
+ ! compute positive shift value in temp1
+ temp1 CL SHL
+ shift-arg NEG
+ ! compute negative shift value in temp3
+ temp3 CL SAR
+ temp3 tag-mask get bitnot AND
+ shift-arg 0 CMP
+ ! if shift count was negative, move temp0 to temp1
+ temp1 temp3 CMOVGE
+ ! push to stack
+ ds-reg [] temp1 MOV
] f f f \ fixnum-shift-fast define-sub-primitive
-[
- temp-reg ds-reg [] MOV ! load second parameter
- ds-reg bootstrap-cell SUB ! adjust stack pointer
- div-arg ds-reg [] MOV ! load first parameter
- mod-arg div-arg MOV ! make a copy
- mod-arg bootstrap-cell-bits 1- SAR ! sign-extend
- temp-reg IDIV ! divide
- ds-reg [] mod-arg MOV ! push to stack
+: jit-fixnum-/mod ( -- )
+ ! load second parameter
+ temp3 ds-reg [] MOV
+ ! load first parameter
+ div-arg ds-reg bootstrap-cell neg [+] MOV
+ ! make a copy
+ mod-arg div-arg MOV
+ ! sign-extend
+ mod-arg bootstrap-cell-bits 1- SAR
+ ! divide
+ temp3 IDIV ;
+
+[
+ jit-fixnum-/mod
+ ! adjust stack pointer
+ ds-reg bootstrap-cell SUB
+ ! push to stack
+ ds-reg [] mod-arg MOV
] f f f \ fixnum-mod define-sub-primitive
[
- arg0 ds-reg [] MOV ! load local number
- fixnum>slot@ ! turn local number into offset
- arg1 bootstrap-cell MOV ! load base
- arg1 arg0 SUB ! turn it into a stack offset
- arg0 rs-reg arg1 [+] MOV ! load local value
- ds-reg [] arg0 MOV ! push to stack
+ jit-fixnum-/mod
+ ! adjust stack pointer
+ ds-reg bootstrap-cell SUB
+ ! tag it
+ div-arg tag-bits get SHL
+ ! push to stack
+ ds-reg [] div-arg MOV
+] f f f \ fixnum/i-fast define-sub-primitive
+
+[
+ jit-fixnum-/mod
+ ! tag it
+ div-arg tag-bits get SHL
+ ! push to stack
+ ds-reg [] mod-arg MOV
+ ds-reg bootstrap-cell neg [+] div-arg MOV
+] f f f \ fixnum/mod-fast define-sub-primitive
+
+[
+ temp0 ds-reg [] MOV
+ ds-reg bootstrap-cell SUB
+ temp0 ds-reg [] OR
+ temp0 tag-mask get AND
+ temp0 \ f tag-number MOV
+ temp1 1 tag-fixnum MOV
+ temp0 temp1 CMOVE
+ ds-reg [] temp0 MOV
+] f f f \ both-fixnums? define-sub-primitive
+
+[
+ ! load local number
+ temp0 ds-reg [] MOV
+ ! turn local number into offset
+ fixnum>slot@
+ ! load local value
+ temp0 rs-reg temp0 [+] MOV
+ ! push to stack
+ ds-reg [] temp0 MOV
] f f f \ get-local define-sub-primitive
[
- arg0 ds-reg [] MOV ! load local count
- ds-reg bootstrap-cell SUB ! adjust stack pointer
- fixnum>slot@ ! turn local number into offset
- rs-reg arg0 SUB ! decrement retain stack pointer
+ ! load local count
+ temp0 ds-reg [] MOV
+ ! adjust stack pointer
+ ds-reg bootstrap-cell SUB
+ ! turn local number into offset
+ fixnum>slot@
+ ! decrement retain stack pointer
+ rs-reg temp0 SUB
] f f f \ drop-locals define-sub-primitive
[ "bootstrap.x86" forget-vocab ] with-compilation-unit
kernel kernel.private math memory namespaces make sequences
words system layouts combinators math.order fry locals
compiler.constants compiler.cfg.registers
-compiler.cfg.instructions compiler.codegen
-compiler.codegen.fixup ;
+compiler.cfg.instructions compiler.cfg.intrinsics
+compiler.codegen compiler.codegen.fixup ;
IN: cpu.x86
+<< enable-fixnum-log2 >>
+
M: x86 two-operand? t ;
HOOK: temp-reg-1 cpu ( -- reg )
HOOK: temp-reg-2 cpu ( -- reg )
-M: x86 %load-immediate MOV ;
+HOOK: param-reg-1 cpu ( -- reg )
+HOOK: param-reg-2 cpu ( -- reg )
-HOOK: rel-literal-x86 cpu ( literal -- )
+M: x86 %load-immediate MOV ;
-M: x86 %load-indirect swap 0 [] MOV rel-literal-x86 ;
+M: x86 %load-indirect swap 0 MOV rc-absolute-cell rel-immediate ;
HOOK: ds-reg cpu ( -- reg )
HOOK: rs-reg cpu ( -- reg )
M: x86 %shr-imm nip SHR ;
M: x86 %sar-imm nip SAR ;
M: x86 %not drop NOT ;
+M: x86 %log2 BSR ;
+
+: ?MOV ( dst src -- )
+ 2dup = [ 2drop ] [ MOV ] if ; inline
+
+:: move>args ( src1 src2 -- )
+ {
+ { [ src1 param-reg-2 = ] [ param-reg-1 src2 ?MOV param-reg-1 param-reg-2 XCHG ] }
+ { [ src1 param-reg-1 = ] [ param-reg-2 src2 ?MOV ] }
+ { [ src2 param-reg-1 = ] [ param-reg-2 src1 ?MOV param-reg-1 param-reg-2 XCHG ] }
+ { [ src2 param-reg-2 = ] [ param-reg-1 src1 ?MOV ] }
+ [
+ param-reg-1 src1 MOV
+ param-reg-2 src2 MOV
+ ]
+ } cond ;
+
+HOOK: %alien-invoke-tail cpu ( func dll -- )
+
+:: overflow-template ( src1 src2 insn inverse func -- )
+ <label> "no-overflow" set
+ src1 src2 insn call
+ ds-reg [] src1 MOV
+ "no-overflow" get JNO
+ src1 src2 inverse call
+ src1 src2 move>args
+ %prepare-alien-invoke
+ func f %alien-invoke
+ "no-overflow" resolve-label ; inline
+
+:: overflow-template-tail ( src1 src2 insn inverse func -- )
+ <label> "no-overflow" set
+ src1 src2 insn call
+ "no-overflow" get JNO
+ src1 src2 inverse call
+ src1 src2 move>args
+ %prepare-alien-invoke
+ func f %alien-invoke-tail
+ "no-overflow" resolve-label
+ ds-reg [] src1 MOV
+ 0 RET ; inline
+
+M: x86 %fixnum-add ( src1 src2 -- )
+ [ ADD ] [ SUB ] "overflow_fixnum_add" overflow-template ;
+
+M: x86 %fixnum-add-tail ( src1 src2 -- )
+ [ ADD ] [ SUB ] "overflow_fixnum_add" overflow-template-tail ;
+
+M: x86 %fixnum-sub ( src1 src2 -- )
+ [ SUB ] [ ADD ] "overflow_fixnum_subtract" overflow-template ;
+
+M: x86 %fixnum-sub-tail ( src1 src2 -- )
+ [ SUB ] [ ADD ] "overflow_fixnum_subtract" overflow-template-tail ;
+
+M:: x86 %fixnum-mul ( src1 src2 temp1 temp2 -- )
+ "no-overflow" define-label
+ temp1 src1 MOV
+ temp1 tag-bits get SAR
+ src2 temp1 IMUL2
+ ds-reg [] temp1 MOV
+ "no-overflow" get JNO
+ src1 src2 move>args
+ param-reg-1 tag-bits get SAR
+ param-reg-2 tag-bits get SAR
+ %prepare-alien-invoke
+ "overflow_fixnum_multiply" f %alien-invoke
+ "no-overflow" resolve-label ;
+
+M:: x86 %fixnum-mul-tail ( src1 src2 temp1 temp2 -- )
+ "overflow" define-label
+ temp1 src1 MOV
+ temp1 tag-bits get SAR
+ src2 temp1 IMUL2
+ "overflow" get JO
+ ds-reg [] temp1 MOV
+ 0 RET
+ "overflow" resolve-label
+ src1 src2 move>args
+ param-reg-1 tag-bits get SAR
+ param-reg-2 tag-bits get SAR
+ %prepare-alien-invoke
+ "overflow_fixnum_multiply" f %alien-invoke-tail ;
: bignum@ ( reg n -- op )
cells bignum tag-number - [+] ; inline
M: x86 %integer>float CVTSI2SD ;
M: x86 %float>integer CVTTSD2SI ;
-: ?MOV ( dst src -- )
- 2dup = [ 2drop ] [ MOV ] if ; inline
-
M: x86 %copy ( dst src -- ) ?MOV ;
M: x86 %copy-float ( dst src -- )
M:: x86 %string-nth ( dst src index temp -- )
"end" define-label
dst { src index temp } [| new-dst |
+ ! Load the least significant 7 bits into new-dst.
+ ! 8th bit indicates whether we have to load from
+ ! the aux vector or not.
temp src index [+] LEA
new-dst 1 small-reg temp string-offset [+] MOV
new-dst new-dst 1 small-reg MOVZX
+ ! Do we have to look at the aux vector?
+ new-dst HEX: 80 CMP
+ "end" get JL
+ ! Yes, this is a non-ASCII character. Load aux vector
temp src string-aux-offset [+] MOV
- temp \ f tag-number CMP
- "end" get JE
new-dst temp XCHG
+ ! Compute index
new-dst index ADD
new-dst index ADD
+ ! Load high 16 bits
new-dst 2 small-reg new-dst byte-array-offset [+] MOV
new-dst new-dst 2 small-reg MOVZX
- new-dst 8 SHL
- new-dst temp OR
+ new-dst 7 SHL
+ ! Compute code point
+ new-dst temp XOR
"end" resolve-label
dst new-dst ?MOV
] with-small-register ;
+M:: x86 %set-string-nth-fast ( ch str index temp -- )
+ ch { index str temp } [| new-ch |
+ new-ch ch ?MOV
+ temp str index [+] LEA
+ temp string-offset [+] new-ch 1 small-reg MOV
+ ] with-small-register ;
+
:: %alien-integer-getter ( dst src size quot -- )
dst { src } [| new-dst |
new-dst dup size small-reg dup src [] MOV
dst class store-tagged
nursery-ptr size inc-allot-ptr ;
-HOOK: %alien-global cpu ( symbol dll register -- )
-
M:: x86 %write-barrier ( src card# table -- )
#! Mark the card pointed to by vreg.
! Mark the card
card# src MOV
card# card-bits SHR
- "cards_offset" f table %alien-global
+ table "cards_offset" f %alien-global
+ table table [] MOV
table card# [+] card-mark <byte> MOV
! Mark the card deck
card# deck-bits card-bits - SHR
- "decks_offset" f table %alien-global
+ table "decks_offset" f %alien-global
+ table table [] MOV
table card# [+] card-mark <byte> MOV ;
M: x86 %gc ( -- )
"minor_gc" f %alien-invoke
"end" resolve-label ;
+M: x86 %alien-global
+ [ 0 MOV ] 2dip rc-absolute-cell rel-dlsym ;
+
HOOK: stack-reg cpu ( -- reg )
: decr-stack-reg ( n -- )
M: x86 %epilogue ( n -- ) cell - incr-stack-reg ;
-: %boolean ( dst word -- )
- over \ f tag-number MOV
- 0 [] swap execute
- \ t rel-literal-x86 ; inline
+:: %boolean ( dst temp word -- )
+ dst \ f tag-number MOV
+ temp 0 MOV \ t rc-absolute-cell rel-immediate
+ dst temp word execute ; inline
-M: x86 %compare ( dst cc src1 src2 -- )
+M: x86 %compare ( dst temp cc src1 src2 -- )
CMP {
{ cc< [ \ CMOVL %boolean ] }
{ cc<= [ \ CMOVLE %boolean ] }
{ cc/= [ \ CMOVNE %boolean ] }
} case ;
-M: x86 %compare-imm ( dst cc src1 src2 -- )
+M: x86 %compare-imm ( dst temp cc src1 src2 -- )
%compare ;
-M: x86 %compare-float ( dst cc src1 src2 -- )
+M: x86 %compare-float ( dst temp cc src1 src2 -- )
UCOMISD {
{ cc< [ \ CMOVB %boolean ] }
{ cc<= [ \ CMOVBE %boolean ] }
M: x86 %loop-entry 16 code-alignment [ NOP ] times ;
-M: int-regs %save-param-reg drop >r param@ r> MOV ;
+M: int-regs %save-param-reg drop [ param@ ] dip MOV ;
M: int-regs %load-param-reg drop swap param@ MOV ;
GENERIC: MOVSS/D ( dst src reg-class -- )
M: single-float-regs MOVSS/D drop MOVSS ;
M: double-float-regs MOVSS/D drop MOVSD ;
-M: float-regs %save-param-reg >r >r param@ r> r> MOVSS/D ;
-M: float-regs %load-param-reg >r swap param@ r> MOVSS/D ;
+M: float-regs %save-param-reg [ param@ ] 2dip MOVSS/D ;
+M: float-regs %load-param-reg [ swap param@ ] dip MOVSS/D ;
GENERIC: push-return-reg ( reg-class -- )
GENERIC: load-return-reg ( n reg-class -- )
#! Save Factor stack pointers in case the C code calls a
#! callback which does a GC, which must reliably trace
#! all roots.
- "stack_chain" f temp-reg-1 %alien-global
+ temp-reg-1 "stack_chain" f %alien-global
+ temp-reg-1 temp-reg-1 [] MOV
temp-reg-1 [] stack-reg MOV
temp-reg-1 [] cell SUB
temp-reg-1 2 cells [+] ds-reg MOV
temp-reg-1 3 cells [+] rs-reg MOV ;
-M: x86 value-structs? t ;
+M: x86 value-struct? drop t ;
M: x86 small-enough? ( n -- ? )
HEX: -80000000 HEX: 7fffffff between? ;
{ $subsection db-open }
"Closing a database:"
{ $subsection db-close }
-"Creating tatements:"
+"Creating statements:"
{ $subsection <simple-statement> }
{ $subsection <prepared-statement> }
"Using statements with the database:"
: new-result-set ( query handle class -- result-set )
new
swap >>handle
- >r [ sql>> ] [ in-params>> ] [ out-params>> ] tri r>
+ [ [ sql>> ] [ in-params>> ] [ out-params>> ] tri ] dip
swap >>out-params
swap >>in-params
swap >>sql ;
db.types tools.walker ascii splitting math.parser combinators
libc shuffle calendar.format byte-arrays destructors prettyprint
accessors strings serialize io.encodings.binary io.encodings.utf8
-alien.strings io.streams.byte-array summary present urls ;
+alien.strings io.streams.byte-array summary present urls
+specialized-arrays.uint specialized-arrays.alien ;
IN: db.postgresql.lib
: postgresql-result-error-message ( res -- str/f )
} case ;
: param-types ( statement -- seq )
- in-params>> [ type>> type>oid ] map >c-uint-array ;
+ in-params>> [ type>> type>oid ] uint-array{ } map-as underlying>> ;
: malloc-byte-array/length ( byte-array -- alien length )
[ malloc-byte-array &free ] [ length ] bi ;
: param-values ( statement -- seq seq2 )
[ bind-params>> ] [ in-params>> ] bi
[
- >r value>> r> type>> {
+ [ value>> ] [ type>> ] bi* {
{ FACTOR-BLOB [
dup [ object>bytes malloc-byte-array/length ] [ 0 ] if
] }
] 2map flip [
f f
] [
- first2 [ >c-void*-array ] [ >c-uint-array ] bi*
+ first2 [ >void*-array underlying>> ] [ >uint-array underlying>> ] bi*
] if-empty ;
: param-formats ( statement -- seq )
- in-params>> [ type>> type>param-format ] map >c-uint-array ;
+ in-params>> [ type>> type>param-format ] uint-array{ } map-as underlying>> ;
: do-postgresql-bound-statement ( statement -- res )
[
- >r db get handle>> r>
+ [ db get handle>> ] dip
{
[ sql>> ]
[ bind-params>> length ]
: pq-get-string ( handle row column -- obj )
3dup PQgetvalue utf8 alien>string
- dup empty? [ >r pq-get-is-null f r> ? ] [ 3nip ] if ;
+ dup empty? [ [ pq-get-is-null f ] dip ? ] [ 3nip ] if ;
: pq-get-number ( handle row column -- obj )
pq-get-string dup [ string>number ] when ;
USING: kernel db.postgresql alien continuations io classes
prettyprint sequences namespaces tools.test db
-db.tuples db.types unicode.case accessors ;
+db.tuples db.types unicode.case accessors system ;
IN: db.postgresql.tests
: test-db ( -- postgresql-db )
"thepasswordistrust" >>password
"factor-test" >>database ;
-[ ] [ test-db [ ] with-db ] unit-test
+os windows? cpu x86.64? and [
+ [ ] [ test-db [ ] with-db ] unit-test
-[ ] [
- test-db [
- [ "drop table person;" sql-command ] ignore-errors
- "create table person (name varchar(30), country varchar(30));"
- sql-command
+ [ ] [
+ test-db [
+ [ "drop table person;" sql-command ] ignore-errors
+ "create table person (name varchar(30), country varchar(30));"
+ sql-command
- "insert into person values('John', 'America');" sql-command
- "insert into person values('Jane', 'New Zealand');" sql-command
- ] with-db
-] unit-test
+ "insert into person values('John', 'America');" sql-command
+ "insert into person values('Jane', 'New Zealand');" sql-command
+ ] with-db
+ ] unit-test
-[
- {
- { "John" "America" }
- { "Jane" "New Zealand" }
- }
-] [
- test-db [
- "select * from person" sql-query
- ] with-db
-] unit-test
+ [
+ {
+ { "John" "America" }
+ { "Jane" "New Zealand" }
+ }
+ ] [
+ test-db [
+ "select * from person" sql-query
+ ] with-db
+ ] unit-test
-[
- {
- { "John" "America" }
- { "Jane" "New Zealand" }
- }
-] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
+ [
+ {
+ { "John" "America" }
+ { "Jane" "New Zealand" }
+ }
+ ] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
-[
-] [
- test-db [
- "insert into person(name, country) values('Jimmy', 'Canada')"
- sql-command
- ] with-db
-] unit-test
+ [
+ ] [
+ test-db [
+ "insert into person(name, country) values('Jimmy', 'Canada')"
+ sql-command
+ ] with-db
+ ] unit-test
-[
- {
- { "John" "America" }
- { "Jane" "New Zealand" }
- { "Jimmy" "Canada" }
- }
-] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
+ [
+ {
+ { "John" "America" }
+ { "Jane" "New Zealand" }
+ { "Jimmy" "Canada" }
+ }
+ ] [ test-db [ "select * from person" sql-query ] with-db ] unit-test
-[
- test-db [
- [
- "insert into person(name, country) values('Jose', 'Mexico')" sql-command
- "insert into person(name, country) values('Jose', 'Mexico')" sql-command
- "oops" throw
- ] with-transaction
- ] with-db
-] must-fail
+ [
+ test-db [
+ [
+ "insert into person(name, country) values('Jose', 'Mexico')" sql-command
+ "insert into person(name, country) values('Jose', 'Mexico')" sql-command
+ "oops" throw
+ ] with-transaction
+ ] with-db
+ ] must-fail
-[ 3 ] [
- test-db [
- "select * from person" sql-query length
- ] with-db
-] unit-test
+ [ 3 ] [
+ test-db [
+ "select * from person" sql-query length
+ ] with-db
+ ] unit-test
-[
-] [
- test-db [
- [
- "insert into person(name, country) values('Jose', 'Mexico')"
- sql-command
- "insert into person(name, country) values('Jose', 'Mexico')"
- sql-command
- ] with-transaction
- ] with-db
-] unit-test
+ [
+ ] [
+ test-db [
+ [
+ "insert into person(name, country) values('Jose', 'Mexico')"
+ sql-command
+ "insert into person(name, country) values('Jose', 'Mexico')"
+ sql-command
+ ] with-transaction
+ ] with-db
+ ] unit-test
-[ 5 ] [
- test-db [
- "select * from person" sql-query length
- ] with-db
-] unit-test
+ [ 5 ] [
+ test-db [
+ "select * from person" sql-query length
+ ] with-db
+ ] unit-test
+] unless
: with-dummy-db ( quot -- )
ERROR: no-compound-found string object ;
M: postgresql-db compound ( string object -- string' )
over {
- { "default" [ first number>string join-space ] }
- { "varchar" [ first number>string paren append ] }
+ { "default" [ first number>string " " glue ] }
+ { "varchar" [ first number>string "(" ")" surround append ] }
{ "references" [ >reference-string ] }
[ drop no-compound-found ]
} case ;
3drop
] [
pick column-name>> 0%
- >r first2 r> interval-comparison 0%
+ [ first2 ] dip interval-comparison 0%
bind#
] if ;
where-clause
] query-make ;
-: splice ( string1 string2 string3 -- string )
- swap 3append ;
-
: do-group ( tuple groups -- )
dup string? [ 1array ] when
- [ ", " join " group by " splice ] curry change-sql drop ;
+ [ ", " join " group by " glue ] curry change-sql drop ;
: do-order ( tuple order -- )
dup string? [ 1array ] when
- [ ", " join " order by " splice ] curry change-sql drop ;
+ [ ", " join " order by " glue ] curry change-sql drop ;
: do-offset ( tuple n -- )
- [ number>string " offset " splice ] curry change-sql drop ;
+ [ number>string " offset " glue ] curry change-sql drop ;
: do-limit ( tuple n -- )
- [ number>string " limit " splice ] curry change-sql drop ;
+ [ number>string " limit " glue ] curry change-sql drop ;
: make-query* ( tuple query -- tuple' )
dupd
: create-index ( index-name table-name columns -- )
[
- >r >r "create index " % % r> " on " % % r> "(" %
+ [ [ "create index " % % ] dip " on " % % ] dip "(" %
"," join % ")" %
] "" make sql-command ;
M: sqlite-db bind# ( spec obj -- )
[
- [ column-name>> ":" swap next-sql-counter 3append dup 0% ]
+ [ column-name>> ":" next-sql-counter surround dup 0% ]
[ type>> ] bi
] dip <literal-bind> 1, ;
M: sqlite-db compound ( string seq -- new-string )
over {
- { "default" [ first number>string join-space ] }
+ { "default" [ first number>string " " glue ] }
{ "references" [
[ >reference-string ] keep
first2 [ "foreign-table" set ]
USING: io.files kernel tools.test db db.tuples classes
db.types continuations namespaces math math.ranges
prettyprint calendar sequences db.sqlite math.intervals
-db.postgresql accessors random math.bitwise
+db.postgresql accessors random math.bitwise system
math.ranges strings urls fry db.tuples.private ;
IN: db.tuples.tests
: test-postgresql ( quot -- )
'[
- [ ] [ postgresql-db _ with-db ] unit-test
+ os windows? cpu x86.64? and [
+ [ ] [ postgresql-db _ with-db ] unit-test
+ ] unless
] call ; inline
! These words leak resources, but are useful for interactivel testing
{ "value" "the value stored in the slot" } }
{ $description "Returns the value stored in a tuple slot, where the tuple slot is a string." } ;
-HELP: join-space
-{ $values
- { "string1" string } { "string2" string }
- { "new-string" null } }
-{ $description "" } ;
-
HELP: literal-bind
{ $description "" } ;
modifiers>> [ lookup-modifier ] map " " join
[ "" ] [ " " prepend ] if-empty ;
-: join-space ( string1 string2 -- new-string )
- " " swap 3append ;
-
-: paren ( string -- new-string )
- "(" swap ")" 3append ;
-
HOOK: bind% db ( spec -- )
HOOK: bind# db ( spec obj -- )
: >reference-string ( string pair -- string )
first2
- [ [ unparse join-space ] [ db-columns ] bi ] dip
+ [ [ unparse " " glue ] [ db-columns ] bi ] dip
swap [ column-name>> = ] with find nip
[ no-column ] unless*
- column-name>> paren append ;
+ column-name>> "(" ")" surround append ;
{ $notes "This error usually indicates a run-away recursion, however if you legitimately need a data stack larger than the default, see " { $link "runtime-cli-args" } "." } ;
HELP: retainstack-underflow.
-{ $error-description "Thrown by the Factor VM if " { $link r> } " is called while the retain stack is empty." }
+{ $error-description "Thrown by the Factor VM if an attempt is made to access the retain stack in an invalid manner. This bug should never come up in practice and indicates a bug in Factor." }
{ $notes "You can use the stack effect tool to statically check stack effects of quotations. See " { $link "inference" } "." } ;
HELP: retainstack-overflow.
-{ $error-description "Thrown by the Factor VM if " { $link >r } " is called when the retain stack is full." }
+{ $error-description "Thrown by the Factor VM if " { $link dip } " is called when the retain stack is full." }
{ $notes "This error usually indicates a run-away recursion, however if you legitimately need a retain stack larger than the default, see " { $link "runtime-cli-args" } "." } ;
HELP: memory-error.
USING: slots arrays definitions generic hashtables summary io
kernel math namespaces make prettyprint prettyprint.config
sequences assocs sequences.private strings io.styles io.files
-vectors words system splitting math.parser classes.tuple
-continuations continuations.private combinators generic.math
-classes.builtin classes compiler.units generic.standard vocabs
-init kernel.private io.encodings accessors math.order
-destructors source-files parser classes.tuple.parser
-effects.parser lexer compiler.errors generic.parser
-strings.parser ;
+vectors words system splitting math.parser classes.mixin
+classes.tuple continuations continuations.private combinators
+generic.math classes.builtin classes compiler.units
+generic.standard vocabs init kernel.private io.encodings
+accessors math.order destructors source-files parser
+classes.tuple.parser effects.parser lexer compiler.errors
+generic.parser strings.parser ;
IN: debugger
GENERIC: error. ( error -- )
M: string error. print ;
-: :error ( -- )
- error get error. ;
-
: :s ( -- )
error-continuation get data>> stack. ;
[ global [ "Error in print-error!" print drop ] bind ]
recover ;
+: :error ( -- )
+ error get print-error ;
+
: print-error-and-restarts ( error -- )
print-error
restarts.
: try ( quot -- )
[ print-error-and-restarts ] recover ;
-M: relative-underflow summary
- drop "Too many items removed from data stack" ;
-
-M: relative-overflow summary
- drop "Superfluous items pushed to data stack" ;
-
: expired-error. ( obj -- )
"Object did not survive image save/load: " write third . ;
M: no-case summary
drop "Fall-through in case" ;
-M: slice-error error.
- "Cannot create slice because " write
- reason>> print ;
+M: slice-error summary
+ drop "Cannot create slice" ;
M: bounds-error summary drop "Sequence index out of bounds" ;
M: bad-escape summary drop "Bad escape code" ;
M: bad-literal-tuple summary drop "Bad literal tuple" ;
+
+M: check-mixin-class summary drop "Not a mixin class" ;
{ $values { "group" "a group" } { "words" "an array of words" } }
{ $description "Given a protocol or tuple class, this returns the corresponding generic words that this group contains." } ;
-ARTICLE: { "delegate" "intro" } "Delegation"
+ARTICLE: "delegate" "Delegation"
"The " { $vocab-link "delegate" } " vocabulary implements run-time consultation for method dispatch."
$nl
-"Fundamental to the concept of " { $emphasis "protocols" } ", which are groups of tuple slot accessors, or groups of arbtirary generic words."
+"A " { $emphasis "protocol" } " is a collection of related generic words. An object is said to " { $emphasis "consult" } " another object if it implements a protocol by forwarding all methods onto the other object."
$nl
-"This allows an object to implement a certain protocol by passing the method calls to another object."
+"Using this vocabulary, protocols can be defined and consulation can be set up without any repetitive boilerplate."
$nl
"Unlike " { $link "tuple-subclassing" } ", which expresses " { $emphasis "is-a" } " relationships by statically including the methods and slots of the superclass in all subclasses, consultation forwards generic word calls to another distinct object."
$nl
-"Fundamentally, a protocol is a word which has a method for " { $link group-words } ". One type of protocol is a tuple, which consists of the slot accessors. To define a protocol as a set of words, use"
+"Defining new protocols:"
{ $subsection POSTPONE: PROTOCOL: }
{ $subsection define-protocol }
-"The literal syntax and defining word are:"
+"Defining consultation:"
{ $subsection POSTPONE: CONSULT: }
{ $subsection define-consult }
-"The " { $vocab-link "delegate.protocols" } " vocabulary defines formal protocols for the various informal protocols used in the Factor core, such as " { $link "sequence-protocol" } ", " { $link "assocs-protocol" } " or " { $link "stream-protocol" } ;
+"Every tuple class has an associated protocol consisting of all of its slot accessor methods. The " { $vocab-link "delegate.protocols" } " vocabulary defines formal protocols for the various informal protocols used in the Factor core, such as " { $link "sequence-protocol" } ", " { $link "assocs-protocol" } " or " { $link "stream-protocol" } ;
-ABOUT: { "delegate" "intro" }
+ABOUT: "delegate"
! See http://factorcode.org/license.txt for BSD license.
USING: accessors parser generic kernel classes classes.tuple
words slots assocs sequences arrays vectors definitions
-prettyprint math hashtables sets macros namespaces make ;
+math hashtables sets generalizations namespaces make ;
IN: delegate
: protocol-words ( protocol -- words )
: consult-method ( word class quot -- )
[ drop swap first create-method ]
- [
- nip
- [
- over second saver %
- %
- dup second restorer %
- first ,
- ] [ ] make
- ] 3bi
+ [ nip [ , dup second , \ ndip , first , ] [ ] make ] 3bi
define ;
: change-word-prop ( word prop quot -- )
: define-consult ( group class quot -- )
[ register-protocol ]
- [ rot group-words -rot [ consult-method ] 2curry each ]
+ [ [ group-words ] 2dip [ consult-method ] 2curry each ]
3bi ;
: CONSULT:
M: protocol definer drop \ PROTOCOL: \ ; ;
-M: protocol synopsis* word-synopsis ; ! Necessary?
-
M: protocol group-words protocol-words ;
! Copyright (C) 2007 Daniel Ehrenberg
! See http://factorcode.org/license.txt for BSD license.
USING: delegate sequences.private sequences assocs
-prettyprint.sections io definitions kernel continuations
-listener ;
+io definitions kernel continuations ;
IN: delegate.protocols
PROTOCOL: sequence-protocol
PROTOCOL: input-stream-protocol
stream-read1 stream-read stream-read-partial stream-readln
- stream-read-until stream-read-quot ;
+ stream-read-until ;
PROTOCOL: output-stream-protocol
stream-flush stream-write1 stream-write stream-format
dup clone 3 over push-back
[ dlist>seq ] bi@
] unit-test
+
+[ V{ f 3 1 f } ] [ <dlist> 1 over push-front 3 over push-front f over push-front f over push-back dlist>seq ] unit-test
+
+[ V{ } ] [ <dlist> dlist>seq ] unit-test
: (dlist-find-node) ( dlist-node quot: ( node -- ? ) -- node/f ? )
over [
[ call ] 2keep rot
- [ drop t ] [ >r next>> r> (dlist-find-node) ] if
+ [ drop t ] [ [ next>> ] dip (dlist-find-node) ] if
] [ 2drop f f ] if ; inline recursive
: dlist-find-node ( dlist quot -- node/f ? )
- >r front>> r> (dlist-find-node) ; inline
+ [ front>> ] dip (dlist-find-node) ; inline
: dlist-each-node ( dlist quot -- )
[ f ] compose dlist-find-node 2drop ; inline
M: dlist pop-front* ( dlist -- )
[
- dup front>> [ empty-dlist ] unless*
- dup next>>
- f rot (>>next)
- f over set-prev-when
- swap (>>front)
+ [
+ [ empty-dlist ] unless*
+ [ f ] change-next drop
+ f over set-prev-when
+ ] change-front drop
] keep
normalize-back ;
M: dlist pop-back* ( dlist -- )
[
- dup back>> [ empty-dlist ] unless*
- dup prev>>
- f rot (>>prev)
- f over set-next-when
- swap (>>back)
+ [
+ [ empty-dlist ] unless*
+ [ f ] change-prev drop
+ f over set-next-when
+ ] change-back drop
] keep
normalize-front ;
[ obj>> ] prepose dlist-each-node ; inline
: dlist>seq ( dlist -- seq )
- [ ] pusher [ dlist-each ] dip ;
+ [ ] accumulator [ dlist-each ] dip ;
: 1dlist ( obj -- dlist ) <dlist> [ push-front ] keep ;
IN: documents.tests
-USING: documents namespaces tools.test ;
+USING: documents namespaces tools.test make arrays kernel fry ;
! Tests
+[ { } ] [
+ [
+ { 1 10 }
+ { 1 10 } [ , "HI" , ] each-line
+ ] { } make
+] unit-test
+
+[ { 1 "HI" } ] [
+ [
+ { 1 10 }
+ { 1 11 } [ , "HI" , ] each-line
+ ] { } make
+] unit-test
+
+[ { 1 "HI" 2 "HI" } ] [
+ [
+ { 1 10 }
+ { 2 11 } [ , "HI" , ] each-line
+ ] { } make
+] unit-test
+
+[ { { t f 1 } { t f 2 } } ] [
+ [
+ { 1 10 } { 2 11 }
+ t f
+ '[ [ _ _ ] dip 3array , ] each-line
+ ] { } make
+] unit-test
+
[ { 10 4 } ] [ { "a" } { 10 3 } text+loc ] unit-test
[ { 10 4 } ] [ { "a" } { 10 3 } text+loc ] unit-test
-! Copyright (C) 2006, 2007 Slava Pestov
+! Copyright (C) 2006, 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays io kernel math models namespaces make
sequences strings splitting combinators unicode.categories
-math.order ;
+math.order math.ranges ;
IN: documents
-: +col ( loc n -- newloc ) >r first2 r> + 2array ;
+: +col ( loc n -- newloc ) [ first2 ] dip + 2array ;
-: +line ( loc n -- newloc ) >r first2 swap r> + swap 2array ;
+: +line ( loc n -- newloc ) [ first2 swap ] dip + swap 2array ;
: =col ( n loc -- newloc ) first swap 2array ;
: doc-line ( n document -- string ) value>> nth ;
: doc-lines ( from to document -- slice )
- >r 1+ r> value>> <slice> ;
+ [ 1+ ] dip value>> <slice> ;
: start-on-line ( document from line# -- n1 )
- >r dup first r> = [ nip second ] [ 2drop 0 ] if ;
+ [ dup first ] dip = [ nip second ] [ 2drop 0 ] if ;
: end-on-line ( document to line# -- n2 )
over first over = [
2over = [
3drop
] [
- >r [ first ] bi@ 1+ dup <slice> r> each
+ [ [ first ] bi@ [a,b] ] dip each
] if ; inline
: start/end-on-line ( from to line# -- n1 n2 )
- tuck >r >r document get -rot start-on-line r> r>
- document get -rot end-on-line ;
+ tuck
+ [ [ document get ] 2dip start-on-line ]
+ [ [ document get ] 2dip end-on-line ]
+ 2bi* ;
: (doc-range) ( from to line# -- )
[ start/end-on-line ] keep document get doc-line <slice> , ;
: doc-range ( from to document -- string )
[
document set 2dup [
- >r 2dup r> (doc-range)
+ [ 2dup ] dip (doc-range)
] each-line 2drop
] { } make "\n" join ;
: text+loc ( lines loc -- loc )
- over >r over length 1 = [
- nip first2
- ] [
- first swap length 1- + 0
- ] if r> peek length + 2array ;
+ over [
+ over length 1 = [
+ nip first2
+ ] [
+ first swap length 1- + 0
+ ] if
+ ] dip peek length + 2array ;
: prepend-first ( str seq -- )
0 swap [ append ] change-nth ;
[ length 1- ] keep [ prepend ] change-nth ;
: loc-col/str ( loc document -- str col )
- >r first2 swap r> nth swap ;
+ [ first2 swap ] dip nth swap ;
: prepare-insert ( newinput from to lines -- newinput )
- tuck loc-col/str tail-slice >r loc-col/str head-slice r>
+ tuck [ loc-col/str head-slice ] [ loc-col/str tail-slice ] 2bi*
pick append-last over prepend-first ;
: (set-doc-range) ( newlines from to lines -- )
[ prepare-insert ] 3keep
- >r [ first ] bi@ 1+ r>
+ [ [ first ] bi@ 1+ ] dip
replace-slice ;
: set-doc-range ( string from to document -- )
[
- >r >r >r string-lines r> [ text+loc ] 2keep r> r>
+ [ [ string-lines ] dip [ text+loc ] 2keep ] 2dip
[ [ (set-doc-range) ] keep ] change-model
] keep update-locs ;
: remove-doc-range ( from to document -- )
- >r >r >r "" r> r> r> set-doc-range ;
+ [ "" ] 3dip set-doc-range ;
: last-line# ( document -- line )
value>> length 1- ;
dupd doc-line length 2array ;
: line-end? ( loc document -- ? )
- >r first2 swap r> doc-line length = ;
+ [ first2 swap ] dip doc-line length = ;
: doc-end ( document -- loc )
[ last-line# ] keep line-end ;
over first 0 < [
2drop { 0 0 }
] [
- >r first2 swap tuck r> validate-col 2array
+ [ first2 swap tuck ] dip validate-col 2array
] if
] if ;
value>> "\n" join ;
: set-doc-string ( string document -- )
- >r string-lines V{ } like r> [ set-model ] keep
+ [ string-lines V{ } like ] dip [ set-model ] keep
[ doc-end ] [ update-locs ] bi ;
: clear-doc ( document -- )
GENERIC: next-elt ( loc document elt -- newloc )
: prev/next-elt ( loc document elt -- start end )
- 3dup next-elt >r prev-elt r> ;
+ [ prev-elt ] [ next-elt ] 3bi ;
: elt-string ( loc document elt -- string )
- over >r prev/next-elt r> doc-range ;
+ [ prev/next-elt ] [ drop ] 2bi doc-range ;
TUPLE: char-elt ;
: (prev-char) ( loc document quot -- loc )
-rot {
{ [ over { 0 0 } = ] [ drop ] }
- { [ over second zero? ] [ >r first 1- r> line-end ] }
+ { [ over second zero? ] [ [ first 1- ] dip line-end ] }
[ pick call ]
} cond nip ; inline
M: one-char-elt next-elt 2drop ;
: (word-elt) ( loc document quot -- loc )
- pick >r
- >r >r first2 swap r> doc-line r> call
- r> =col ; inline
+ pick [
+ [ [ first2 swap ] dip doc-line ] dip call
+ ] dip =col ; inline
: ((word-elt)) ( n seq -- ? n seq ) [ ?nth blank? ] 2keep ;
: break-detector ( ? -- quot )
- [ >r blank? r> xor ] curry ; inline
+ [ [ blank? ] dip xor ] curry ; inline
: (prev-word) ( ? col str -- col )
rot break-detector find-last-from drop ?1+ ;
M: one-word-elt prev-elt
drop
- [ f -rot >r 1- r> (prev-word) ] (word-elt) ;
+ [ [ [ f ] dip 1- ] dip (prev-word) ] (word-elt) ;
M: one-word-elt next-elt
drop
- [ f -rot (next-word) ] (word-elt) ;
+ [ [ f ] 2dip (next-word) ] (word-elt) ;
TUPLE: word-elt ;
M: word-elt prev-elt
drop
- [ [ >r 1- r> ((word-elt)) (prev-word) ] (word-elt) ]
+ [ [ [ 1- ] dip ((word-elt)) (prev-word) ] (word-elt) ]
(prev-char) ;
M: word-elt next-elt
2drop first 0 2array ;
M: one-line-elt next-elt
- drop >r first dup r> doc-line length 2array ;
+ drop [ first dup ] dip doc-line length 2array ;
TUPLE: line-elt ;
require ;
: edit-location ( file line -- )
- >r (normalize-path) r>
- edit-hook get-global
+ [ (normalize-path) ] dip edit-hook get-global
[ call ] [ no-edit-hook edit-location ] if* ;
: edit ( defspec -- )
M: object error-line
drop f ;
-: :edit ( -- )
- error get [ error-file ] [ error-line ] bi
+: (:edit) ( error -- )
+ [ error-file ] [ error-line ] bi
2dup and [ edit-location ] [ 2drop ] if ;
+: :edit ( -- )
+ error get (:edit) ;
+
: edit-each ( seq -- )
[
[ "Editing " write . ]
--- /dev/null
+Ryan Murphy
+Doug Coleman
--- /dev/null
+USING: help.syntax help.markup ;
+IN: editors.editpadpro
+
+ARTICLE: "editors.editpadpro" "EditPad Pro support"
+"EditPadPro text editor integration on Windows. Be sure to put EditPadPro in your system path so that it will be found. Windows only." ;
+
+ABOUT: "editors.editpadpro"
--- /dev/null
+USING: definitions kernel parser words sequences math.parser
+namespaces editors io.launcher windows.shell32 io.files
+io.paths.windows strings unicode.case make ;
+IN: editors.editpadlite
+
+: editpadlite-path ( -- path )
+ \ editpadlite-path get-global [
+ "JGsoft" t [ >lower "editpadlite.exe" tail? ] find-in-program-files
+ ] unless* ;
+
+: editpadlite ( file line -- )
+ [
+ editpadlite-path , drop ,
+ ] { } make run-detached drop ;
+
+[ editpadlite ] edit-hook set-global
--- /dev/null
+EditPadLite editor integration
--- /dev/null
+unportable
USING: help.syntax help.markup ;
+IN: editors.editpadpro
-ARTICLE: "editpadpro" "EditPad Pro support"
-"Just load this module and you will be able to edit documentation with EditPadPro. Be sure to put EditPadPro in your system path so that it will be found. Windows only." ;
+ARTICLE: "editors.editpadpro" "EditPad Pro support"
+"EditPadPro text editor integration on Windows. Be sure to put EditPadPro in your system path so that it will be found. Windows only." ;
-ABOUT: "editpadpro"
\ No newline at end of file
+ABOUT: "editors.editpadpro"
USING: definitions kernel parser words sequences math.parser
namespaces editors io.launcher windows.shell32 io.files
-io.paths strings unicode.case make ;
+io.paths.windows strings unicode.case make ;
IN: editors.editpadpro
-: editpadpro-path
+: editpadpro-path ( -- path )
\ editpadpro-path get-global [
- program-files "JGsoft" append-path
- t [ >lower "editpadpro.exe" tail? ] find-file
+ "JGsoft" t [ >lower "editpadpro.exe" tail? ] find-in-program-files
] unless* ;
: editpadpro ( file line -- )
[
- editpadpro-path , "/l" swap number>string append , ,
+ editpadpro-path , number>string "/l" prepend , ,
] { } make run-detached drop ;
[ editpadpro ] edit-hook set-global
USING: editors io.files io.launcher kernel math.parser
-namespaces sequences windows.shell32 make ;
+namespaces sequences windows.shell32 make io.paths.windows ;
IN: editors.editplus
: editplus-path ( -- path )
\ editplus-path get-global [
- program-files "\\EditPlus 2\\editplus.exe" append-path
+ "EditPlus 2" t [ "editplus.exe" tail? ] find-in-program-files
] unless* ;
: editplus ( file line -- )
USING: help help.syntax help.markup ;
+IN: editors.emacs
-ARTICLE: { "emacs" "emacs" } "Integration with Emacs"
-
-"Put this in your .emacs file:"
-
+ARTICLE: "editors.emacs" "Integration with Emacs"
+"Put this in your " { $snippet ".emacs" } " file:"
{ $code "(server-start)" }
-
-"If you would like a new window to open when you ask Factor to edit an object, put this in your .emacs file:"
-
+"If you would like a new window to open when you ask Factor to edit an object, put this in your " { $snippet ".emacs" } " file:"
{ $code "(setq server-window 'switch-to-buffer-other-frame)" }
-
{ $see-also "editor" } ;
+
+ABOUT: "editors.emacs"
\ No newline at end of file
-USING: editors hardware-info.windows io.files io.launcher
-kernel math.parser namespaces sequences windows.shell32
-make ;
+USING: editors io.files io.launcher kernel math.parser
+namespaces sequences windows.shell32 make io.paths.windows ;
IN: editors.emeditor
: emeditor-path ( -- path )
\ emeditor-path get-global [
- program-files "\\EmEditor\\EmEditor.exe" append-path
+ "EmEditor" t [ "EmEditor.exe" tail? ] find-in-program-files
] unless* ;
: emeditor ( file line -- )
! Copyright (C) 2008 Kibleur Christophe.
! See http://factorcode.org/license.txt for BSD license.
USING: editors io.files io.launcher kernel math.parser
-namespaces sequences windows.shell32 make ;
+namespaces sequences windows.shell32 io.paths.windows make ;
IN: editors.etexteditor
: etexteditor-path ( -- str )
\ etexteditor-path get-global [
- program-files "e\\e.exe" append-path
+ "e" t [ "e.exe" tail? ] find-in-program-files
] unless* ;
: etexteditor ( file line -- )
USING: editors.gvim io.files io.windows kernel namespaces
-sequences windows.shell32 io.paths system ;
+sequences windows.shell32 io.paths.windows system ;
IN: editors.gvim.windows
M: windows gvim-path
\ gvim-path get-global [
- program-files "vim" append-path
- t [ "gvim.exe" tail? ] find-file
+ "vim" t [ "gvim.exe" tail? ] find-in-program-files
] unless* ;
--- /dev/null
+Marc Fauconneau
--- /dev/null
+USING: editors io.files io.launcher kernel math.parser
+namespaces sequences windows.shell32 make ;
+IN: editors.notepad2
+
+: notepad2-path ( -- path )
+ \ notepad2-path get-global [
+ "C:\\Windows\\system32\\notepad.exe"
+ ] unless* ;
+
+: notepad2 ( file line -- )
+ [
+ notepad2-path ,
+ "/g" , number>string , ,
+ ] { } make run-detached drop ;
+
+[ notepad2 ] edit-hook set-global
--- /dev/null
+Notepad2 editor integration
--- /dev/null
+unportable
USING: editors io.files io.launcher kernel math.parser
-namespaces sequences windows.shell32 make ;
+namespaces sequences io.paths.windows make ;
IN: editors.notepadpp
-: notepadpp-path
+: notepadpp-path ( -- path )
\ notepadpp-path get-global [
- program-files "notepad++\\notepad++.exe" append-path
+ "notepad++" t [ "notepad++.exe" tail? ] find-in-program-files
] unless* ;
: notepadpp ( file line -- )
-! Basic SciTE integration for Factor.
-!
-! By Clemens F. Hofreither, 2007.
+! Copyright (C) 2007 Clemens F. Hofreither.
+! See http://factorcode.org/license.txt for BSD license.
! clemens.hofreither@gmx.net
-!
-! In your .factor-rc or .factor-boot-rc,
-! require this module and set the scite-path
-! variable to point to your executable,
-! if not on the path.
-!
-USING: io.files io.launcher kernel namespaces math
-math.parser editors sequences windows.shell32 make ;
+USING: io.files io.launcher kernel namespaces io.paths.windows
+math math.parser editors sequences make unicode.case ;
IN: editors.scite
: scite-path ( -- path )
\ scite-path get-global [
- program-files "wscite\\SciTE.exe" append-path
+ "Scintilla Text Editor" t
+ [ >lower "scite.exe" tail? ] find-in-program-files
] unless* ;
: scite-command ( file line -- cmd )
- swap
- [
- scite-path ,
- ,
- "-goto:" swap number>string append ,
- ] { } make ;
+ swap
+ [
+ scite-path ,
+ ,
+ number>string "-goto:" prepend ,
+ ] { } make ;
: scite-location ( file line -- )
- scite-command run-detached drop ;
+ scite-command run-detached drop ;
[ scite-location ] edit-hook set-global
-SciTE editor integration
+Scintilla text editor (SciTE) integration
USING: editors io.files io.launcher kernel math.parser
-namespaces sequences windows.shell32 make ;
+namespaces sequences io.paths.windows make ;
IN: editors.ted-notepad
-: ted-notepad-path
+: ted-notepad-path ( -- path )
\ ted-notepad-path get-global [
- program-files "\\TED Notepad\\TedNPad.exe" append-path
+ "TED Notepad" t [ "TedNPad.exe" tail? ] find-in-program-files
] unless* ;
: ted-notepad ( file line -- )
[
- ted-notepad-path , "/l" swap number>string append , ,
+ ted-notepad-path ,
+ number>string "/l" prepend , ,
] { } make run-detached drop ;
[ ted-notepad ] edit-hook set-global
USING: definitions io.launcher kernel math math.parser parser
namespaces prettyprint editors make ;
-
IN: editors.textedit
: textedit-location ( file line -- )
try-process ;
[ textedit-location ] edit-hook set-global
-
-
USING: editors io.files io.launcher kernel math.parser
-namespaces sequences windows.shell32 wne ;
+namespaces sequences io.paths.windows make ;
IN: editors.ultraedit
: ultraedit-path ( -- path )
\ ultraedit-path get-global [
- program-files
- "IDM Computer Solutions\\UltraEdit-32\\uedit32.exe" append-path
+ "IDM Computer Solutions" t [ "uedit32.exe" tail? ] find-in-program-files
] unless* ;
: ultraedit ( file line -- )
-USING: editors hardware-info.windows io.launcher kernel
-math.parser namespaces sequences windows.shell32 io.files
-arrays ;
+USING: editors io.launcher kernel io.paths.windows
+math.parser namespaces sequences io.files arrays ;
IN: editors.wordpad
: wordpad-path ( -- path )
\ wordpad-path get [
- program-files "Windows NT\\Accessories\\wordpad.exe" append-path
+ "Windows NT\\Accessories" t
+ [ "wordpad.exe" tail? ] find-in-program-files
] unless* ;
: wordpad ( file line -- )
- drop wordpad-path swap 2array dup . run-detached drop ;
+ drop wordpad-path swap 2array run-detached drop ;
[ wordpad ] edit-hook set-global
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: assocs combinators kernel sequences splitting system
-vocabs.loader ;
+vocabs.loader init ;
IN: environment
HOOK: os-env os ( key -- value )
(os-envs) [ "=" split1 ] H{ } map>assoc ;
: set-os-envs ( assoc -- )
- [ "=" swap 3append ] { } assoc>map (set-os-envs) ;
+ [ "=" glue ] { } assoc>map (set-os-envs) ;
{
{ [ os unix? ] [ "environment.unix" require ] }
{ [ os winnt? ] [ "environment.winnt" require ] }
{ [ os wince? ] [ ] }
} cond
+
+[
+ "FACTOR_ROOTS" os-env
+ [
+ os windows? ";" ":" ? split
+ [ add-vocab-root ] each
+ ] when*
+] "environment" add-init-hook
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types alien.strings alien.syntax kernel
layouts sequences system unix environment io.encodings.utf8
-unix.utilities vocabs.loader combinators alien.accessors ;
+unix.utilities vocabs.loader combinators alien.accessors
+alien.syntax ;
IN: environment.unix
HOOK: environ os ( -- void* )
-M: unix environ ( -- void* ) "environ" f dlsym ;
+M: unix environ ( -- void* ) &: environ ;
M: unix os-env ( key -- value ) getenv ;
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.strings fry io.encodings.utf16 kernel
+USING: alien.strings fry io.encodings.utf16n kernel
splitting windows windows.kernel32 system environment
alien.c-types sequences windows.errors io.streams.memory
io.encodings io ;
{ "http://" "https://" "ftp://" } [ head? ] with contains? ;
: simple-link-title ( string -- string' )
- dup absolute-url? [ "/" last-split1 swap or ] unless ;
+ dup absolute-url? [ "/" split1-last swap or ] unless ;
EBNF: parse-farkup
nl = ("\r\n" | "\r" | "\n") => [[ drop "\n" ]]
} cond ;
: escape-link ( href text -- href-esc text-esc )
- >r check-url escape-quoted-string r> escape-string ;
+ [ check-url escape-quoted-string ] dip escape-string ;
: write-link ( href text -- )
escape-link
] if ;
: render-code ( string mode -- string' )
- >r string-lines r>
+ [ string-lines ] dip
[
<pre>
htmlize-lines
+++ /dev/null
-Slava Pestov
+++ /dev/null
-USING: arrays bit-arrays vectors strings sbufs
-kernel help.markup help.syntax math ;
-IN: float-arrays
-
-ARTICLE: "float-arrays" "Float arrays"
-"Float arrays are fixed-size mutable sequences (" { $link "sequence-protocol" } ") whose elements are instances of " { $link float } ". Elements are unboxed, hence the memory usage is lower than an equivalent " { $link array } " of floats."
-$nl
-"Float array words are in the " { $vocab-link "float-arrays" } " vocabulary."
-$nl
-"Float arrays play a special role in the C library interface; they can be used to pass binary data back and forth between Factor and C. See " { $link "c-byte-arrays" } "."
-$nl
-"Float arrays form a class of objects."
-{ $subsection float-array }
-{ $subsection float-array? }
-"There are several ways to construct float arrays."
-{ $subsection >float-array }
-{ $subsection <float-array> }
-"Creating a float array from several elements on the stack:"
-{ $subsection 1float-array }
-{ $subsection 2float-array }
-{ $subsection 3float-array }
-{ $subsection 4float-array }
-"Float array literal syntax:"
-{ $subsection POSTPONE: F{ } ;
-
-ABOUT: "float-arrays"
-
-HELP: F{
-{ $syntax "F{ elements... }" }
-{ $values { "elements" "a list of real numbers" } }
-{ $description "Marks the beginning of a literal float array. Literal float arrays are terminated by " { $link POSTPONE: } } "." }
-{ $examples { $code "F{ 1.0 2.0 3.0 }" } } ;
-
-HELP: float-array
-{ $description "The class of float arrays." } ;
-
-HELP: <float-array> ( n -- float-array )
-{ $values { "n" "a non-negative integer" } { "float-array" "a new float array" } }
-{ $description "Creates a new float array holding " { $snippet "n" } " floats with all elements initially set to " { $snippet "0.0" } "." } ;
-
-HELP: >float-array
-{ $values { "seq" "a sequence" } { "float-array" float-array } }
-{ $description "Outputs a freshly-allocated float array whose elements have the same floating-point values as a given sequence." }
-{ $errors "Throws an error if the sequence contains elements other than real numbers." } ;
-
-HELP: 1float-array
-{ $values { "x" object } { "array" float-array } }
-{ $description "Create a new float array with one element." } ;
-
-{ 1array 2array 3array 4array } related-words
-
-HELP: 2float-array
-{ $values { "x" object } { "y" object } { "array" float-array } }
-{ $description "Create a new float array with two elements, with " { $snippet "x" } " appearing first." } ;
-
-HELP: 3float-array
-{ $values { "x" object } { "y" object } { "z" object } { "array" float-array } }
-{ $description "Create a new float array with three elements, with " { $snippet "x" } " appearing first." } ;
-
-HELP: 4float-array
-{ $values { "w" object } { "x" object } { "y" object } { "z" object } { "array" float-array } }
-{ $description "Create a new float array with four elements, with " { $snippet "w" } " appearing first." } ;
+++ /dev/null
-IN: float-arrays.tests
-USING: float-arrays tools.test sequences.private ;
-
-[ F{ 0.0 0.0 0.0 } ] [ 3 <float-array> ] unit-test
-
-[ F{ 1 2 3 0 0 0 } ] [ 6 F{ 1 2 3 } resize ] unit-test
-
-[ F{ 1 2 } ] [ 2 F{ 1 2 3 4 5 6 7 8 9 } resize ] unit-test
-
-[ -10 F{ } resize ] must-fail
-
-[ F{ 1.3 } ] [ 1.3 1float-array ] unit-test
+++ /dev/null
-! Copyright (C) 2007, 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel kernel.private alien.accessors sequences
-sequences.private math math.private byte-arrays accessors
-alien.c-types parser prettyprint.backend ;
-IN: float-arrays
-
-TUPLE: float-array
-{ length array-capacity read-only }
-{ underlying byte-array read-only } ;
-
-: <float-array> ( n -- float-array )
- dup "double" <c-array> float-array boa ; inline
-
-M: float-array clone
- [ length>> ] [ underlying>> clone ] bi float-array boa ;
-
-M: float-array length length>> ;
-
-M: float-array nth-unsafe
- underlying>> double-nth ;
-
-M: float-array set-nth-unsafe
- [ >float ] 2dip underlying>> set-double-nth ;
-
-: >float-array ( seq -- float-array )
- T{ float-array } clone-like ; inline
-
-M: float-array like
- drop dup float-array? [ >float-array ] unless ;
-
-M: float-array new-sequence
- drop <float-array> ;
-
-M: float-array equal?
- over float-array? [ sequence= ] [ 2drop f ] if ;
-
-M: float-array resize
- [ drop ] [
- [ "double" heap-size * ] [ underlying>> ] bi*
- resize-byte-array
- ] 2bi
- float-array boa ;
-
-M: float-array byte-length length "double" heap-size * ;
-
-INSTANCE: float-array sequence
-
-: 1float-array ( x -- array )
- 1 <float-array> [ set-first ] keep ; inline
-
-: 2float-array ( x y -- array )
- T{ float-array } 2sequence ; inline
-
-: 3float-array ( x y z -- array )
- T{ float-array } 3sequence ; inline
-
-: 4float-array ( w x y z -- array )
- T{ float-array } 4sequence ; inline
-
-: F{ \ } [ >float-array ] parse-literal ; parsing
-
-M: float-array pprint-delims drop \ F{ \ } ;
-M: float-array >pprint-sequence ;
-M: float-array pprint* pprint-object ;
-
-! Rice
-USING: hints math.vectors arrays ;
-
-HINTS: vneg { float-array } { array } ;
-HINTS: v*n { float-array float } { array object } ;
-HINTS: n*v { float float-array } { array object } ;
-HINTS: v/n { float-array float } { array object } ;
-HINTS: n/v { float float-array } { object array } ;
-HINTS: v+ { float-array float-array } { array array } ;
-HINTS: v- { float-array float-array } { array array } ;
-HINTS: v* { float-array float-array } { array array } ;
-HINTS: v/ { float-array float-array } { array array } ;
-HINTS: vmax { float-array float-array } { array array } ;
-HINTS: vmin { float-array float-array } { array array } ;
-HINTS: v. { float-array float-array } { array array } ;
-HINTS: norm-sq { float-array } { array } ;
-HINTS: norm { float-array } { array } ;
-HINTS: normalize { float-array } { array } ;
-
-! More rice. Experimental, currently causes a slowdown in raytracer
-! for some odd reason.
-
-USING: words classes.algebra compiler.tree.propagation.info ;
-
-{ v+ v- v* v/ vmax vmin } [
- [
- [ class>> float-array class<= ] both?
- float-array object ? <class-info>
- ] "outputs" set-word-prop
-] each
-
-{ n*v n/v } [
- [
- nip class>> float-array class<= float-array object ? <class-info>
- ] "outputs" set-word-prop
-] each
-
-{ v*n v/n } [
- [
- drop class>> float-array class<= float-array object ? <class-info>
- ] "outputs" set-word-prop
-] each
-
-{ vneg normalize } [
- [
- class>> float-array class<= float-array object ? <class-info>
- ] "outputs" set-word-prop
-] each
-
-\ norm-sq [
- class>> float-array class<= float object ? <class-info>
-] "outputs" set-word-prop
-
-\ v. [
- [ class>> float-array class<= ] both?
- float object ? <class-info>
-] "outputs" set-word-prop
+++ /dev/null
-Efficient fixed-length floating point number arrays
+++ /dev/null
-collections
+++ /dev/null
-USING: arrays float-arrays help.markup help.syntax kernel\r
-combinators ;\r
-IN: float-vectors\r
-\r
-ARTICLE: "float-vectors" "Float vectors"\r
-"A float vector is a resizable mutable sequence of unsigned floats. Float vector words are found in the " { $vocab-link "float-vectors" } " vocabulary."\r
-$nl\r
-"Float vectors form a class:"\r
-{ $subsection float-vector }\r
-{ $subsection float-vector? }\r
-"Creating float vectors:"\r
-{ $subsection >float-vector }\r
-{ $subsection <float-vector> }\r
-"Literal syntax:"\r
-{ $subsection POSTPONE: FV{ }\r
-"If you don't care about initial capacity, a more elegant way to create a new float vector is to write:"\r
-{ $code "FV{ } clone" } ;\r
-\r
-ABOUT: "float-vectors"\r
-\r
-HELP: float-vector\r
-{ $description "The class of resizable float vectors. See " { $link "float-vectors" } " for information." } ;\r
-\r
-HELP: <float-vector>\r
-{ $values { "n" "a positive integer specifying initial capacity" } { "float-vector" float-vector } }\r
-{ $description "Creates a new float vector that can hold " { $snippet "n" } " floats before resizing." } ;\r
-\r
-HELP: >float-vector\r
-{ $values { "seq" "a sequence" } { "float-vector" float-vector } }\r
-{ $description "Outputs a freshly-allocated float vector with the same elements as a given sequence." }\r
-{ $errors "Throws an error if the sequence contains elements other than real numbers." } ;\r
-\r
-HELP: FV{\r
-{ $syntax "FV{ elements... }" }\r
-{ $values { "elements" "a list of real numbers" } }\r
-{ $description "Marks the beginning of a literal float vector. Literal float vectors are terminated by " { $link POSTPONE: } } "." } \r
-{ $examples { $code "FV{ 1.0 2.0 3.0 }" } } ;\r
+++ /dev/null
-USING: tools.test float-vectors vectors sequences kernel math ;\r
-IN: float-vectors.tests\r
-\r
-[ 0 ] [ 123 <float-vector> length ] unit-test\r
-\r
-: do-it\r
- 12345 [ >float over push ] each ;\r
-\r
-[ t ] [\r
- 3 <float-vector> do-it\r
- 3 <vector> do-it sequence=\r
-] unit-test\r
-\r
-[ t ] [ FV{ } float-vector? ] unit-test\r
+++ /dev/null
-! Copyright (C) 2008 Slava Pestov.\r
-! See http://factorcode.org/license.txt for BSD license.\r
-USING: arrays kernel kernel.private math sequences\r
-sequences.private growable float-arrays prettyprint.backend\r
-parser accessors ;\r
-IN: float-vectors\r
-\r
-TUPLE: float-vector\r
-{ underlying float-array initial: F{ } }\r
-{ length array-capacity } ;\r
-\r
-: <float-vector> ( n -- float-vector )\r
- <float-array> 0 float-vector boa ; inline\r
-\r
-: >float-vector ( seq -- float-vector )\r
- T{ float-vector f F{ } 0 } clone-like ;\r
-\r
-M: float-vector like\r
- drop dup float-vector? [\r
- dup float-array?\r
- [ dup length float-vector boa ] [ >float-vector ] if\r
- ] unless ;\r
-\r
-M: float-vector new-sequence\r
- drop [ <float-array> ] [ >fixnum ] bi float-vector boa ;\r
-\r
-M: float-vector equal?\r
- over float-vector? [ sequence= ] [ 2drop f ] if ;\r
-\r
-M: float-array new-resizable drop <float-vector> ;\r
-\r
-INSTANCE: float-vector growable\r
-\r
-: FV{ \ } [ >float-vector ] parse-literal ; parsing\r
-\r
-M: float-vector >pprint-sequence ;\r
-M: float-vector pprint-delims drop \ FV{ \ } ;\r
-M: float-vector pprint* pprint-object ;\r
+++ /dev/null
-Growable float arrays
+++ /dev/null
-collections
{ "FT_Pos" "advance-x" }
{ "FT_Pos" "advance-y" }
- { "long" "format" }
+ { "intptr_t" "format" }
{ "int" "bitmap-rows" }
{ "int" "bitmap-width" }
} ;\r
\r
HELP: '[\r
-{ $syntax "code... ]" }\r
+{ $syntax "'[ code... ]" }\r
{ $description "Literal fried quotation. Expands into code which takes values from the stack and substitutes them in place of the fry specifiers " { $link _ } " and " { $link @ } "." }\r
{ $examples "See " { $link "fry.examples" } "." } ;\r
\r
+HELP: >r/r>-in-fry-error\r
+{ $error-description "Thrown by " { $link POSTPONE: '[ } " if the fried quotation contains calls to " { $link >r } " or " { $link r> } ". Explicit retain stack manipulation of this form does not work with fry; use " { $link dip } " instead." } ;\r
+\r
ARTICLE: "fry.examples" "Examples of fried quotations"\r
"The easiest way to understand fried quotations is to look at some examples."\r
$nl\r
"{ 10 20 30 } [ sq ] [ . ] compose each"\r
"{ 10 20 30 } [ sq . ] each"\r
}\r
-"The " { $link _ } " and " { $link @ } " specifiers may be freely mixed:"\r
+"The " { $link _ } " and " { $link @ } " specifiers may be freely mixed, and the result is considerably more concise and readable than the version using " { $link curry } " and " { $link compose } " directly:"\r
{ $code\r
"{ 8 13 14 27 } [ even? ] 5 '[ @ dup _ ? ] map"\r
- "{ 8 13 14 27 } [ even? ] 5 [ dup ] swap [ ? ] curry 3compose map"\r
+ "{ 8 13 14 27 } [ even? ] 5 [ dup ] swap [ ? ] curry compose compose map"\r
"{ 8 13 14 27 } [ even? dup 5 ? ] map"\r
}\r
+"The following is a no-op:"\r
+{ $code "'[ @ ]" }\r
"Here are some built-in combinators rewritten in terms of fried quotations:"\r
{ $table\r
{ { $link literalize } { $snippet ": literalize '[ _ ] ;" } }\r
"[let | a [ ] b [ ] | [ 3 a + 4 b / ] ]"\r
} ;\r
\r
-ARTICLE: "fry.limitations" "Fried quotation limitations"\r
-"As with " { $vocab-link "locals" } ", fried quotations cannot contain " { $link >r } " and " { $link r> } ". This is not a real limitation in practice, since " { $link dip } " can be used instead." ;\r
-\r
ARTICLE: "fry" "Fried quotations"\r
-"A " { $emphasis "fried quotation" } " differs from a literal quotation in that when it is evaluated, instead of just pushing itself on the stack, it consumes zero or more stack values and inserts them into the quotation."\r
+"The " { $vocab-link "fry" } " vocabulary implements " { $emphasis "fried quotation" } ". Conceptually, fried quotations are quotations with ``holes'' (more formally, " { $emphasis "fry specifiers" } "), and the holes are filled in when the fried quotation is pushed on the stack."\r
$nl\r
-"Fried quotations are denoted with a special parsing word:"\r
+"Fried quotations are started by a special parsing word:"\r
{ $subsection POSTPONE: '[ }\r
-"Fried quotations contain zero or more " { $emphasis "fry specifiers" } ":"\r
+"There are two types of fry specifiers; the first can hold a value, and the second ``splices'' a quotation, as if it were inserted without surrounding brackets:"\r
{ $subsection _ }\r
{ $subsection @ }\r
-"When a fried quotation is being evaluated, values are consumed from the stack and spliced into the quotation from right to left."\r
+"The holes are filled in with the top of stack going in the rightmost hole, the second item on the stack going in the second hole from the right, and so on."\r
{ $subsection "fry.examples" }\r
{ $subsection "fry.philosophy" }\r
-{ $subsection "fry.limitations" }\r
-"Quotations can also be fried without using a parsing word:"\r
-{ $subsection fry } ;\r
+"Fry is implemented as a parsing word which reads a quotation and scans for occurrences of " { $link _ } " and " { $link @ } "; these words are not actually executed, and doing so raises an error (this can happen if they're accidentally used outside of a fry)."\r
+$nl\r
+"Fried quotations can also be constructed without using a parsing word; this is useful when meta-programming:"\r
+{ $subsection fry }\r
+"Fried quotations are an abstraction on top of the " { $link "compositional-combinators" } "; their use is encouraged over the combinators, because often the fry form is shorter and clearer than the combinator form." ;\r
\r
ABOUT: "fry"\r
IN: fry.tests
USING: fry tools.test math prettyprint kernel io arrays
-sequences ;
+sequences eval accessors ;
[ [ 3 + ] ] [ 3 '[ _ + ] ] unit-test
[ [ 1 3 + ] ] [ 1 3 '[ _ _ + ] ] unit-test
-[ [ 1 + ] ] [ 1 [ + ] '[ _ @ ] ] unit-test
+[ [ 1 [ + ] call ] ] [ 1 [ + ] '[ _ @ ] ] unit-test
-[ [ 1 + . ] ] [ 1 [ + ] '[ _ @ . ] ] unit-test
+[ [ 1 [ + ] call . ] ] [ 1 [ + ] '[ _ @ . ] ] unit-test
-[ [ + - ] ] [ [ + ] [ - ] '[ @ @ ] ] unit-test
+[ [ [ + ] [ - ] [ call ] dip call ] ] [ [ + ] [ - ] '[ @ @ ] ] unit-test
-[ [ "a" write "b" print ] ]
+[ [ "a" "b" [ write ] dip print ] ]
[ "a" "b" '[ _ write _ print ] ] unit-test
-[ [ 1 2 + 3 4 - ] ]
-[ [ + ] [ - ] '[ 1 2 @ 3 4 @ ] ] unit-test
-
[ 1/2 ] [
1 '[ [ _ ] dip / ] 2 swap call
] unit-test
[ { { { 3 } } } ] [
3 '[ [ [ _ 1array ] call 1array ] call 1array ] call
] unit-test
+
+[ "USING: fry kernel ; f '[ >r _ r> ]" eval ]
+[ error>> >r/r>-in-fry-error? ] must-fail-with
+
+[ { { "a" 1 } { "b" 2 } { "c" 3 } { "d" 4 } } ] [
+ 1 2 3 4 '[ "a" _ 2array "b" _ 2array "c" _ 2array "d" _ 2array 4array ] call
+] unit-test
! Copyright (C) 2008 Slava Pestov, Eduardo Cavazos.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences combinators parser splitting math
-quotations arrays make words ;
+quotations arrays make words locals.backend summary sets ;
IN: fry
: _ ( -- * ) "Only valid inside a fry" throw ;
: @ ( -- * ) "Only valid inside a fry" throw ;
-<PRIVATE
+ERROR: >r/r>-in-fry-error ;
-DEFER: (shallow-fry)
-DEFER: shallow-fry
+<PRIVATE
-: ((shallow-fry)) ( accum quot adder -- result )
- >r shallow-fry r>
- append swap [
- [ prepose ] curry append
- ] unless-empty ; inline
+: [ncurry] ( n -- quot )
+ {
+ { 0 [ [ ] ] }
+ { 1 [ [ curry ] ] }
+ { 2 [ [ 2curry ] ] }
+ { 3 [ [ 3curry ] ] }
+ [ \ curry <repetition> ]
+ } case ;
-: (shallow-fry) ( accum quot -- result )
- [ 1quotation ] [
- unclip {
- { \ _ [ [ curry ] ((shallow-fry)) ] }
- { \ @ [ [ compose ] ((shallow-fry)) ] }
- [ swap >r suffix r> (shallow-fry) ]
- } case
- ] if-empty ;
+M: >r/r>-in-fry-error summary
+ drop
+ "Explicit retain stack manipulation is not permitted in fried quotations" ;
-: shallow-fry ( quot -- quot' ) [ ] swap (shallow-fry) ;
+: check-fry ( quot -- quot )
+ dup { >r r> load-locals get-local drop-locals } intersect
+ empty? [ >r/r>-in-fry-error ] unless ;
PREDICATE: fry-specifier < word { _ @ } memq? ;
M: fry-specifier count-inputs drop 1 ;
M: object count-inputs drop 0 ;
+GENERIC: deep-fry ( obj -- )
+
+: shallow-fry ( quot -- quot' curry# )
+ check-fry
+ [ [ deep-fry ] each ] [ ] make
+ [ dup \ @ = [ drop [ _ call ] ] [ 1array ] if ] map concat
+ { _ } split [ spread>quot ] [ length 1- ] bi ;
+
PRIVATE>
-: fry ( quot -- quot' )
- [
- [
- dup callable? [
- [ count-inputs \ _ <repetition> % ] [ fry % ] bi
- ] [ , ] if
- ] each
- ] [ ] make shallow-fry ;
+: fry ( quot -- quot' ) shallow-fry [ncurry] swap prefix ;
+
+M: callable deep-fry
+ [ count-inputs \ _ <repetition> % ] [ fry % ] bi ;
+
+M: object deep-fry , ;
: '[ \ ] parse-until fry over push-all ; parsing
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays classes.singleton combinators
+continuations io io.encodings.binary io.encodings.utf8
+io.files io.sockets kernel io.streams.duplex math
+math.parser sequences splitting namespaces strings fry ftp
+ftp.client.listing-parser urls ;
+IN: ftp.client
+
+: (ftp-response-code) ( str -- n )
+ 3 head string>number ;
+
+: ftp-response-code ( string -- n/f )
+ dup fourth CHAR: - = [ drop f ] [ (ftp-response-code) ] if ;
+
+: read-response-loop ( ftp-response -- ftp-response )
+ readln
+ [ add-response-line ] [ ftp-response-code ] bi
+ over n>> = [ read-response-loop ] unless ;
+
+: read-response ( -- ftp-response )
+ <ftp-response> readln
+ [ (ftp-response-code) >>n ]
+ [ add-response-line ]
+ [ fourth CHAR: - = ] tri
+ [ read-response-loop ] when ;
+
+ERROR: ftp-error got expected ;
+
+: ftp-assert ( ftp-response n -- )
+ 2dup [ n>> ] dip = [ 2drop ] [ ftp-error ] if ;
+
+: ftp-command ( string -- ftp-response )
+ ftp-send read-response ;
+
+: ftp-user ( url -- ftp-response )
+ username>> "USER " prepend ftp-command ;
+
+: ftp-password ( url -- ftp-response )
+ password>> "PASS " prepend ftp-command ;
+
+: ftp-cwd ( directory -- ftp-response )
+ "CWD " prepend ftp-command ;
+
+: ftp-retr ( filename -- ftp-response )
+ "RETR " prepend ftp-command ;
+
+: ftp-set-binary ( -- ftp-response ) "TYPE I" ftp-command ;
+
+: ftp-pwd ( -- ftp-response ) "PWD" ftp-command ;
+
+: ftp-list ( -- )
+ "LIST" ftp-command 150 ftp-assert ;
+
+: ftp-quit ( -- ftp-response ) "QUIT" ftp-command ;
+
+: ftp-epsv ( -- ftp-response )
+ "EPSV" ftp-command dup 229 ftp-assert ;
+
+: parse-epsv ( ftp-response -- port )
+ strings>> first "|" split 2 tail* first string>number ;
+
+: open-passive-client ( url protocol -- stream )
+ [ host>> ftp-epsv parse-epsv <inet> ] dip <client> drop ;
+
+: list ( url -- ftp-response )
+ utf8 open-passive-client
+ ftp-list
+ lines
+ <ftp-response> swap >>strings
+ read-response 226 ftp-assert
+ parse-list ;
+
+: (ftp-get) ( url path -- )
+ [ binary open-passive-client ] dip
+ [ ftp-retr 150 ftp-assert drop ]
+ [ binary <file-writer> stream-copy ] 2bi
+ read-response 226 ftp-assert ;
+
+: ftp-login ( url -- )
+ read-response 220 ftp-assert
+ [ ftp-user 331 ftp-assert ]
+ [ ftp-password 230 ftp-assert ] bi
+ ftp-set-binary 200 ftp-assert ;
+
+: ftp-connect ( url -- stream )
+ [ host>> ] [ port>> ] bi <inet> utf8 <client> drop ;
+
+: with-ftp-client ( url quot -- )
+ [ [ ftp-connect ] keep ] dip
+ '[ _ [ ftp-login ] _ bi ftp-quit drop ] with-stream ; inline
+
+: ensure-login ( url -- url )
+ dup username>> [
+ "anonymous" >>username
+ "ftp-client" >>password
+ ] unless ;
+
+: >ftp-url ( url -- url' ) >url ensure-port ensure-login ;
+
+: ftp-get ( url -- )
+ >ftp-url [
+ dup path>>
+ [ nip parent-directory ftp-cwd drop ]
+ [ file-name (ftp-get) ] 2bi
+ ] with-ftp-client ;
+
+
+
+
--- /dev/null
+Doug Coleman
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators io.files kernel math.parser
+sequences splitting ;
+IN: ftp.client.listing-parser
+
+: ch>file-type ( ch -- type )
+ {
+ { CHAR: b [ +block-device+ ] }
+ { CHAR: c [ +character-device+ ] }
+ { CHAR: d [ +directory+ ] }
+ { CHAR: l [ +symbolic-link+ ] }
+ { CHAR: s [ +socket+ ] }
+ { CHAR: p [ +fifo+ ] }
+ { CHAR: - [ +regular-file+ ] }
+ [ drop +unknown+ ]
+ } case ;
+
+: file-type>ch ( type -- string )
+ {
+ { +block-device+ [ CHAR: b ] }
+ { +character-device+ [ CHAR: c ] }
+ { +directory+ [ CHAR: d ] }
+ { +symbolic-link+ [ CHAR: l ] }
+ { +socket+ [ CHAR: s ] }
+ { +fifo+ [ CHAR: p ] }
+ { +regular-file+ [ CHAR: - ] }
+ [ drop CHAR: - ]
+ } case ;
+
+: parse-permissions ( remote-file str -- remote-file )
+ [ first ch>file-type >>type ] [ rest >>permissions ] bi ;
+
+TUPLE: remote-file
+type permissions links owner group size month day time year
+name target ;
+
+: <remote-file> ( -- remote-file ) remote-file new ;
+
+: parse-list-11 ( lines -- seq )
+ [
+ 11 f pad-right
+ <remote-file> swap {
+ [ 0 swap nth parse-permissions ]
+ [ 1 swap nth string>number >>links ]
+ [ 2 swap nth >>owner ]
+ [ 3 swap nth >>group ]
+ [ 4 swap nth string>number >>size ]
+ [ 5 swap nth >>month ]
+ [ 6 swap nth >>day ]
+ [ 7 swap nth >>time ]
+ [ 8 swap nth >>name ]
+ [ 10 swap nth >>target ]
+ } cleave
+ ] map ;
+
+: parse-list-8 ( lines -- seq )
+ [
+ <remote-file> swap {
+ [ 0 swap nth parse-permissions ]
+ [ 1 swap nth string>number >>links ]
+ [ 2 swap nth >>owner ]
+ [ 3 swap nth >>size ]
+ [ 4 swap nth >>month ]
+ [ 5 swap nth >>day ]
+ [ 6 swap nth >>time ]
+ [ 7 swap nth >>name ]
+ } cleave
+ ] map ;
+
+: parse-list-3 ( lines -- seq )
+ [
+ <remote-file> swap {
+ [ 0 swap nth parse-permissions ]
+ [ 1 swap nth string>number >>links ]
+ [ 2 swap nth >>name ]
+ } cleave
+ ] map ;
+
+: parse-list ( ftp-response -- ftp-response )
+ dup strings>>
+ [ " " split harvest ] map
+ dup length {
+ { 11 [ parse-list-11 ] }
+ { 9 [ parse-list-11 ] }
+ { 8 [ parse-list-8 ] }
+ { 3 [ parse-list-3 ] }
+ [ drop ]
+ } case >>parsed ;
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs combinators io io.files kernel
+math.parser sequences strings ;
+IN: ftp
+
+SINGLETON: active
+SINGLETON: passive
+
+TUPLE: ftp-response n strings parsed ;
+
+: <ftp-response> ( -- ftp-response )
+ ftp-response new
+ V{ } clone >>strings ;
+
+: add-response-line ( ftp-response string -- ftp-response )
+ over strings>> push ;
+
+: ftp-send ( string -- ) write "\r\n" write flush ;
+: ftp-ipv4 1 ; inline
+: ftp-ipv6 2 ; inline
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: combinators.short-circuit accessors combinators io
+io.encodings.8-bit io.encodings io.encodings.binary
+io.encodings.utf8 io.files io.sockets kernel math.parser
+namespaces make sequences ftp io.unix.launcher.parser
+unicode.case splitting assocs classes io.servers.connection
+destructors calendar io.timeouts io.streams.duplex threads
+continuations math concurrency.promises byte-arrays
+io.backend tools.hexdump tools.files io.streams.string ;
+IN: ftp.server
+
+TUPLE: ftp-client url mode state command-promise user password ;
+
+: <ftp-client> ( url -- ftp-client )
+ ftp-client new
+ swap >>url ;
+
+SYMBOL: client
+
+: ftp-server-directory ( -- str )
+ \ ftp-server-directory get-global "resource:temp" or
+ normalize-path ;
+
+TUPLE: ftp-command raw tokenized ;
+
+: <ftp-command> ( -- obj )
+ ftp-command new ;
+
+TUPLE: ftp-get path ;
+
+: <ftp-get> ( path -- obj )
+ ftp-get new
+ swap >>path ;
+
+TUPLE: ftp-put path ;
+
+: <ftp-put> ( path -- obj )
+ ftp-put new
+ swap >>path ;
+
+TUPLE: ftp-list ;
+
+C: <ftp-list> ftp-list
+
+: read-command ( -- ftp-command )
+ <ftp-command> readln
+ [ >>raw ] [ tokenize-command >>tokenized ] bi ;
+
+: (send-response) ( n string separator -- )
+ rot number>string write write ftp-send ;
+
+: send-response ( ftp-response -- )
+ [ n>> ] [ strings>> ] bi
+ [ but-last-slice [ "-" (send-response) ] with each ]
+ [ first " " (send-response) ] 2bi ;
+
+: server-response ( n string -- )
+ <ftp-response>
+ swap add-response-line
+ swap >>n
+ send-response ;
+
+: ftp-error ( string -- )
+ 500 "Unrecognized command: " rot append server-response ;
+
+: send-banner ( -- )
+ 220 "Welcome to " host-name append server-response ;
+
+: anonymous-only ( -- )
+ 530 "This FTP server is anonymous only." server-response ;
+
+: handle-QUIT ( obj -- )
+ drop 221 "Goodbye." server-response ;
+
+: handle-USER ( ftp-command -- )
+ [
+ tokenized>> second client get (>>user)
+ 331 "Please specify the password." server-response
+ ] [
+ 2drop "bad USER" ftp-error
+ ] recover ;
+
+: handle-PASS ( ftp-command -- )
+ [
+ tokenized>> second client get (>>password)
+ 230 "Login successful" server-response
+ ] [
+ 2drop "PASS error" ftp-error
+ ] recover ;
+
+ERROR: type-error type ;
+
+: parse-type ( string -- string' )
+ >upper {
+ { "IMAGE" [ "Binary" ] }
+ { "I" [ "Binary" ] }
+ [ type-error ]
+ } case ;
+
+: handle-TYPE ( obj -- )
+ [
+ tokenized>> second parse-type
+ 200 "Switching to " rot " mode" 3append server-response
+ ] [
+ 2drop "TYPE is binary only" ftp-error
+ ] recover ;
+
+: random-local-server ( -- server )
+ remote-address get class new 0 >>port binary <server> ;
+
+: port>bytes ( port -- hi lo )
+ [ -8 shift ] keep [ HEX: ff bitand ] bi@ ;
+
+: handle-PWD ( obj -- )
+ drop
+ 257 current-directory get "\"" "\"" surround server-response ;
+
+: handle-SYST ( obj -- )
+ drop
+ 215 "UNIX Type: L8" server-response ;
+
+: if-command-promise ( quot -- )
+ [ client get command-promise>> ] dip
+ [ "Establish an active or passive connection first" ftp-error ] if* ;
+
+: handle-STOR ( obj -- )
+ [
+ tokenized>> second
+ [ [ <ftp-put> ] dip fulfill ] if-command-promise
+ ] [
+ 2drop
+ ] recover ;
+
+! EPRT |2|::1|62138|
+! : handle-EPRT ( obj -- )
+ ! tokenized>> second "|" split harvest ;
+
+: start-directory ( -- )
+ 150 "Here comes the directory listing." server-response ;
+
+: finish-directory ( -- )
+ 226 "Directory send OK." server-response ;
+
+GENERIC: service-command ( stream obj -- )
+
+M: ftp-list service-command ( stream obj -- )
+ drop
+ start-directory [
+ utf8 encode-output
+ [ current-directory get directory. ] with-string-writer string-lines
+ harvest [ ftp-send ] each
+ ] with-output-stream
+ finish-directory ;
+
+: transfer-outgoing-file ( path -- )
+ 150 "Opening BINARY mode data connection for "
+ rot
+ [ file-name ] [
+ " " swap file-info size>> number>string
+ "(" " bytes)." surround append
+ ] bi 3append server-response ;
+
+: transfer-incoming-file ( path -- )
+ 150 "Opening BINARY mode data connection for " rot append
+ server-response ;
+
+: finish-file-transfer ( -- )
+ 226 "File send OK." server-response ;
+
+M: ftp-get service-command ( stream obj -- )
+ [
+ path>>
+ [ transfer-outgoing-file ]
+ [ binary <file-reader> swap stream-copy ] bi
+ finish-file-transfer
+ ] [
+ 3drop "File transfer failed" ftp-error
+ ] recover ;
+
+M: ftp-put service-command ( stream obj -- )
+ [
+ path>>
+ [ transfer-incoming-file ]
+ [ binary <file-writer> stream-copy ] bi
+ finish-file-transfer
+ ] [
+ 3drop "File transfer failed" ftp-error
+ ] recover ;
+
+: passive-loop ( server -- )
+ [
+ [
+ |dispose
+ 30 seconds over set-timeout
+ accept drop &dispose
+ client get command-promise>>
+ 30 seconds ?promise-timeout
+ service-command
+ ]
+ [ client get f >>command-promise drop ]
+ [ drop ] cleanup
+ ] with-destructors ;
+
+: handle-LIST ( obj -- )
+ drop
+ [ [ <ftp-list> ] dip fulfill ] if-command-promise ;
+
+: handle-SIZE ( obj -- )
+ [
+ tokenized>> second file-info size>>
+ 213 swap number>string server-response
+ ] [
+ 2drop
+ 550 "Could not get file size" server-response
+ ] recover ;
+
+: handle-RETR ( obj -- )
+ [ tokenized>> second <ftp-get> swap fulfill ]
+ curry if-command-promise ;
+
+: expect-connection ( -- port )
+ random-local-server
+ client get <promise> >>command-promise drop
+ [ [ passive-loop ] curry in-thread ]
+ [ addr>> port>> ] bi ;
+
+: handle-PASV ( obj -- )
+ drop client get passive >>mode drop
+ expect-connection
+ [
+ "Entering Passive Mode (127,0,0,1," %
+ port>bytes [ number>string ] bi@ "," glue %
+ ")" %
+ ] "" make 227 swap server-response ;
+
+: handle-EPSV ( obj -- )
+ drop
+ client get command-promise>> [
+ "You already have a passive stream" ftp-error
+ ] [
+ 229 "Entering Extended Passive Mode (|||"
+ expect-connection number>string
+ "|)" 3append server-response
+ ] if ;
+
+! LPRT 6,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,242,186
+! : handle-LPRT ( obj -- ) tokenized>> "," split ;
+
+ERROR: not-a-directory ;
+ERROR: no-permissions ;
+
+: handle-CWD ( obj -- )
+ [
+ tokenized>> second dup normalize-path
+ dup ftp-server-directory head? [
+ no-permissions
+ ] unless
+
+ file-info directory? [
+ set-current-directory
+ 250 "Directory successully changed." server-response
+ ] [
+ not-a-directory
+ ] if
+ ] [
+ 2drop
+ 550 "Failed to change directory." server-response
+ ] recover ;
+
+: unrecognized-command ( obj -- ) raw>> ftp-error ;
+
+: handle-client-loop ( -- )
+ <ftp-command> readln
+ USE: prettyprint global [ dup . flush ] bind
+ [ >>raw ]
+ [ tokenize-command >>tokenized ] bi
+ dup tokenized>> first >upper {
+ { "USER" [ handle-USER t ] }
+ { "PASS" [ handle-PASS t ] }
+ { "ACCT" [ drop "ACCT unimplemented" ftp-error t ] }
+ { "CWD" [ handle-CWD t ] }
+ ! { "XCWD" [ ] }
+ ! { "CDUP" [ ] }
+ ! { "SMNT" [ ] }
+
+ ! { "REIN" [ drop client get reset-ftp-client t ] }
+ { "QUIT" [ handle-QUIT f ] }
+
+ ! { "PORT" [ ] } ! TODO
+ { "PASV" [ handle-PASV t ] }
+ ! { "MODE" [ ] }
+ { "TYPE" [ handle-TYPE t ] }
+ ! { "STRU" [ ] }
+
+ ! { "ALLO" [ ] }
+ ! { "REST" [ ] }
+ { "STOR" [ handle-STOR t ] }
+ ! { "STOU" [ ] }
+ { "RETR" [ handle-RETR t ] }
+ { "LIST" [ handle-LIST t ] }
+ { "SIZE" [ handle-SIZE t ] }
+ ! { "NLST" [ ] }
+ ! { "APPE" [ ] }
+ ! { "RNFR" [ ] }
+ ! { "RNTO" [ ] }
+ ! { "DELE" [ handle-DELE t ] }
+ ! { "RMD" [ handle-RMD t ] }
+ ! ! { "XRMD" [ handle-XRMD t ] }
+ ! { "MKD" [ handle-MKD t ] }
+ { "PWD" [ handle-PWD t ] }
+ ! { "ABOR" [ ] }
+
+ { "SYST" [ handle-SYST t ] }
+ ! { "STAT" [ ] }
+ ! { "HELP" [ ] }
+
+ ! { "SITE" [ ] }
+ ! { "NOOP" [ ] }
+
+ ! { "EPRT" [ handle-EPRT ] }
+ ! { "LPRT" [ handle-LPRT ] }
+ { "EPSV" [ handle-EPSV t ] }
+ ! { "LPSV" [ drop handle-LPSV t ] }
+ [ drop unrecognized-command t ]
+ } case [ handle-client-loop ] when ;
+
+TUPLE: ftp-server < threaded-server ;
+
+M: ftp-server handle-client* ( server -- )
+ drop
+ [
+ ftp-server-directory [
+ host-name <ftp-client> client set
+ send-banner handle-client-loop
+ ] with-directory
+ ] with-destructors ;
+
+: <ftp-server> ( port -- server )
+ ftp-server new-threaded-server
+ swap >>insecure
+ "ftp.server" >>name
+ 5 minutes >>timeout
+ latin1 >>encoding ;
+
+: ftpd ( port -- )
+ <ftp-server> start-server ;
+
+: ftpd-main ( -- ) 2100 ftpd ;
+
+MAIN: ftpd-main
+
+! sudo tcpdump -i en1 -A -s 10000 tcp port 21
--- /dev/null
+Slava Pestov
--- /dev/null
+IN: functors.tests
+USING: functors tools.test math words kernel ;
+
+<<
+
+FUNCTOR: define-box ( T -- )
+
+B DEFINES ${T}-box
+<B> DEFINES <${B}>
+
+WHERE
+
+TUPLE: B { value T } ;
+
+C: <B> B
+
+;FUNCTOR
+
+\ float define-box
+
+>>
+
+{ 1 0 } [ define-box ] must-infer-as
+
+[ T{ float-box f 5.0 } ] [ 5.0 <float-box> ] unit-test
+
+: twice ( word -- )
+ [ execute ] [ execute ] bi ; inline
+<<
+
+FUNCTOR: wrapper-test ( W -- )
+
+WW DEFINES ${W}${W}
+
+WHERE
+
+: WW W twice ; inline
+
+;FUNCTOR
+
+\ sq wrapper-test
+
+>>
+
+\ sqsq must-infer
+
+[ 16 ] [ 2 sqsq ] unit-test
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel quotations classes.tuple make combinators generic
+words interpolate namespaces sequences io.streams.string fry
+classes.mixin effects lexer parser classes.tuple.parser
+effects.parser locals.types locals.parser locals.rewrite.closures ;
+IN: functors
+
+: scan-param ( -- obj )
+ scan-object dup special? [ literalize ] unless ;
+
+: define* ( word def effect -- ) pick set-word define-declared ;
+
+: DEFINE* ( accum -- accum ) effect get parsed \ define* parsed ;
+
+: `TUPLE:
+ scan-param parsed
+ scan {
+ { ";" [ tuple parsed f parsed ] }
+ { "<" [ scan-param parsed [ parse-tuple-slots ] { } make parsed ] }
+ [
+ [ tuple parsed ] dip
+ [ parse-slot-name [ parse-tuple-slots ] when ] { }
+ make parsed
+ ]
+ } case
+ \ define-tuple-class parsed ; parsing
+
+: `M:
+ effect off
+ scan-param parsed
+ scan-param parsed
+ \ create-method parsed
+ parse-definition parsed
+ DEFINE* ; parsing
+
+: `C:
+ effect off
+ scan-param parsed
+ scan-param parsed
+ [ [ boa ] curry ] over push-all
+ DEFINE* ; parsing
+
+: `:
+ effect off
+ scan-param parsed
+ parse-definition parsed
+ DEFINE* ; parsing
+
+: `INSTANCE:
+ scan-param parsed
+ scan-param parsed
+ \ add-mixin-instance parsed ; parsing
+
+: `inline \ inline parsed ; parsing
+
+: `parsing \ parsing parsed ; parsing
+
+: `(
+ ")" parse-effect effect set ; parsing
+
+: (INTERPOLATE) ( accum quot -- accum )
+ [ scan interpolate-locals ] dip
+ '[ _ with-string-writer @ ] parsed ;
+
+: IS [ dup search [ ] [ no-word ] ?if ] (INTERPOLATE) ; parsing
+
+: DEFINES [ create-in ] (INTERPOLATE) ; parsing
+
+DEFER: ;FUNCTOR delimiter
+
+: functor-words ( -- assoc )
+ H{
+ { "TUPLE:" POSTPONE: `TUPLE: }
+ { "M:" POSTPONE: `M: }
+ { "C:" POSTPONE: `C: }
+ { ":" POSTPONE: `: }
+ { "INSTANCE:" POSTPONE: `INSTANCE: }
+ { "inline" POSTPONE: `inline }
+ { "parsing" POSTPONE: `parsing }
+ { "(" POSTPONE: `( }
+ } ;
+
+: push-functor-words ( -- )
+ functor-words use get push ;
+
+: pop-functor-words ( -- )
+ functor-words use get delq ;
+
+: parse-functor-body ( -- form )
+ t in-lambda? [
+ V{ } clone
+ push-functor-words
+ "WHERE" parse-bindings* \ ;FUNCTOR (parse-lambda)
+ <let*> parsed-lambda
+ pop-functor-words
+ >quotation
+ ] with-variable ;
+
+: (FUNCTOR:) ( -- word def )
+ CREATE
+ parse-locals dup push-locals
+ parse-functor-body swap pop-locals <lambda>
+ rewrite-closures first ;
+
+: FUNCTOR: (FUNCTOR:) define ; parsing
--- /dev/null
+First-class syntax
--- /dev/null
+extensions
xml.entities\r
http.server\r
http.server.responses\r
-furnace\r
+furnace.utilities\r
furnace.redirection\r
furnace.conversations\r
html.forms\r
urls db.types db.tuples math.parser fry logging combinators
html.templates.chloe.syntax
http http.server http.server.filters http.server.redirection
-furnace
furnace.cache
furnace.sessions
+furnace.utilities
furnace.redirection ;
IN: furnace.asides
http.server\r
http.server.filters\r
http.server.dispatchers\r
-furnace\r
furnace.actions\r
+furnace.utilities\r
furnace.redirection\r
furnace.boilerplate\r
furnace.auth.providers\r
</table>
<p>
- <button>Update</button>
+ <button type="submit">Update</button>
<t:validation-errors />
</p>
</table>
- <button>Recover password</button>
+ <button type="submit">Recover password</button>
</t:form>
</table>
<p>
- <button>Set password</button>
+ <button type="submit">Set password</button>
<t:validation-errors />
</p>
! Copyright (c) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: namespaces make accessors kernel assocs arrays io.sockets
-threads fry urls smtp validators html.forms present
-http http.server.responses http.server.redirection
-http.server.dispatchers
-furnace furnace.actions furnace.auth furnace.auth.providers
-furnace.redirection ;
+threads fry urls smtp validators html.forms present http
+http.server.responses http.server.redirection
+http.server.dispatchers furnace.actions furnace.auth
+furnace.auth.providers furnace.redirection furnace.utilities ;
IN: furnace.auth.features.recover-password
SYMBOL: lost-password-from
<p>
- <button>Register</button>
+ <button type="submit">Register</button>
<t:validation-errors />
</p>
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs kernel namespaces validators html.forms urls
http.server.dispatchers
-furnace furnace.auth furnace.auth.providers furnace.actions
+furnace.auth furnace.auth.providers furnace.actions
furnace.redirection ;
IN: furnace.auth.features.registration
USING: kernel accessors namespaces sequences math.parser\r
calendar validators urls logging html.forms\r
http http.server http.server.dispatchers\r
-furnace\r
furnace.auth\r
furnace.asides\r
furnace.actions\r
<p>
- <button>Log in</button>
+ <button type="submit">Log in</button>
<t:validation-errors />
</p>
! Copyright (c) 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel math.order namespaces furnace combinators.short-circuit
+USING: accessors kernel math.order namespaces combinators.short-circuit
html.forms
html.templates
html.templates.chloe
locals
http.server
-http.server.filters ;
+http.server.filters
+furnace.utilities ;
IN: furnace.boilerplate
TUPLE: boilerplate < filter-responder template init ;
http.server
http.server.redirection
http.server.responses
-furnace ;
+furnace.utilities ;
QUALIFIED-WITH: assocs a
IN: furnace.chloe-tags
urls db.types db.tuples math.parser fry logging combinators
html.templates.chloe.syntax
http http.server http.server.filters http.server.redirection
-furnace
furnace.cache
furnace.scopes
furnace.sessions
+furnace.utilities
furnace.redirection ;
IN: furnace.conversations
quotations sequences strings urls xml.data http ;
IN: furnace
-HELP: adjust-redirect-url
-{ $values { "url" url } { "url'" url } }
-{ $description "Adjusts a redirection URL by filtering the URL's query parameters through the " { $link modify-redirect-query } " generic word on every responder involved in handling the current request." } ;
-
-HELP: adjust-url
-{ $values { "url" url } { "url'" url } }
-{ $description "Adjusts a link URL by filtering the URL's query parameters through the " { $link modify-query } " generic word on every responder involved in handling the current request." } ;
-
-HELP: client-state
-{ $values { "key" string } { "value/f" { $maybe string } } }
-{ $description "Looks up a cookie (if the current request is a GET or HEAD request) or a POST parameter (if the current request is a POST request)." }
-{ $notes "This word is used by session management, conversation scope and asides." } ;
-
-HELP: each-responder
-{ $values { "quot" { $quotation "( responder -- )" } } }
-{ $description "Applies the quotation to each responder involved in processing the current request." } ;
-
-HELP: hidden-form-field
-{ $values { "value" string } { "name" string } }
-{ $description "Renders an HTML hidden form field tag." }
-{ $notes "This word is used by session management, conversation scope and asides." }
-{ $examples
- { $example
- "USING: furnace io ;"
- "\"bar\" \"foo\" hidden-form-field nl"
- "<input type='hidden' name='foo' value='bar'/>"
- }
-} ;
-
-HELP: link-attr
-{ $values { "tag" tag } { "responder" "a responder" } }
-{ $contract "Modifies an XHTML " { $snippet "a" } " tag." }
-{ $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
-{ $examples "Conversation scope adds attributes to link tags." } ;
-
-HELP: modify-form
-{ $values { "responder" "a responder" } }
-{ $contract "Emits hidden form fields using " { $link hidden-form-field } "." }
-{ $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
-{ $examples "Session management, conversation scope and asides use hidden form fields to pass state." } ;
-
-HELP: modify-query
-{ $values { "query" assoc } { "responder" "a responder" } { "query'" assoc } }
-{ $contract "Modifies the query parameters of a URL destined to be displayed as a link." }
-{ $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
-{ $examples "Asides add query parameters to URLs." } ;
-
-HELP: modify-redirect-query
-{ $values { "query" assoc } { "responder" "a responder" } { "query'" assoc } }
-{ $contract "Modifies the query parameters of a URL destined to be used with a redirect." }
-{ $notes "This word is called by " { $link "furnace.redirection" } "." }
-{ $examples "Conversation scope and asides add query parameters to redirect URLs." } ;
-
-HELP: nested-responders
-{ $values { "seq" "a sequence of responders" } }
-{ $description "" } ;
-
-HELP: referrer
-{ $values { "referrer/f" { $maybe string } } }
-{ $description "Outputs the current request's referrer URL." } ;
-
-HELP: request-params
-{ $values { "request" request } { "assoc" assoc } }
-{ $description "Outputs the query parameters (if the current request is a GET or HEAD request) or the POST parameters (if the current request is a POST request)." } ;
-
-HELP: resolve-base-path
-{ $values { "string" string } { "string'" string } }
-{ $description "" } ;
-
-HELP: resolve-template-path
-{ $values { "pair" "a pair with shape " { $snippet "{ class string }" } } { "path" "a pathname string" } }
-{ $description "" } ;
-
-HELP: same-host?
-{ $values { "url" url } { "?" "a boolean" } }
-{ $description "Tests if the given URL is located on the same host as the URL of the current request." } ;
-
-HELP: user-agent
-{ $values { "user-agent" { $maybe string } } }
-{ $description "Outputs the user agent reported by the client for the current request." } ;
-
-HELP: vocab-path
-{ $values { "vocab" "a vocabulary specifier" } { "path" "a pathname string" } }
-{ $description "" } ;
-
-HELP: exit-with
-{ $values { "value" object } }
-{ $description "Exits from an outer " { $link with-exit-continuation } "." } ;
-
-HELP: with-exit-continuation
-{ $values { "quot" { $quotation { "( -- value )" } } } { "value" "a value returned by the quotation or an " { $link exit-with } " invocation" } }
-{ $description "Runs a quotation with the " { $link exit-continuation } " variable bound. Calling " { $link exit-with } " in the quotation will immediately return." }
-{ $notes "Furnace actions and authentication realms wrap their execution in this combinator, allowing form validation failures and login requests, respectively, to immediately return an HTTP response to the client without running any more responder code." } ;
-
-ARTICLE: "furnace.extension-points" "Furnace extension points"
-"Furnace features such as session management, conversation scope and asides need to modify URLs in links and redirects, and insert hidden form fields, to implement state on top of the setateless HTTP protocol. In order to decouple the server-side state management code from the HTML templating code, a series of hooks are used."
-$nl
-"Responders can implement methods on the following generic words:"
-{ $subsection modify-query }
-{ $subsection modify-redirect-query }
-{ $subsection link-attr }
-{ $subsection modify-form }
-"Presentation-level code can call the following words:"
-{ $subsection adjust-url }
-{ $subsection adjust-redirect-url } ;
-
-ARTICLE: "furnace.misc" "Miscellaneous Furnace features"
-"Inspecting the chain of responders handling the current request:"
-{ $subsection nested-responders }
-{ $subsection each-responder }
-{ $subsection resolve-base-path }
-"Vocabulary root-relative resources:"
-{ $subsection vocab-path }
-{ $subsection resolve-template-path }
-"Early return from a responder:"
-{ $subsection with-exit-continuation }
-{ $subsection exit-with }
-"Other useful words:"
-{ $subsection hidden-form-field }
-{ $subsection request-params }
-{ $subsection client-state }
-{ $subsection user-agent } ;
-
ARTICLE: "furnace.persistence" "Furnace persistence layer"
{ $subsection "furnace.db" }
"Server-side state:"
IN: furnace.tests
USING: http http.server.dispatchers http.server.responses
-http.server furnace tools.test kernel namespaces accessors
-io.streams.string urls ;
+http.server furnace furnace.utilities tools.test kernel
+namespaces accessors io.streams.string urls ;
TUPLE: funny-dispatcher < dispatcher ;
: <funny-dispatcher> funny-dispatcher new-dispatcher ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: namespaces make assocs sequences kernel classes splitting
-vocabs.loader accessors strings combinators arrays
-continuations present fry
-urls html.elements
-http http.server http.server.redirection http.server.remapping ;
IN: furnace
-: nested-responders ( -- seq )
- responder-nesting get values ;
-
-: each-responder ( quot -- )
- nested-responders swap each ; inline
-
-: base-path ( string -- pair )
- dup responder-nesting get
- [ second class superclasses [ name>> = ] with contains? ] with find nip
- [ first ] [ "No such responder: " swap append throw ] ?if ;
-
-: resolve-base-path ( string -- string' )
- "$" ?head [
- [
- "/" split1 [ base-path [ "/" % % ] each "/" % ] dip %
- ] "" make
- ] when ;
-
-: vocab-path ( vocab -- path )
- dup vocab-dir vocab-append-path ;
-
-: resolve-template-path ( pair -- path )
- [
- first2 [ vocabulary>> vocab-path % ] [ "/" % % ] bi*
- ] "" make ;
-
-GENERIC: modify-query ( query responder -- query' )
-
-M: object modify-query drop ;
-
-GENERIC: modify-redirect-query ( query responder -- query' )
-
-M: object modify-redirect-query drop ;
-
-GENERIC: adjust-url ( url -- url' )
-
-M: url adjust-url
- clone
- [ [ modify-query ] each-responder ] change-query
- [ resolve-base-path ] change-path
- relative-to-request ;
-
-M: string adjust-url ;
-
-GENERIC: adjust-redirect-url ( url -- url' )
-
-M: url adjust-redirect-url
- adjust-url
- [ [ modify-redirect-query ] each-responder ] change-query ;
-
-M: string adjust-redirect-url ;
-
-GENERIC: link-attr ( tag responder -- )
-
-M: object link-attr 2drop ;
-
-GENERIC: modify-form ( responder -- )
-
-M: object modify-form drop ;
-
-: hidden-form-field ( value name -- )
- over [
- <input
- "hidden" =type
- =name
- present =value
- input/>
- ] [ 2drop ] if ;
-
-: nested-forms-key "__n" ;
-
-: request-params ( request -- assoc )
- dup method>> {
- { "GET" [ url>> query>> ] }
- { "HEAD" [ url>> query>> ] }
- { "POST" [
- post-data>>
- dup content-type>> "application/x-www-form-urlencoded" =
- [ content>> ] [ drop f ] if
- ] }
- } case ;
-
-: referrer ( -- referrer/f )
- #! Typo is intentional, it's in the HTTP spec!
- "referer" request get header>> at
- dup [ >url ensure-port [ remap-port ] change-port ] when ;
-
-: user-agent ( -- user-agent )
- "user-agent" request get header>> at "" or ;
-
-: same-host? ( url -- ? )
- dup [
- url get [
- [ protocol>> ]
- [ host>> ]
- [ port>> remap-port ]
- tri 3array
- ] bi@ =
- ] when ;
-
-: cookie-client-state ( key request -- value/f )
- swap get-cookie dup [ value>> ] when ;
-
-: post-client-state ( key request -- value/f )
- request-params at ;
-
-: client-state ( key -- value/f )
- request get dup method>> {
- { "GET" [ cookie-client-state ] }
- { "HEAD" [ cookie-client-state ] }
- { "POST" [ post-client-state ] }
- } case ;
-
-SYMBOL: exit-continuation
-
-: exit-with ( value -- )
- exit-continuation get continue-with ;
-
-: with-exit-continuation ( quot -- value )
- '[ exit-continuation set @ ] callcc1 exit-continuation off ;
-
USE: vocabs.loader
"furnace.actions" require
"furnace.alloy" require
! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors combinators namespaces fry urls http
http.server http.server.redirection http.server.responses
-http.server.remapping http.server.filters furnace ;
+http.server.remapping http.server.filters furnace.utilities ;
IN: furnace.redirection
: <redirect> ( url -- response )
USING: help.markup help.syntax io.streams.string
-furnace ;
+furnace.utilities ;
IN: furnace.referrer
HELP: <check-form-submissions>
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel http.server http.server.filters
-http.server.responses furnace ;
+http.server.responses furnace.utilities ;
IN: furnace.referrer
TUPLE: referrer-check < filter-responder quot ;
http.server http.server.responses math namespaces make kernel\r
accessors io.sockets io.servers.connection prettyprint\r
io.streams.string io.files splitting destructors sequences db\r
-db.tuples db.sqlite continuations urls math.parser furnace ;\r
+db.tuples db.sqlite continuations urls math.parser furnace\r
+furnace.utilities ;\r
\r
: with-session\r
[\r
! Copyright (C) 2008 Doug Coleman, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: assocs kernel math.intervals math.parser namespaces
-strings random accessors quotations hashtables sequences continuations
-fry calendar combinators combinators.short-circuit destructors alarms
-io.servers.connection
-db db.tuples db.types
+strings random accessors quotations hashtables sequences
+continuations fry calendar combinators combinators.short-circuit
+destructors alarms io.sockets db db.tuples db.types
http http.server http.server.dispatchers http.server.filters
-html.elements
-furnace furnace.cache furnace.scopes ;
+html.elements furnace.cache furnace.scopes furnace.utilities ;
IN: furnace.sessions
TUPLE: session < scope user-agent client ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel sequences fry
-combinators syndication
-http.server.responses http.server.redirection
-furnace furnace.actions ;
+USING: accessors kernel sequences fry combinators syndication
+http.server.responses http.server.redirection furnace.actions
+furnace.utilities ;
IN: furnace.syndication
GENERIC: feed-entry-title ( object -- string )
--- /dev/null
+USING: assocs help.markup help.syntax kernel
+quotations sequences strings urls xml.data http ;
+IN: furnace.utilities
+
+HELP: adjust-redirect-url
+{ $values { "url" url } { "url'" url } }
+{ $description "Adjusts a redirection URL by filtering the URL's query parameters through the " { $link modify-redirect-query } " generic word on every responder involved in handling the current request." } ;
+
+HELP: adjust-url
+{ $values { "url" url } { "url'" url } }
+{ $description "Adjusts a link URL by filtering the URL's query parameters through the " { $link modify-query } " generic word on every responder involved in handling the current request." } ;
+
+HELP: client-state
+{ $values { "key" string } { "value/f" { $maybe string } } }
+{ $description "Looks up a cookie (if the current request is a GET or HEAD request) or a POST parameter (if the current request is a POST request)." }
+{ $notes "This word is used by session management, conversation scope and asides." } ;
+
+HELP: each-responder
+{ $values { "quot" { $quotation "( responder -- )" } } }
+{ $description "Applies the quotation to each responder involved in processing the current request." } ;
+
+HELP: hidden-form-field
+{ $values { "value" string } { "name" string } }
+{ $description "Renders an HTML hidden form field tag." }
+{ $notes "This word is used by session management, conversation scope and asides." }
+{ $examples
+ { $example
+ "USING: furnace.utilities io ;"
+ "\"bar\" \"foo\" hidden-form-field nl"
+ "<input type='hidden' name='foo' value='bar'/>"
+ }
+} ;
+
+HELP: link-attr
+{ $values { "tag" tag } { "responder" "a responder" } }
+{ $contract "Modifies an XHTML " { $snippet "a" } " tag." }
+{ $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
+{ $examples "Conversation scope adds attributes to link tags." } ;
+
+HELP: modify-form
+{ $values { "responder" "a responder" } }
+{ $contract "Emits hidden form fields using " { $link hidden-form-field } "." }
+{ $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
+{ $examples "Session management, conversation scope and asides use hidden form fields to pass state." } ;
+
+HELP: modify-query
+{ $values { "query" assoc } { "responder" "a responder" } { "query'" assoc } }
+{ $contract "Modifies the query parameters of a URL destined to be displayed as a link." }
+{ $notes "This word is called by " { $link "html.templates.chloe.tags.form" } "." }
+{ $examples "Asides add query parameters to URLs." } ;
+
+HELP: modify-redirect-query
+{ $values { "query" assoc } { "responder" "a responder" } { "query'" assoc } }
+{ $contract "Modifies the query parameters of a URL destined to be used with a redirect." }
+{ $notes "This word is called by " { $link "furnace.redirection" } "." }
+{ $examples "Conversation scope and asides add query parameters to redirect URLs." } ;
+
+HELP: nested-responders
+{ $values { "seq" "a sequence of responders" } }
+{ $description "" } ;
+
+HELP: referrer
+{ $values { "referrer/f" { $maybe string } } }
+{ $description "Outputs the current request's referrer URL." } ;
+
+HELP: request-params
+{ $values { "request" request } { "assoc" assoc } }
+{ $description "Outputs the query parameters (if the current request is a GET or HEAD request) or the POST parameters (if the current request is a POST request)." } ;
+
+HELP: resolve-base-path
+{ $values { "string" string } { "string'" string } }
+{ $description "" } ;
+
+HELP: resolve-template-path
+{ $values { "pair" "a pair with shape " { $snippet "{ class string }" } } { "path" "a pathname string" } }
+{ $description "" } ;
+
+HELP: same-host?
+{ $values { "url" url } { "?" "a boolean" } }
+{ $description "Tests if the given URL is located on the same host as the URL of the current request." } ;
+
+HELP: user-agent
+{ $values { "user-agent" { $maybe string } } }
+{ $description "Outputs the user agent reported by the client for the current request." } ;
+
+HELP: vocab-path
+{ $values { "vocab" "a vocabulary specifier" } { "path" "a pathname string" } }
+{ $description "" } ;
+
+HELP: exit-with
+{ $values { "value" object } }
+{ $description "Exits from an outer " { $link with-exit-continuation } "." } ;
+
+HELP: with-exit-continuation
+{ $values { "quot" { $quotation { "( -- value )" } } } { "value" "a value returned by the quotation or an " { $link exit-with } " invocation" } }
+{ $description "Runs a quotation with the " { $link exit-continuation } " variable bound. Calling " { $link exit-with } " in the quotation will immediately return." }
+{ $notes "Furnace actions and authentication realms wrap their execution in this combinator, allowing form validation failures and login requests, respectively, to immediately return an HTTP response to the client without running any more responder code." } ;
+
+ARTICLE: "furnace.extension-points" "Furnace extension points"
+"Furnace features such as session management, conversation scope and asides need to modify URLs in links and redirects, and insert hidden form fields, to implement state on top of the stateless HTTP protocol. In order to decouple the server-side state management code from the HTML templating code, a series of hooks are used."
+$nl
+"Responders can implement methods on the following generic words:"
+{ $subsection modify-query }
+{ $subsection modify-redirect-query }
+{ $subsection link-attr }
+{ $subsection modify-form }
+"Presentation-level code can call the following words:"
+{ $subsection adjust-url }
+{ $subsection adjust-redirect-url } ;
+
+ARTICLE: "furnace.misc" "Miscellaneous Furnace features"
+"Inspecting the chain of responders handling the current request:"
+{ $subsection nested-responders }
+{ $subsection each-responder }
+{ $subsection resolve-base-path }
+"Vocabulary root-relative resources:"
+{ $subsection vocab-path }
+{ $subsection resolve-template-path }
+"Early return from a responder:"
+{ $subsection with-exit-continuation }
+{ $subsection exit-with }
+"Other useful words:"
+{ $subsection hidden-form-field }
+{ $subsection request-params }
+{ $subsection client-state }
+{ $subsection user-agent } ;
-! Copyright (c) 2008 Slava Pestov
+! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors words kernel sequences splitting ;
+USING: namespaces make assocs sequences kernel classes splitting
+words vocabs.loader accessors strings combinators arrays
+continuations present fry urls html.elements http http.server
+http.server.redirection http.server.remapping ;
IN: furnace.utilities
: word>string ( word -- string )
- [ vocabulary>> ] [ name>> ] bi ":" swap 3append ;
+ [ vocabulary>> ] [ name>> ] bi ":" glue ;
: words>strings ( seq -- seq' )
[ word>string ] map ;
: strings>words ( seq -- seq' )
[ string>word ] map ;
+
+: nested-responders ( -- seq )
+ responder-nesting get values ;
+
+: each-responder ( quot -- )
+ nested-responders swap each ; inline
+
+: base-path ( string -- pair )
+ dup responder-nesting get
+ [ second class superclasses [ name>> = ] with contains? ] with find nip
+ [ first ] [ "No such responder: " swap append throw ] ?if ;
+
+: resolve-base-path ( string -- string' )
+ "$" ?head [
+ [
+ "/" split1 [ base-path [ "/" % % ] each "/" % ] dip %
+ ] "" make
+ ] when ;
+
+: vocab-path ( vocab -- path )
+ dup vocab-dir vocab-append-path ;
+
+: resolve-template-path ( pair -- path )
+ [
+ first2 [ vocabulary>> vocab-path % ] [ "/" % % ] bi*
+ ] "" make ;
+
+GENERIC: modify-query ( query responder -- query' )
+
+M: object modify-query drop ;
+
+GENERIC: modify-redirect-query ( query responder -- query' )
+
+M: object modify-redirect-query drop ;
+
+GENERIC: adjust-url ( url -- url' )
+
+M: url adjust-url
+ clone
+ [ [ modify-query ] each-responder ] change-query
+ [ resolve-base-path ] change-path
+ relative-to-request ;
+
+M: string adjust-url ;
+
+GENERIC: adjust-redirect-url ( url -- url' )
+
+M: url adjust-redirect-url
+ adjust-url
+ [ [ modify-redirect-query ] each-responder ] change-query ;
+
+M: string adjust-redirect-url ;
+
+GENERIC: link-attr ( tag responder -- )
+
+M: object link-attr 2drop ;
+
+GENERIC: modify-form ( responder -- )
+
+M: object modify-form drop ;
+
+: hidden-form-field ( value name -- )
+ over [
+ <input
+ "hidden" =type
+ =name
+ present =value
+ input/>
+ ] [ 2drop ] if ;
+
+: nested-forms-key "__n" ;
+
+: request-params ( request -- assoc )
+ dup method>> {
+ { "GET" [ url>> query>> ] }
+ { "HEAD" [ url>> query>> ] }
+ { "POST" [
+ post-data>>
+ dup content-type>> "application/x-www-form-urlencoded" =
+ [ content>> ] [ drop f ] if
+ ] }
+ } case ;
+
+: referrer ( -- referrer/f )
+ #! Typo is intentional, it's in the HTTP spec!
+ "referer" request get header>> at
+ dup [ >url ensure-port [ remap-port ] change-port ] when ;
+
+: user-agent ( -- user-agent )
+ "user-agent" request get header>> at "" or ;
+
+: same-host? ( url -- ? )
+ dup [
+ url get [
+ [ protocol>> ]
+ [ host>> ]
+ [ port>> remap-port ]
+ tri 3array
+ ] bi@ =
+ ] when ;
+
+: cookie-client-state ( key request -- value/f )
+ swap get-cookie dup [ value>> ] when ;
+
+: post-client-state ( key request -- value/f )
+ request-params at ;
+
+: client-state ( key -- value/f )
+ request get dup method>> {
+ { "GET" [ cookie-client-state ] }
+ { "HEAD" [ cookie-client-state ] }
+ { "POST" [ post-client-state ] }
+ } case ;
+
+SYMBOL: exit-continuation
+
+: exit-with ( value -- )
+ exit-continuation get continue-with ;
+
+: with-exit-continuation ( quot -- value )
+ '[ exit-continuation set @ ] callcc1 exit-continuation off ;
USING: help.syntax help.markup kernel sequences quotations\r
-math arrays ;\r
+math arrays combinators ;\r
IN: generalizations\r
\r
HELP: nsequence\r
{ $description "A generalization of " { $link 1array } ", "\r
{ $link 2array } ", " { $link 3array } " and " { $link 4array } " "\r
"that constructs an array from the top " { $snippet "n" } " elements of the stack."\r
+}\r
+{ $examples\r
+ "Some core words expressed in terms of " { $link narray } ":"\r
+ { $table\r
+ { { $link 1array } { $snippet "1 narray" } }\r
+ { { $link 2array } { $snippet "2 narray" } }\r
+ { { $link 3array } { $snippet "3 narray" } }\r
+ { { $link 4array } { $snippet "4 narray" } }\r
+ }\r
} ;\r
\r
{ nsequence narray } related-words\r
{ $description "A generalization of " { $link first } ", "\r
{ $link first2 } ", " { $link first3 } " and " { $link first4 } " "\r
"that pushes the first " { $snippet "n" } " elements of a sequence on the stack."\r
+}\r
+{ $examples\r
+ "Some core words expressed in terms of " { $link firstn } ":"\r
+ { $table\r
+ { { $link first } { $snippet "1 firstn" } }\r
+ { { $link first2 } { $snippet "2 firstn" } }\r
+ { { $link first3 } { $snippet "3 firstn" } }\r
+ { { $link first4 } { $snippet "4 firstn" } }\r
+ }\r
} ;\r
\r
HELP: npick\r
}\r
{ $examples\r
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 4 npick .s" "1\n2\n3\n4\n1" }\r
-}\r
-{ $see-also dup over pick } ;\r
+ "Some core words expressed in terms of " { $link npick } ":"\r
+ { $table\r
+ { { $link dup } { $snippet "1 npick" } }\r
+ { { $link over } { $snippet "2 npick" } }\r
+ { { $link pick } { $snippet "3 npick" } }\r
+ }\r
+} ;\r
\r
HELP: ndup\r
{ $values { "n" integer } }\r
}\r
{ $examples\r
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 4 ndup .s" "1\n2\n3\n4\n1\n2\n3\n4" }\r
-}\r
-{ $see-also dup 2dup 3dup } ;\r
+ "Some core words expressed in terms of " { $link ndup } ":"\r
+ { $table\r
+ { { $link dup } { $snippet "1 ndup" } }\r
+ { { $link 2dup } { $snippet "2 ndup" } }\r
+ { { $link 3dup } { $snippet "3 ndup" } }\r
+ }\r
+} ;\r
\r
HELP: nnip\r
{ $values { "n" integer } }\r
}\r
{ $examples\r
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 3 nnip .s" "4" }\r
-}\r
-{ $see-also nip 2nip } ;\r
+ "Some core words expressed in terms of " { $link nnip } ":"\r
+ { $table\r
+ { { $link nip } { $snippet "1 nnip" } }\r
+ { { $link 2nip } { $snippet "2 nnip" } }\r
+ }\r
+} ;\r
\r
HELP: ndrop\r
{ $values { "n" integer } }\r
}\r
{ $examples\r
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 3 ndrop .s" "1" }\r
-}\r
-{ $see-also drop 2drop 3drop } ;\r
+ "Some core words expressed in terms of " { $link ndrop } ":"\r
+ { $table\r
+ { { $link drop } { $snippet "1 ndrop" } }\r
+ { { $link 2drop } { $snippet "2 ndrop" } }\r
+ { { $link 3drop } { $snippet "3 ndrop" } }\r
+ }\r
+} ;\r
\r
HELP: nrot\r
{ $values { "n" integer } }\r
}\r
{ $examples\r
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 4 nrot .s" "2\n3\n4\n1" }\r
-}\r
-{ $see-also rot -nrot } ;\r
+ "Some core words expressed in terms of " { $link nrot } ":"\r
+ { $table\r
+ { { $link swap } { $snippet "1 nrot" } }\r
+ { { $link rot } { $snippet "2 nrot" } }\r
+ }\r
+} ;\r
\r
HELP: -nrot\r
{ $values { "n" integer } }\r
}\r
{ $examples\r
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 4 -nrot .s" "4\n1\n2\n3" }\r
-}\r
-{ $see-also rot nrot } ;\r
+ "Some core words expressed in terms of " { $link -nrot } ":"\r
+ { $table\r
+ { { $link swap } { $snippet "1 -nrot" } }\r
+ { { $link -rot } { $snippet "2 -nrot" } }\r
+ }\r
+} ;\r
\r
HELP: nrev\r
{ $values { "n" integer } }\r
}\r
{ $examples\r
{ $example "USING: prettyprint generalizations ;" "1 2 3 4 4 nrev .s" "4\n3\n2\n1" }\r
-}\r
-{ $see-also rot nrot } ;\r
+ "The " { $link spin } " word is equivalent to " { $snippet "3 nrev" } "."\r
+} ;\r
\r
HELP: ndip\r
-{ $values { "quot" quotation } { "n" number } }\r
+{ $values { "quot" quotation } { "n" integer } }\r
{ $description "A generalization of " { $link dip } " that can work " \r
"for any stack depth. The quotation will be called with a stack that "\r
"has 'n' items removed first. The 'n' items are then put back on the "\r
{ $examples\r
{ $example "USING: generalizations kernel prettyprint ;" "1 2 [ dup ] 1 ndip .s" "1\n1\n2" }\r
{ $example "USING: generalizations kernel prettyprint ;" "1 2 3 [ drop ] 2 ndip .s" "2\n3" }\r
-}\r
-{ $see-also dip 2dip } ;\r
+ "Some core words expressed in terms of " { $link ndip } ":"\r
+ { $table\r
+ { { $link dip } { $snippet "1 ndip" } }\r
+ { { $link 2dip } { $snippet "2 ndip" } }\r
+ { { $link 3dip } { $snippet "3 ndip" } }\r
+ }\r
+} ;\r
\r
HELP: nslip\r
-{ $values { "n" number } }\r
+{ $values { "n" integer } }\r
{ $description "A generalization of " { $link slip } " that can work " \r
"for any stack depth. The first " { $snippet "n" } " items after the quotation will be "\r
"removed from the stack, the quotation called, and the items restored."\r
} \r
{ $examples\r
{ $example "USING: generalizations prettyprint ;" "[ 99 ] 1 2 3 4 5 5 nslip .s" "99\n1\n2\n3\n4\n5" }\r
-}\r
-{ $see-also slip nkeep } ;\r
+ "Some core words expressed in terms of " { $link nslip } ":"\r
+ { $table\r
+ { { $link slip } { $snippet "1 nslip" } }\r
+ { { $link 2slip } { $snippet "2 nslip" } }\r
+ { { $link 3slip } { $snippet "3 nslip" } }\r
+ }\r
+} ;\r
\r
HELP: nkeep\r
-{ $values { "quot" quotation } { "n" number } }\r
+{ $values { "quot" quotation } { "n" integer } }\r
{ $description "A generalization of " { $link keep } " that can work " \r
"for any stack depth. The first " { $snippet "n" } " items after the quotation will be "\r
"saved, the quotation called, and the items restored."\r
} \r
{ $examples\r
{ $example "USING: generalizations kernel prettyprint ;" "1 2 3 4 5 [ drop drop drop drop drop 99 ] 5 nkeep .s" "99\n1\n2\n3\n4\n5" }\r
-}\r
-{ $see-also keep nslip } ;\r
+ "Some core words expressed in terms of " { $link nkeep } ":"\r
+ { $table\r
+ { { $link keep } { $snippet "1 nkeep" } }\r
+ { { $link 2keep } { $snippet "2 nkeep" } }\r
+ { { $link 3keep } { $snippet "3 nkeep" } }\r
+ }\r
+} ;\r
+\r
+HELP: ncurry\r
+{ $values { "quot" quotation } { "n" integer } }\r
+{ $description "A generalization of " { $link curry } " that can work for any stack depth."\r
+} \r
+{ $examples\r
+ "Some core words expressed in terms of " { $link ncurry } ":"\r
+ { $table\r
+ { { $link curry } { $snippet "1 ncurry" } }\r
+ { { $link 2curry } { $snippet "2 ncurry" } }\r
+ { { $link 3curry } { $snippet "3 ncurry" } }\r
+ }\r
+} ;\r
+\r
+HELP: nwith\r
+{ $values { "quot" quotation } { "n" integer } }\r
+{ $description "A generalization of " { $link with } " that can work for any stack depth."\r
+} \r
+{ $examples\r
+ "Some core words expressed in terms of " { $link nwith } ":"\r
+ { $table\r
+ { { $link with } { $snippet "1 nwith" } }\r
+ }\r
+} ;\r
+\r
+HELP: napply\r
+{ $values { "quot" quotation } { "n" integer } }\r
+{ $description "A generalization of " { $link bi@ } " and " { $link tri@ } " that can work for any stack depth."\r
+} \r
+{ $examples\r
+ "Some core words expressed in terms of " { $link napply } ":"\r
+ { $table\r
+ { { $link bi@ } { $snippet "1 napply" } }\r
+ { { $link tri@ } { $snippet "2 napply" } }\r
+ }\r
+} ;\r
+\r
+HELP: ncleave\r
+{ $values { "quots" "a sequence of quotations" } { "n" integer } }\r
+{ $description "A generalization of " { $link cleave } " and " { $link 2cleave } " that can work for any quotation arity."\r
+} \r
+{ $examples\r
+ "Some core words expressed in terms of " { $link ncleave } ":"\r
+ { $table\r
+ { { $link cleave } { $snippet "1 ncleave" } }\r
+ { { $link 2cleave } { $snippet "2 ncleave" } }\r
+ }\r
+} ;\r
+\r
+HELP: mnswap\r
+{ $values { "m" integer } { "n" integer } }\r
+{ $description "Swaps the top " { $snippet "m" } " stack elements with the " { $snippet "n" } " elements directly underneath." }\r
+{ $examples\r
+ "Some core words expressed in terms of " { $link mnswap } ":"\r
+ { $table\r
+ { { $link swap } { $snippet "1 1 mnswap" } }\r
+ { { $link rot } { $snippet "2 1 mnswap" } }\r
+ { { $link -rot } { $snippet "1 2 mnswap" } }\r
+ }\r
+} ;\r
\r
ARTICLE: "generalizations" "Generalized shuffle words and combinators"\r
"The " { $vocab-link "generalizations" } " vocabulary defines a number of stack shuffling words and combinators for use in "\r
{ $subsection nnip }\r
{ $subsection ndrop }\r
{ $subsection nrev }\r
+{ $subsection mnswap }\r
"Generalized combinators:"\r
{ $subsection ndip }\r
{ $subsection nslip }\r
{ $subsection nkeep }\r
+{ $subsection napply }\r
+{ $subsection ncleave }\r
+"Generalized quotation construction:"\r
{ $subsection ncurry } \r
-{ $subsection nwith } \r
-{ $subsection napply } ;\r
+{ $subsection nwith } ;\r
\r
ABOUT: "generalizations"\r
[ 1 2 3 4 ] [ { 1 2 3 4 } 4 firstn ] unit-test\r
[ ] [ { } 0 firstn ] unit-test\r
[ "a" ] [ { "a" } 1 firstn ] unit-test\r
+\r
+[ [ 1 2 ] ] [ 1 2 2 [ ] nsequence ] unit-test\r
+\r
+[ 4 5 1 2 3 ] [ 1 2 3 4 5 2 3 mnswap ] unit-test\r
+\r
+[ 1 2 3 4 5 6 ] [ 1 2 3 4 5 6 2 4 mnswap 4 2 mnswap ] unit-test\r
-! Copyright (C) 2007, 2008 Chris Double, Doug Coleman, Eduardo\r
-! Cavazos, Slava Pestov.\r
-! See http://factorcode.org/license.txt for BSD license.\r
-USING: kernel sequences sequences.private namespaces math\r
-math.ranges combinators macros quotations fry arrays ;\r
-IN: generalizations\r
-\r
-MACRO: nsequence ( n seq -- quot )\r
- [ drop <reversed> ] [ '[ _ _ new-sequence ] ] 2bi\r
- [ '[ @ [ _ swap set-nth-unsafe ] keep ] ] reduce ;\r
-\r
-MACRO: narray ( n -- quot )\r
- '[ _ { } nsequence ] ;\r
-\r
-MACRO: firstn ( n -- )\r
- dup zero? [ drop [ drop ] ] [\r
- [ [ '[ [ _ ] dip nth-unsafe ] ] map ]\r
- [ 1- '[ [ _ ] dip bounds-check 2drop ] ]\r
- bi prefix '[ _ cleave ]\r
- ] if ;\r
-\r
-MACRO: npick ( n -- )\r
- 1- dup saver [ dup ] rot [ r> swap ] n*quot 3append ;\r
-\r
-MACRO: ndup ( n -- )\r
- dup '[ _ npick ] n*quot ;\r
-\r
-MACRO: nrot ( n -- )\r
- 1- dup saver swap [ r> swap ] n*quot append ;\r
-\r
-MACRO: -nrot ( n -- )\r
- 1- dup [ swap >r ] n*quot swap restorer append ;\r
-\r
-MACRO: ndrop ( n -- )\r
- [ drop ] n*quot ;\r
-\r
-: nnip ( n -- )\r
- swap >r ndrop r> ; inline\r
-\r
-MACRO: ntuck ( n -- )\r
- 2 + [ dupd -nrot ] curry ;\r
-\r
-MACRO: nrev ( n -- quot )\r
- 1 [a,b] [ ] [ '[ @ _ -nrot ] ] reduce ;\r
-\r
-MACRO: ndip ( quot n -- )\r
- dup saver -rot restorer 3append ;\r
-\r
-MACRO: nslip ( n -- )\r
- dup saver [ call ] rot restorer 3append ;\r
-\r
-MACRO: nkeep ( n -- )\r
- [ ] [ 1+ ] [ ] tri\r
- '[ [ _ ndup ] dip _ -nrot _ nslip ] ;\r
-\r
-MACRO: ncurry ( n -- )\r
- [ curry ] n*quot ;\r
-\r
-MACRO: nwith ( n -- )\r
- [ with ] n*quot ;\r
-\r
-MACRO: napply ( n -- )\r
- 2 [a,b]\r
- [ [ 1- ] keep '[ _ ntuck _ nslip ] ]\r
- map concat >quotation [ call ] append ;\r
+! Copyright (C) 2007, 2008 Chris Double, Doug Coleman, Eduardo
+! Cavazos, Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel sequences sequences.private math math.ranges
+combinators macros quotations fry ;
+IN: generalizations
+
+<<
+
+: n*quot ( n seq -- seq' ) <repetition> concat >quotation ;
+
+: repeat ( n obj quot -- ) swapd times ; inline
+
+>>
+
+MACRO: nsequence ( n seq -- )
+ [
+ [ drop <reversed> ] [ '[ _ _ new-sequence ] ] 2bi
+ [ '[ @ [ _ swap set-nth-unsafe ] keep ] ] reduce
+ ] keep
+ '[ @ _ like ] ;
+
+MACRO: narray ( n -- )
+ '[ _ { } nsequence ] ;
+
+MACRO: firstn ( n -- )
+ dup zero? [ drop [ drop ] ] [
+ [ [ '[ [ _ ] dip nth-unsafe ] ] map ]
+ [ 1- '[ [ _ ] dip bounds-check 2drop ] ]
+ bi prefix '[ _ cleave ]
+ ] if ;
+
+MACRO: npick ( n -- )
+ 1- [ dup ] [ '[ _ dip swap ] ] repeat ;
+
+MACRO: ndup ( n -- )
+ dup '[ _ npick ] n*quot ;
+
+MACRO: nrot ( n -- )
+ 1- [ ] [ '[ _ dip swap ] ] repeat ;
+
+MACRO: -nrot ( n -- )
+ 1- [ ] [ '[ swap _ dip ] ] repeat ;
+
+MACRO: ndrop ( n -- )
+ [ drop ] n*quot ;
+
+MACRO: nnip ( n -- )
+ '[ [ _ ndrop ] dip ] ;
+
+MACRO: ntuck ( n -- )
+ 2 + '[ dup _ -nrot ] ;
+
+MACRO: nrev ( n -- )
+ 1 [a,b] [ ] [ '[ @ _ -nrot ] ] reduce ;
+
+MACRO: ndip ( quot n -- )
+ [ '[ _ dip ] ] times ;
+
+MACRO: nslip ( n -- )
+ '[ [ call ] _ ndip ] ;
+
+MACRO: nkeep ( quot n -- )
+ tuck '[ _ ndup _ _ ndip ] ;
+
+MACRO: ncurry ( n -- )
+ [ curry ] n*quot ;
+
+MACRO: nwith ( n -- )
+ [ with ] n*quot ;
+
+MACRO: ncleave ( quots n -- )
+ [ '[ _ '[ _ _ nkeep ] ] map [ ] join ] [ '[ _ ndrop ] ] bi
+ compose ;
+
+MACRO: napply ( n -- )
+ 2 [a,b]
+ [ [ 1- ] [ ] bi '[ _ ntuck _ nslip ] ]
+ map concat >quotation [ call ] append ;
+
+MACRO: mnswap ( m n -- )
+ 1+ '[ _ -nrot ] <repetition> spread>quot ;
[ { "hell" "o wo" "rld" } ] [ "hello world" 4 group ] unit-test
-[ { V{ "a" "b" } V{ f f } } ] [
+[ { V{ "a" "b" } V{ 0 0 } } ] [
V{ "a" "b" } clone 2 <groups>
2 over set-length
>array
: check-groups dup 0 <= [ "Invalid group count" throw ] when ; inline
: new-groups ( seq n class -- groups )
- >r check-groups r> boa ; inline
+ [ check-groups ] dip boa ; inline
GENERIC: group@ ( n groups -- from to seq )
: <hash2> ( size -- hash2 ) f <array> ;
: 2= ( a b pair -- ? )
- first2 swapd >r >r = r> r> = and ; inline
+ first2 swapd [ = ] 2bi@ and ; inline
: (assoc2) ( a b alist -- {a,b,val} )
- [ >r 2dup r> 2= ] find >r 3drop r> ; inline
+ [ 2= ] with with find nip ; inline
: assoc2 ( a b alist -- value )
(assoc2) dup [ third ] when ; inline
: set-assoc2 ( value a b alist -- alist )
- >r rot 3array r> ?push ; inline
+ [ rot 3array ] dip ?push ; inline
: hash2@ ( a b hash2 -- a b bucket hash2 )
- >r 2dup hashcode2 r> [ length mod ] keep ; inline
+ [ 2dup hashcode2 ] dip [ length mod ] keep ; inline
: hash2 ( a b hash2 -- value/f )
- hash2@ nth [ assoc2 ] [ 2drop f ] if* ;
+ hash2@ nth dup [ assoc2 ] [ 3drop f ] if ;
: set-hash2 ( a b value hash2 -- )
- >r -rot r> hash2@ [ set-assoc2 ] change-nth ;
+ [ -rot ] dip hash2@ [ set-assoc2 ] change-nth ;
: alist>hash2 ( alist size -- hash2 )
- <hash2> [ over >r first3 r> set-hash2 ] reduce ; inline
+ <hash2> [ over [ first3 ] dip set-hash2 ] reduce ; inline
TUPLE: heap data ;
: <heap> ( class -- heap )
- >r V{ } clone r> boa ; inline
+ [ V{ } clone ] dip boa ; inline
TUPLE: entry value key heap index ;
data>> nth-unsafe ; inline
: up-value ( n heap -- entry )
- >r up r> data-nth ; inline
+ [ up ] dip data-nth ; inline
: left-value ( n heap -- entry )
- >r left r> data-nth ; inline
+ [ left ] dip data-nth ; inline
: right-value ( n heap -- entry )
- >r right r> data-nth ; inline
+ [ right ] dip data-nth ; inline
: data-set-nth ( entry n heap -- )
- >r [ >>index drop ] 2keep r>
+ [ [ >>index drop ] 2keep ] dip
data>> set-nth-unsafe ; inline
: data-push ( entry heap -- n )
data>> first ; inline
: data-exchange ( m n heap -- )
- [ tuck data-nth >r data-nth r> ] 3keep
- tuck >r >r data-set-nth r> r> data-set-nth ; inline
+ [ tuck data-nth [ data-nth ] dip ] 3keep
+ tuck [ data-set-nth ] 2dip data-set-nth ; inline
GENERIC: heap-compare ( pair1 pair2 heap -- ? )
heap-size >= ; inline
: left-bounds-check? ( m heap -- ? )
- >r left r> heap-bounds-check? ; inline
+ [ left ] dip heap-bounds-check? ; inline
: right-bounds-check? ( m heap -- ? )
- >r right r> heap-bounds-check? ; inline
+ [ right ] dip heap-bounds-check? ; inline
: continue? ( m up[m] heap -- ? )
[ data-nth swap ] keep [ data-nth ] keep
DEFER: up-heap
: (up-heap) ( n heap -- )
- >r dup up r>
+ [ dup up ] dip
3dup continue? [
[ data-exchange ] 2keep up-heap
] [
: (child) ( m heap -- n )
2dup right-value
- >r 2dup left-value r>
+ [ 2dup left-value ] dip
rot heap-compare
[ right ] [ left ] if ;
USING: help.markup help.syntax io kernel math namespaces parser
-prettyprint sequences vocabs.loader namespaces stack-checker ;
+prettyprint sequences vocabs.loader namespaces stack-checker
+help command-line multiline ;
IN: help.cookbook
ARTICLE: "cookbook-syntax" "Basic syntax cookbook"
}
"Convert a file of 4-byte cells from little to big endian or vice versa, by directly mapping it into memory and operating on it with sequence words:"
{ $code
- "USING: accessors grouping io.files io.mmap kernel sequences ;"
- "\"mydata.dat\" dup file-info size>> ["
+ "USING: accessors grouping io.files io.mmap.char kernel sequences ;"
+ "\"mydata.dat\" ["
" 4 <sliced-groups> [ reverse-here ] change-each"
- "] with-mapped-file"
+ "] with-mapped-char-file"
}
"Send some bytes to a remote host:"
{ $code
ARTICLE: "cookbook-scripts" "Scripting cookbook"
"Factor can be used for command-line scripting on Unix-like systems."
$nl
-"A text file can begin with a comment like the following, and made executable:"
-{ $code "#! /usr/bin/env factor -script" }
-"Running the text file will run it through Factor, assuming the " { $snippet "factor" } " binary is in your " { $snippet "$PATH" } "."
+"To run a script, simply pass it as an argument to the Factor executable:"
+{ $code "./factor cleanup.factor" }
+"The script may access command line arguments by inspecting the value of the " { $link command-line } " variable. It can also get its own path from the " { $link script } " variable."
+{ $heading "Example: ls" }
+"Here is an example implementing a simplified version of the Unix " { $snippet "ls" } " command in Factor:"
+{ $code
+ <" USING: command-line namespaces io io.files tools.files
+sequences kernel ;
+
+command-line get [
+ current-directory get directory.
+] [
+ dup length 1 = [ first directory. ] [
+ [ [ nl write ":" print ] [ directory. ] bi ] each
+ ] if
+] if-empty">
+}
+"You can put it in a file named " { $snippet "ls.factor" } ", and then run it, to list the " { $snippet "/usr/bin" } " directory for example:"
+{ $code "./factor ls.factor /usr/bin" }
+{ $heading "Example: grep" }
+"The following is a more complicated example, implementing something like the Unix " { $snippet "grep" } " command:"
+{ $code <" USING: kernel fry io io.files io.encodings.ascii sequences
+regexp command-line namespaces ;
+IN: grep
+
+: grep-lines ( pattern -- )
+ '[ dup _ matches? [ print ] [ drop ] if ] each-line ;
+
+: grep-file ( pattern filename -- )
+ ascii [ grep-lines ] with-file-reader ;
+
+: grep-usage ( -- )
+ "Usage: factor grep.factor <pattern> [<file>...]" print ;
+
+command-line get [
+ grep-usage
+] [
+ unclip <regexp> swap [
+ grep-lines
+ ] [
+ [ grep-file ] with each
+ ] if-empty
+] if-empty"> }
+"You can run it like so,"
+{ $code "./factor grep.factor '.*hello.*' myfile.txt" }
+"You'll notice this script takes a while to start. This is because it is loading and compiling the " { $vocab-link "regexp" } " vocabulary every time. To speed up startup, load the vocabulary into your image, and save the image:"
+{ $code "USE: regexp" "save" }
+"Now, the " { $snippet "grep.factor" } " script will start up much faster. See " { $link "images" } " for details."
+{ $heading "Executable scripts" }
+"It is also possible to make executable scripts. A Factor file can begin with a comment like the following:"
+{ $code "#! /usr/bin/env factor" }
+"If the text file is made executable, then it can be run, assuming the " { $snippet "factor" } " binary is in your " { $snippet "$PATH" } "."
$nl
-"The space between " { $snippet "#!" } " and " { $snippet "/usr/bin/env" } " is necessary, since " { $link POSTPONE: #! } " is a parsing word, and a syntax error would otherwise result. The " { $snippet "-script" } " switch suppresses compiler messages, and exits Factor when the script finishes."
+"The space between " { $snippet "#!" } " and " { $snippet "/usr/bin/env" } " is necessary, since " { $link POSTPONE: #! } " is a parsing word, and a syntax error would otherwise result."
{ $references
{ }
"cli"
"cookbook-application"
+ "images"
} ;
ARTICLE: "cookbook-philosophy" "Factor philosophy"
{ "If " { $link run-file } " throws a stack depth assertion, it means that the top-level form in the file left behind values on the stack. The stack depth is compared before and after loading a source file, since this type of situation is almost always an error. If you have a legitimate need to load a source file which returns data in some manner, define a word in the source file which produces this data on the stack and call the word after loading the file." }
} ;
+ARTICLE: "cookbook-next" "Next steps"
+"Once you have read through " { $link "first-program" } " and " { $link "cookbook" } ", the best way to keep learning Factor is to start looking at some simple example programs. Here are a few particularly nice vocabularies which should keep you busy for a little while:"
+{ $list
+ { $vocab-link "base64" }
+ { $vocab-link "roman" }
+ { $vocab-link "rot13" }
+ { $vocab-link "smtp" }
+ { $vocab-link "time-server" }
+ { $vocab-link "tools.hexdump" }
+ { $vocab-link "webapps.counter" }
+}
+"If you see code in there that you do not understand, use " { $link see } " and " { $link help } " to explore." ;
+
ARTICLE: "cookbook" "Factor cookbook"
"The Factor cookbook is a high-level overview of the most important concepts required to program in Factor."
{ $subsection "cookbook-syntax" }
{ $subsection "cookbook-scripts" }
{ $subsection "cookbook-compiler" }
{ $subsection "cookbook-philosophy" }
-{ $subsection "cookbook-pitfalls" } ;
+{ $subsection "cookbook-pitfalls" }
+{ $subsection "cookbook-next" } ;
ABOUT: "cookbook"
[ ] [ "IN: help.definitions.tests USING: help.syntax ; : xxx ; HELP: xxx ;" eval ] unit-test
- [ ] [ "xxx" "help.definitions.tests" lookup help ] unit-test
+ [ ] [ "xxx" "help.definitions.tests" lookup print-topic ] unit-test
[ ] [ "xxx" "help.definitions.tests" lookup >link synopsis print ] unit-test
] with-file-vocabs
! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors definitions help help.topics help.syntax
-prettyprint.backend prettyprint words kernel effects ;
+prettyprint.backend prettyprint.custom prettyprint words kernel
+effects ;
IN: help.definitions
! Definition protocol implementation
IN: help.handbook.tests
USING: help tools.test ;
-[ ] [ "article-index" help ] unit-test
-[ ] [ "primitive-index" help ] unit-test
-[ ] [ "error-index" help ] unit-test
-[ ] [ "type-index" help ] unit-test
-[ ] [ "class-index" help ] unit-test
+[ ] [ "article-index" print-topic ] unit-test
+[ ] [ "primitive-index" print-topic ] unit-test
+[ ] [ "error-index" print-topic ] unit-test
+[ ] [ "type-index" print-topic ] unit-test
+[ ] [ "class-index" print-topic ] unit-test
USING: help help.markup help.syntax help.definitions help.topics
namespaces words sequences classes assocs vocabs kernel arrays
-prettyprint.backend kernel.private io generic math system
-strings sbufs vectors byte-arrays quotations
+prettyprint.backend prettyprint.custom kernel.private io generic
+math system strings sbufs vectors byte-arrays quotations
io.streams.byte-array classes.builtin parser lexer
classes.predicate classes.union classes.intersection
classes.singleton classes.tuple tools.vocabs.browser math.parser
{ "word" { "the basic unit of code, analogous to a function or procedure in other programming languages. See " { $link "words" } } }
} ;
+ARTICLE: "tail-call-opt" "Tail-call optimization"
+"If the last action performed is the execution of a word, the current quotation is not saved on the call stack; this is known as " { $emphasis "tail-call optimization" } " and the Factor implementation guarantees that it will be performed."
+$nl
+"Tail-call optimization allows iterative algorithms to be implemented in an efficient manner using recursion, without the need for any kind of primitive looping construct in the language. However, in practice, most iteration is performed via combinators such as " { $link while } ", " { $link each } ", " { $link map } ", " { $link assoc-each } ", and so on. The definitions of these combinators do bottom-out in recursive words, however." ;
+
ARTICLE: "evaluator" "Evaluation semantics"
{ $link "quotations" } " are evaluated sequentially from beginning to end. When the end is reached, the quotation returns to its caller. As each object in the quotation is evaluated in turn, an action is taken based on its type:"
{ $list
{ "a " { $link wrapper } " - the wrapped object is pushed on the data stack. Wrappers are used to push word objects directly on the stack when they would otherwise execute. See the " { $link POSTPONE: \ } " parsing word." }
{ "All other types of objects are pushed on the data stack." }
}
-"If the last action performed is the execution of a word, the current quotation is not saved on the call stack; this is known as " { $snippet "tail-recursion" } " and allows iterative algorithms to execute without incurring unbounded call stack usage."
+{ $subsection "tail-call-opt" }
{ $see-also "compiler" } ;
ARTICLE: "objects" "Objects"
{ $values { "topic" "a help article name or a word" } }
{ $description "Prints a help article's title, or a word's " { $link summary } ", depending on the type of " { $snippet "topic" } "." } ;
-HELP: help
+HELP: print-topic
{ $values { "topic" "an article name or a word" } }
{ $description
- "Displays a help article or documentation associated to a word on " { $link output-stream } "."
+ "Displays a help topic on " { $link output-stream } "."
} ;
+HELP: help
+{ $values { "topic" "an article name or a word" } }
+{ $description
+ "Displays a help topic."
+} ;
HELP: about
{ $values { "vocab" "a vocabulary specifier" } }
{ $description
{ { "object" object } { "?" "a boolean" } } $values
[
"Tests if the object is an instance of the " ,
- first "predicating" word-prop \ $link swap 2array ,
+ first "predicating" word-prop <$link> ,
" class." ,
] { } make $description ;
append
] if ;
-M: word article-content
+<PRIVATE
+
+: (word-help) ( word -- element )
[
- \ $vocabulary over 2array ,
- dup word-help %
- \ $related over 2array ,
- dup get-global [ \ $value swap 2array , ] when*
- \ $definition swap 2array ,
+ {
+ [ \ $vocabulary swap 2array , ]
+ [ word-help % ]
+ [ \ $related swap 2array , ]
+ [ get-global [ \ $value swap 2array , ] when* ]
+ [ \ $definition swap 2array , ]
+ } cleave
] { } make ;
+M: word article-content (word-help) ;
+
+<PRIVATE
+
+: word-with-methods ( word -- elements )
+ [
+ [ (word-help) % ]
+ [ \ $methods swap 2array , ]
+ bi
+ ] { } make ;
+
+PRIVATE>
+
+M: generic article-content word-with-methods ;
+
+M: class article-content word-with-methods ;
+
M: word article-parent "help-parent" word-prop ;
M: word set-article-parent swap "help-parent" set-word-prop ;
] with-nesting
] with-style nl ;
-: help ( topic -- )
+: print-topic ( topic -- )
last-element off dup $title
article-content print-content nl ;
+SYMBOL: help-hook
+
+help-hook global [ [ print-topic ] or ] change-at
+
+: help ( topic -- )
+ help-hook get call ;
+
: about ( vocab -- )
dup require
dup vocab [ ] [
":get ( var -- value ) accesses variables at time of the error" print
":vars - list all variables at error time" print ;
-: :help ( -- )
- error get error-help [ help ] [ "No help for this error. " print ] if*
+: (:help) ( error -- )
+ error-help [ help ] [ "No help for this error. " print ] if*
:help-debugger ;
+: :help ( -- )
+ error get (:help) ;
+
: remove-article ( name -- )
dup articles get key? [
dup unxref-article
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: io.encodings.utf8 io.encodings.ascii io.encodings.binary
-io.files html.streams html.elements html.components help kernel
+io.files html.streams html.elements help kernel
assocs sequences make words accessors arrays help.topics vocabs
tools.vocabs tools.vocabs.browser namespaces prettyprint io
vocabs.loader serialize fry memoize unicode.case math.order
: escape-char ( ch -- )
dup H{
- { CHAR: " "__quote__" }
+ { CHAR: " "__quo__" }
{ CHAR: * "__star__" }
{ CHAR: : "__colon__" }
{ CHAR: < "__lt__" }
{ CHAR: > "__gt__" }
- { CHAR: ? "__question__" }
- { CHAR: \\ "__backslash__" }
+ { CHAR: ? "__que__" }
+ { CHAR: \\ "__back__" }
{ CHAR: | "__pipe__" }
- { CHAR: _ "__underscore__" }
{ CHAR: / "__slash__" }
- { CHAR: \\ "__backslash__" }
{ CHAR: , "__comma__" }
{ CHAR: @ "__at__" }
} at [ % ] [ , ] ?if ;
TUPLE: result title href ;
-M: result link-title title>> ;
-
-M: result link-href href>> ;
-
: offline-apropos ( string index -- results )
load-index swap >lower
'[ [ drop _ ] dip >lower subseq? ] assoc-filter
[ [ title>> ] compare ] sort ;
: article-apropos ( string -- results )
- "articles.idx" temp-file offline-apropos ;
+ "articles.idx" offline-apropos ;
: word-apropos ( string -- results )
- "words.idx" temp-file offline-apropos ;
+ "words.idx" offline-apropos ;
: vocab-apropos ( string -- results )
- "vocabs.idx" temp-file offline-apropos ;
+ "vocabs.idx" offline-apropos ;
vocab-exists? [ "$vocab-link to non-existent vocabulary" throw ] unless
] each ;
-: check-rendering ( word element -- )
- [ help ] with-string-writer drop ;
+: check-rendering ( element -- )
+ [ print-topic ] with-string-writer drop ;
: all-word-help ( words -- seq )
[ word-help ] filter ;
: check-word ( word -- )
dup word-help [
[
- dup word-help [
- 2dup check-examples
- 2dup check-values
- 2dup check-see-also
- 2dup nip check-modules
- 2dup drop check-rendering
- ] assert-depth 2drop
+ dup word-help '[
+ _ _ {
+ [ check-examples ]
+ [ check-values ]
+ [ check-see-also ]
+ [ [ check-rendering ] [ check-modules ] bi* ]
+ } 2cleave
+ ] assert-depth
] check-something
] [ drop ] if ;
: check-article ( article -- )
[
- dup article-content [
- 2dup check-modules check-rendering
- ] assert-depth 2drop
+ dup article-content
+ '[ _ check-rendering _ check-modules ]
+ assert-depth
] check-something ;
: files>vocabs ( -- assoc )
] [
[
swap vocab-heading.
- [ error. nl ] each
+ [ print-error nl ] each
] assoc-each
] if-empty ;
[ "an int" ] [ [ { "int" } $instance ] with-string-writer ] unit-test
-[ ] [ \ quux>> help ] unit-test
-[ ] [ \ >>quux help ] unit-test
-[ ] [ \ blahblah? help ] unit-test
+[ ] [ \ quux>> print-topic ] unit-test
+[ ] [ \ >>quux print-topic ] unit-test
+[ ] [ \ blahblah? print-topic ] unit-test
: fooey "fooey" throw ;
-[ ] [ \ fooey help ] unit-test
+[ ] [ \ fooey print-topic ] unit-test
-[ ] [ gensym help ] unit-test
+[ ] [ gensym print-topic ] unit-test
[
snippet-style get [
last-element off
- >r ($code-style) r> with-nesting
+ [ ($code-style) ] dip with-nesting
] with-style
] ($block) ; inline
: $definition ( element -- )
"Definition" $heading $see ;
+: $methods ( element -- )
+ first methods [
+ "Methods" $heading
+ [ see-all ] ($see)
+ ] unless-empty ;
+
: $value ( object -- )
"Variable value" $heading
"Current value in global namespace:" print-element
] each
] curry each
] H{ } make-assoc keys ;
+
+: <$link> ( topic -- element )
+ \ $link swap 2array ;
\ ; parse-until >array swap set-word-help ; parsing
: ARTICLE:
- location >r
- \ ; parse-until >array [ first2 ] keep 2 tail <article>
- over add-article >link r> remember-definition ; parsing
+ location [
+ \ ; parse-until >array [ first2 ] keep 2 tail <article>
+ over add-article >link
+ ] dip remember-definition ; parsing
: ABOUT:
in get vocab
{ $code "\"resource:work\" \"palindrome\" scaffold-vocab" }
"If you look at the output, you will see that a few files were created in your ``work'' directory. The following phrase will print the full path of your work directory:"
{ $code "\"work\" resource-path ." }
+"The work directory is one of several " { $link "vocabs.roots" } " where Factor searches for vocabularies. It is possible to define new vocabulary roots; see " { $link "add-vocab-roots" } ". To keep things simple in this tutorial, we'll just use the work directory, though."
+$nl
"Open the work directory in your file manager, and open the subdirectory named " { $snippet "palindrome" } ". Inside this subdirectory you will see a file named " { $snippet "palindrome.factor" } ". We will be editing this file."
$nl
"Notice that the file ends with an " { $link POSTPONE: IN: } " form telling Factor that all definitions in this source file should go into the " { $snippet "palindrome" } " vocabulary using the " { $link POSTPONE: IN: } " word:"
IN: hints
-USING: help.markup help.syntax words quotations sequences ;
+USING: help.markup help.syntax words quotations sequences kernel ;
ARTICLE: "hints" "Compiler specialization hints"
"Specialization hints help the compiler generate efficient code."
$nl
-"Specialization hints can help words which call a lot of generic words on the same object - perhaps in a loop - and in most cases, it is anticipated that this object is of a certain class. Using specialization hints, the compiler can be instructed to compile a branch at the beginning of the word; if the branch is taken, the input object has the assumed class, and inlining of generic methods can take place."
+"Specialization hints can help words which call a lot of generic words on the same object - perhaps in a loop - and in most cases, it is anticipated that this object is of a certain class, or even " { $link eq? } " to some literal. Using specialization hints, the compiler can be instructed to compile a branch at the beginning of the word; if the branch is taken, the input object has the assumed class or value, and inlining of generic methods can take place."
$nl
"Specialization hints are not declarations; if the inputs do not match what is specified, the word will still run, possibly slower if the compiled code cannot inline methods because of insufficient static type information."
$nl
{ $description "Outputs the definition of a word after it has been split into specialized branches. This is the definition which will actually be compiled by the compiler." } ;
HELP: HINTS:
-{ $values { "defspec" "a definition specifier" } { "hints..." "a list of sequences of classes" } }
+{ $values { "defspec" "a definition specifier" } { "hints..." "a list of sequences of classes or literals" } }
{ $description "Defines specialization hints for a word or a method."
$nl
-"Each sequence of classes in the list will cause a specialized version of the word to be compiled." }
+"Each sequence in the list will cause a specialized version of the word to be compiled. Classes are tested for using their predicate, and literals are tested using " { $link eq? } "." }
{ $examples "The " { $link append } " word has a specializer for the very common case where two strings or two arrays are appended:"
{ $code "HINTS: append { string string } { array array } ;" }
"Specializers can also be defined on methods:"
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 ;
+math generic generic.standard generic.standard.engines classes ;
IN: hints
-: (make-specializer) ( class picker -- quot )
- swap "predicate" word-prop append ;
+GENERIC: specializer-predicate ( spec -- quot )
-: make-specializer ( classes -- quot )
+M: class specializer-predicate "predicate" word-prop ;
+
+M: object specializer-predicate '[ _ eq? ] ;
+
+GENERIC: specializer-declaration ( spec -- class )
+
+M: class specializer-declaration ;
+
+M: object specializer-declaration class ;
+
+: make-specializer ( specs -- quot )
dup length <reversed>
[ (picker) 2array ] 2map
[ drop object eq? not ] assoc-filter
[ [ t ] ] [
- [ (make-specializer) ] { } assoc>map
+ [ swap specializer-predicate append ] { } assoc>map
unclip [ swap [ f ] \ if 3array append [ ] like ] reduce
] if-empty ;
: specializer-cases ( quot word -- default alist )
dup [ array? ] all? [ 1array ] unless [
[ make-specializer ] keep
- '[ _ declare ] pick append
+ [ specializer-declaration ] map '[ _ declare ] pick append
] { } map>assoc ;
: method-declaration ( method -- quot )
: html-word ( name def effect -- )
#! Define 'word creating' word to allow
#! dynamically creating words.
- >r >r elements-vocab create r> r> define-declared ;
+ [ elements-vocab create ] 2dip define-declared ;
-: <foo> ( str -- <str> ) "<" swap ">" 3append ;
+: <foo> ( str -- <str> ) "<" ">" surround ;
: def-for-html-word-<foo> ( name -- )
#! Return the name and code for the <foo> patterned
#! word.
foo> [ ">" write-html ] (( -- )) html-word ;
-: </foo> ( str -- </str> ) "</" swap ">" 3append ;
+: </foo> ( str -- </str> ) "</" ">" surround ;
: def-for-html-word-</foo> ( name -- )
#! Return the name and code for the </foo> patterned
#! word.
</foo> dup '[ _ write-html ] (( -- )) html-word ;
-: <foo/> ( str -- <str/> ) "<" swap "/>" 3append ;
+: <foo/> ( str -- <str/> ) "<" "/>" surround ;
: def-for-html-word-<foo/> ( name -- )
#! Return the name and code for the <foo/> patterned
"font-family: " % % "; " % ;
: apply-style ( style key quot -- style gadget )
- >r over at r> when* ; inline
+ [ over at ] dip when* ; inline
: make-css ( style quot -- str )
"" make nip ; inline
stream>> stream-flush ;
M: html-stream stream-write1
- >r 1string r> stream-write ;
+ [ 1string ] dip stream-write ;
M: html-stream stream-write
- not-a-div >r escape-string r> stream>> stream-write ;
+ not-a-div [ escape-string ] dip stream>> stream-write ;
M: html-stream stream-format
- >r html over at [ >r escape-string r> ] unless r>
+ [ html over at [ [ escape-string ] dip ] unless ] dip
format-html-span ;
M: html-stream stream-nl
namespaces make classes.tuple assocs splitting words arrays io
io.files io.encodings.utf8 io.streams.string unicode.case
mirrors math urls present multiline quotations xml logging
+continuations
xml.data
html.forms
html.elements
USING: assocs namespaces make kernel sequences accessors
combinators strings splitting io io.streams.string present
xml.writer xml.data xml.entities html.forms
-html.templates html.templates.chloe.syntax ;
+html.templates html.templates.chloe.syntax continuations ;
IN: html.templates.chloe.compiler
: chloe-attrs-only ( assoc -- assoc' )
{ [ dup [ tag? ] [ xml? ] bi or ] [ compile-tag ] }
{ [ dup string? ] [ escape-string [write] ] }
{ [ dup comment? ] [ drop ] }
- [ [ write-item ] [code-with] ]
+ [ [ write-xml-chunk ] [code-with] ]
} cond ;
: with-compiler ( quot -- quot' )
USING: io io.files io.streams.string io.encodings.utf8
html.templates html.templates.fhtml kernel
-tools.test sequences parser ;
+tools.test sequences parser splitting prettyprint ;
IN: html.templates.fhtml.tests
: test-template ( path -- ? )
"resource:basis/html/templates/fhtml/test/"
prepend
- [
- ".fhtml" append <fhtml> [ call-template ] with-string-writer
- ] keep
- ".html" append utf8 file-contents = ;
+ [ ".fhtml" append <fhtml> [ call-template ] with-string-writer ]
+ [ ".html" append utf8 file-contents ] bi
+ [ . . ] [ = ] 2bi ;
[ t ] [ "example" test-template ] unit-test
[ t ] [ "bug" test-template ] unit-test
USING: accessors assocs kernel math math.parser namespaces make
sequences io io.sockets io.streams.string io.files io.timeouts
strings splitting calendar continuations accessors vectors
-math.order hashtables byte-arrays prettyprint destructors
+math.order hashtables byte-arrays destructors
io.encodings
io.encodings.string
io.encodings.ascii
+io.encodings.utf8
io.encodings.8-bit
io.encodings.binary
io.streams.duplex
-fry debugger summary ascii urls urls.encoding present
+fry ascii urls urls.encoding present
http http.parsers ;
IN: http.client
M: post-data >post-data ;
-M: string >post-data "application/octet-stream" <post-data> ;
+M: string >post-data utf8 encode "application/octet-stream" <post-data> ;
M: byte-array >post-data "application/octet-stream" <post-data> ;
-M: assoc >post-data assoc>query "application/x-www-form-urlencoded" <post-data> ;
+M: assoc >post-data assoc>query ascii encode "application/x-www-form-urlencoded" <post-data> ;
M: f >post-data ;
[ >post-data ] change-post-data ;
: write-post-data ( request -- request )
- dup method>> "POST" = [ dup post-data>> raw>> write ] when ;
+ dup method>> [ "POST" = ] [ "PUT" = ] bi or [ dup post-data>> raw>> write ] when ;
: write-request ( request -- )
unparse-post-data
write-request-line
write-request-header
+ binary encode-output
write-post-data
flush
drop ;
ERROR: too-many-redirects ;
-M: too-many-redirects summary
- drop
- [ "Redirection limit of " % max-redirects # " exceeded" % ] "" make ;
-
<PRIVATE
DEFER: (with-http-request)
PRIVATE>
-: success? ( code -- ? ) 200 = ;
+: success? ( code -- ? ) 200 299 between? ;
ERROR: download-failed response ;
-M: download-failed error.
- "HTTP request failed:" print nl
- response>> . ;
-
: check-response ( response -- response )
dup code>> success? [ download-failed ] unless ;
: http-post ( post-data url -- response data )
<post-request> http-request ;
+
+USING: vocabs vocabs.loader ;
+
+"debugger" vocab [ "http.client.debugger" require ] when
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel summary debugger io make math.parser
+prettyprint http.client accessors ;
+IN: http.client.debugger
+
+M: too-many-redirects summary
+ drop
+ [ "Redirection limit of " % max-redirects # " exceeded" % ] "" make ;
+
+M: download-failed error.
+ "HTTP request failed:" print nl
+ response>> . ;
io.streams.string io.encodings.utf8 io.encodings.8-bit
io.encodings.binary io.encodings.string kernel arrays splitting
sequences assocs io.sockets db db.sqlite continuations urls
-hashtables accessors ;
+hashtables accessors namespaces ;
IN: http.tests
[ "text/plain" latin1 ] [ "text/plain" parse-content-type ] unit-test
[ "application/octet-stream" binary ] [ "application/octet-stream" parse-content-type ] unit-test
+[ { } ] [ "" parse-cookie ] unit-test
+[ { } ] [ "" parse-set-cookie ] unit-test
+
+! Make sure that totally invalid cookies don't confuse us
+[ { } ] [ "hello world; how are you" parse-cookie ] unit-test
+
: lf>crlf "\n" split "\r\n" join ;
STRING: read-request-test-1
;
read-response-test-1' 1array [
+ URL" http://localhost/" url set
read-response-test-1 lf>crlf
[ read-response ] with-string-reader
[ write-response ] with-string-writer
! Copyright (C) 2003, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel combinators math namespaces make
-assocs sequences splitting sorting sets debugger
-strings vectors hashtables quotations arrays byte-arrays
-math.parser calendar calendar.format present urls
+USING: accessors kernel combinators math namespaces make assocs
+sequences splitting sorting sets strings vectors hashtables
+quotations arrays byte-arrays math.parser calendar
+calendar.format present urls
io io.encodings io.encodings.iana io.encodings.binary
io.encodings.8-bit
{ [ dup real? ] [ number>string ] }
[ ]
} cond
- [ check-cookie-string ] bi@ "=" swap 3append ,
+ [ check-cookie-string ] bi@ "=" glue ,
]
} case ;
'space' ,
'attr' ,
'space' ,
- [ "=" token , 'space' , 'value' , ] seq* [ peek ] action
- epsilon [ drop f ] action
- 2choice ,
+ [ "=" token , 'space' , 'value' , ] seq* [ peek ] action optional ,
'space' ,
] seq* ;
: 'av-pairs' ( -- parser )
'av-pair' ";" token list-of optional ;
-PEG: (parse-set-cookie) ( string -- alist ) 'av-pairs' just ;
+PEG: (parse-set-cookie) ( string -- alist )
+ 'av-pairs' just [ sift ] action ;
: 'cookie-value' ( -- parser )
[
'space' ,
'value' ,
'space' ,
- ] seq* ;
+ ] seq*
+ [ ";,=" member? not ] satisfy repeat1 [ drop f ] action
+ 2choice ;
PEG: (parse-cookie) ( string -- alist )
- 'cookie-value' [ ";," member? ] satisfy list-of optional just ;
+ 'cookie-value' [ ";," member? ] satisfy list-of
+ optional just [ sift ] action ;
! See http://factorcode.org/license.txt for BSD license.\r
USING: calendar io io.files kernel math math.order\r
math.parser namespaces parser sequences strings\r
-assocs hashtables debugger mime-types sorting logging\r
+assocs hashtables debugger mime.types sorting logging\r
calendar.format accessors splitting\r
io.encodings.binary fry xml.entities destructors urls\r
html.elements html.templates.fhtml\r
] [ keys ] if ;
: describe* ( obj mirror keys -- )
- rot summary.
- [
- drop
- ] [
+ [ summary. ] 2dip
+ [ drop ] [
dup enum? [ +sequence+ on ] when
standard-table-style [
swap [ -rot describe-row ] curry each-index
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test interpolate ;
+USING: interpolate io.streams.string namespaces tools.test locals ;
IN: interpolate.tests
+
+[ "Hello, Jane." ] [
+ "Jane" "name" set
+ [ "Hello, ${name}." interpolate ] with-string-writer
+] unit-test
+
+[ "Sup Dawg, we heard you liked rims, so we put rims on your rims so you can roll while you roll." ] [
+ "Dawg" "name" set
+ "rims" "noun" set
+ "roll" "verb" set
+ [ "Sup ${name}, we heard you liked ${noun}, so we put ${noun} on your ${noun} so you can ${verb} while you ${verb}." interpolate ] with-string-writer
+] unit-test
+
+[ "Oops, I accidentally the whole economy..." ] [
+ [let | noun [ "economy" ] |
+ [ I[ Oops, I accidentally the whole ${noun}...]I ] with-string-writer
+ ]
+] unit-test
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: io kernel macros make multiline namespaces parser
-peg.ebnf present sequences strings ;
+present sequences strings splitting fry accessors ;
IN: interpolate
+TUPLE: interpolate-var name ;
+
+: (parse-interpolate) ( string -- )
+ [
+ "${" split1-slice [ >string , ] [
+ [
+ "}" split1-slice
+ [ >string interpolate-var boa , ]
+ [ (parse-interpolate) ] bi*
+ ] when*
+ ] bi*
+ ] unless-empty ;
+
+: parse-interpolate ( string -- seq )
+ [ (parse-interpolate) ] { } make ;
+
MACRO: interpolate ( string -- )
-[EBNF
-var = "${" [^}]+ "}" => [[ second >string [ get present write ] curry ]]
-text = [^$]+ => [[ >string [ write ] curry ]]
-interpolate = (var|text)* => [[ [ ] join ]]
-EBNF] ;
+ parse-interpolate [
+ dup interpolate-var?
+ [ name>> '[ _ get present write ] ]
+ [ '[ _ write ] ]
+ if
+ ] map [ ] join ;
-EBNF: interpolate-locals
-var = "${" [^}]+ "}" => [[ [ second >string search , [ present write ] % ] [ ] make ]]
-text = [^$]+ => [[ [ >string , [ write ] % ] [ ] make ]]
-interpolate = (var|text)* => [[ [ ] join ]]
-;EBNF
+: interpolate-locals ( string -- quot )
+ parse-interpolate [
+ dup interpolate-var?
+ [ name>> search '[ _ present write ] ]
+ [ '[ _ write ] ]
+ if
+ ] map [ ] join ;
: I[ "]I" parse-multiline-string
interpolate-locals parsed \ call parsed ; parsing
first2 between? ;\r
\r
: all-intervals ( sequence -- intervals )\r
- [ >r dup number? [ dup 2array ] when r> ] { } assoc-map-as ;\r
+ [ [ dup number? [ dup 2array ] when ] dip ] { } assoc-map-as ;\r
\r
: disjoint? ( node1 node2 -- ? )\r
[ second ] [ first ] bi* < ;\r
: buffer-set ( string buffer -- )
over >byte-array over ptr>> byte-array>memory
- >r length r> buffer-reset ;
+ [ length ] dip buffer-reset ;
: string>buffer ( string -- buffer )
dup length <buffer> tuck buffer-set ;
[ { CHAR: x } ] [ { HEX: fe HEX: ff 0 CHAR: x } utf16 decode >array ] unit-test
[ { HEX: ff HEX: fe 120 0 52 216 30 221 } ] [ { CHAR: x HEX: 1d11e } utf16 encode >array ] unit-test
-
-: correct-endian
- code>> little-endian? [ utf16le = ] [ utf16be = ] if ;
-
-[ t ] [ B{ } utf16n <byte-reader> correct-endian ] unit-test
-[ t ] [ utf16n <byte-writer> correct-endian ] unit-test
: quad-be ( stream byte -- stream char )
double-be over stream-read1 [
dup -2 shift BIN: 110111 number= [
- >r 2 shift r> BIN: 11 bitand bitor
+ [ 2 shift ] dip BIN: 11 bitand bitor
over stream-read1 swap append-nums HEX: 10000 +
] [ 2drop dup stream-read1 drop replacement-char ] if
] when* ;
--- /dev/null
+USING: help.markup help.syntax ;
+IN: io.encodings.utf16n
+
+HELP: utf16n
+{ $class-description "The encoding descriptor for UTF-16 without a byte order mark in native endian order. This is useful mostly for FFI calls which take input of strings of the type wchar_t*" }
+{ $see-also "encodings-introduction" } ;
--- /dev/null
+USING: accessors alien.c-types kernel
+io.encodings.utf16 io.streams.byte-array tools.test ;
+IN: io.encodings.utf16n
+
+: correct-endian
+ code>> little-endian? [ utf16le = ] [ utf16be = ] if ;
+
+[ t ] [ B{ } utf16n <byte-reader> correct-endian ] unit-test
+[ t ] [ utf16n <byte-writer> correct-endian ] unit-test
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.c-types io.encodings io.encodings.utf16 kernel ;
+IN: io.encodings.utf16n
+
+! Native-order UTF-16
+
+SINGLETON: utf16n
+
+: utf16n ( -- descriptor )
+ little-endian? utf16le utf16be ? ; foldable
+
+M: utf16n <decoder> drop utf16n <decoder> ;
+
+M: utf16n <encoder> drop utf16n <encoder> ;
+++ /dev/null
-Doug Coleman
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: help.markup help.syntax io.streams.string strings ;
-IN: io.files.listing
-
-HELP: directory.
-{ $values
- { "path" "a pathname string" }
-}
-{ $description "Prints information about all files in a directory to the output stream in a cross-platform way similar to the Unix " { $snippet "ls" } " command." } ;
-
-ARTICLE: "io.files.listing" "Listing files"
-"The " { $vocab-link "io.files.listing" } " vocabulary implements directory file listing in a cross-platform way." $nl
-"Listing a directory:"
-{ $subsection directory. } ;
-
-ABOUT: "io.files.listing"
+++ /dev/null
-! Copyright (C) 2008 Your name.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test io.files.listing strings kernel ;
-IN: io.files.listing.tests
-
-[ ] [ "" directory. ] unit-test
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays combinators io io.files kernel
-math.parser sequences system vocabs.loader calendar ;
-
-IN: io.files.listing
-
-<PRIVATE
-
-: ls-time ( timestamp -- string )
- [ hour>> ] [ minute>> ] bi
- [ number>string 2 CHAR: 0 pad-left ] bi@ ":" swap 3append ;
-
-: ls-timestamp ( timestamp -- string )
- [ month>> month-abbreviation ]
- [ day>> number>string 2 CHAR: \s pad-left ]
- [
- dup year>> dup now year>> =
- [ drop ls-time ] [ nip number>string ] if
- 5 CHAR: \s pad-left
- ] tri 3array " " join ;
-
-: read>string ( ? -- string ) "r" "-" ? ; inline
-
-: write>string ( ? -- string ) "w" "-" ? ; inline
-
-: execute>string ( ? -- string ) "x" "-" ? ; inline
-
-HOOK: (directory.) os ( path -- lines )
-
-PRIVATE>
-
-: directory. ( path -- )
- [ (directory.) ] with-directory-files [ print ] each ;
-
-{
- { [ os unix? ] [ "io.files.listing.unix" ] }
- { [ os windows? ] [ "io.files.listing.windows" ] }
-} cond require
+++ /dev/null
-unportable
+++ /dev/null
-Doug Coleman
+++ /dev/null
-unportable
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors combinators kernel system unicode.case
-io.unix.files io.files.listing generalizations strings
-arrays sequences io.files math.parser unix.groups unix.users
-io.files.listing.private ;
-IN: io.files.listing.unix
-
-<PRIVATE
-
-: unix-execute>string ( str bools -- str' )
- swap {
- { { t t } [ >lower ] }
- { { t f } [ >upper ] }
- { { f t } [ drop "x" ] }
- [ 2drop "-" ]
- } case ;
-
-: permissions-string ( permissions -- str )
- {
- [ type>> file-type>ch 1string ]
- [ user-read? read>string ]
- [ user-write? write>string ]
- [ [ uid? ] [ user-execute? ] bi 2array "s" unix-execute>string ]
- [ group-read? read>string ]
- [ group-write? write>string ]
- [ [ gid? ] [ group-execute? ] bi 2array "s" unix-execute>string ]
- [ other-read? read>string ]
- [ other-write? write>string ]
- [ [ sticky? ] [ other-execute? ] bi 2array "t" unix-execute>string ]
- } cleave 10 narray concat ;
-
-M: unix (directory.) ( path -- lines )
- [ [
- [
- dup file-info
- {
- [ permissions-string ]
- [ nlink>> number>string 3 CHAR: \s pad-left ]
- ! [ uid>> ]
- ! [ gid>> ]
- [ size>> number>string 15 CHAR: \s pad-left ]
- [ modified>> ls-timestamp ]
- } cleave 4 narray swap suffix " " join
- ] map
- ] with-group-cache ] with-user-cache ;
-
-PRIVATE>
+++ /dev/null
-Doug Coleman
+++ /dev/null
-unportable
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors calendar.format combinators io.files
-kernel math.parser sequences splitting system io.files.listing
-generalizations io.files.listing.private ;
-IN: io.files.listing.windows
-
-<PRIVATE
-
-: directory-or-size ( file-info -- str )
- dup directory? [
- drop "<DIR>" 20 CHAR: \s pad-right
- ] [
- size>> number>string 20 CHAR: \s pad-left
- ] if ;
-
-M: windows (directory.) ( entries -- lines )
- [
- dup file-info {
- [ modified>> timestamp>ymdhms ]
- [ directory-or-size ]
- } cleave 2 narray swap suffix " " join
- ] map ;
-
-PRIVATE>
--- /dev/null
+USING: help.markup help.syntax io io.ports kernel math
+io.files.unique.private math.parser io.files ;
+IN: io.files.unique
+
+HELP: temporary-path
+{ $values
+ { "path" "a pathname string" }
+}
+{ $description "A hook that returns the path of the temporary directory in a platform-specific way. Does not guarantee that path is writable by your user." } ;
+
+HELP: touch-unique-file
+{ $values
+ { "path" "a pathname string" }
+}
+{ $description "Creates a unique file in a platform-specific way. The file is guaranteed not to exist and is openable by your user." } ;
+
+HELP: unique-length
+{ $description "A symbol storing the number of random characters inserted between the prefix and suffix of a random file name." } ;
+
+HELP: unique-retries
+{ $description "The number of times to try creating a unique file in case of a name collision. The odds of a name collision are extremely low with a sufficient " { $link unique-length } "." } ;
+
+{ unique-length unique-retries } related-words
+
+HELP: make-unique-file ( prefix suffix -- path )
+{ $values { "prefix" "a string" } { "suffix" "a string" }
+{ "path" "a pathname string" } }
+{ $description "Creates a file that is guaranteed not to exist in a platform-specific temporary directory. The file name is composed of a prefix, a number of random digits and letters, and the suffix. Returns the full pathname." }
+{ $errors "Throws an error if a new unique file cannot be created after a number of tries. The most likely error is incorrect directory permissions on the temporary directory." } ;
+
+HELP: make-unique-file*
+{ $values
+ { "prefix" null } { "suffix" null }
+ { "path" "a pathname string" }
+}
+{ $description "Creates a file that is guaranteed not to exist in the directory in the " { $link current-directory } " variable. The file name is composed of a prefix, a number of random digits and letters, and the suffix. Returns the full pathname." } ;
+
+{ make-unique-file make-unique-file* with-unique-file } related-words
+
+HELP: with-unique-file ( prefix suffix quot: ( path -- ) -- )
+{ $values { "prefix" "a string" } { "suffix" "a string" }
+{ "quot" "a quotation" } }
+{ $description "Creates a file with " { $link make-unique-file } " and calls the quotation with the path name on the stack." }
+{ $notes "The unique file will be deleted after calling this word." } ;
+
+HELP: make-unique-directory ( -- path )
+{ $values { "path" "a pathname string" } }
+{ $description "Creates a directory that is guaranteed not to exist in a platform-specific temporary directory and returns the full pathname." }
+{ $errors "Throws an error if the directory cannot be created after a number of tries. The most likely error is incorrect directory permissions on the temporary directory." } ;
+
+HELP: with-unique-directory ( quot -- )
+{ $values { "quot" "a quotation" } }
+{ $description "Creates a directory with " { $link make-unique-directory } " and calls the quotation with the pathname on the stack using the " { $link with-directory } " combinator. The quotation can access the " { $link current-directory } " symbol for the name of the temporary directory." }
+{ $notes "The directory will be deleted after calling this word, even if an error is thrown in the quotation." } ;
+
+ARTICLE: "io.files.unique" "Temporary files"
+"The " { $vocab-link "io.files.unique" } " vocabulary implements cross-platform temporary file creation in a high-level and secure way." $nl
+"Files:"
+{ $subsection make-unique-file }
+{ $subsection make-unique-file* }
+{ $subsection with-unique-file }
+"Directories:"
+{ $subsection make-unique-directory }
+{ $subsection with-unique-directory } ;
+
+ABOUT: "io.files.unique"
--- /dev/null
+USING: io.encodings.ascii sequences strings io io.files accessors
+tools.test kernel io.files.unique namespaces continuations ;
+IN: io.files.unique.tests
+
+[ 123 ] [
+ "core" ".test" [
+ [ [ 123 CHAR: a <repetition> ] dip ascii set-file-contents ]
+ [ file-info size>> ] bi
+ ] with-unique-file
+] unit-test
+
+[ t ] [
+ [ current-directory get file-info directory? ] with-unique-directory
+] unit-test
+
+[ t ] [
+ current-directory get
+ [ [ "FAILDOG" throw ] with-unique-directory ] [ drop ] recover
+ current-directory get =
+] unit-test
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel math math.bitwise math.parser random sequences
+continuations namespaces io.files io arrays system
+combinators vocabs.loader fry io.backend ;
+IN: io.files.unique
+
+HOOK: touch-unique-file io-backend ( path -- )
+HOOK: temporary-path io-backend ( -- path )
+
+SYMBOL: unique-length
+SYMBOL: unique-retries
+
+10 unique-length set-global
+10 unique-retries set-global
+
+<PRIVATE
+
+: random-letter ( -- ch )
+ 26 random { CHAR: a CHAR: A } random + ;
+
+: random-ch ( -- ch )
+ { t f } random
+ [ 10 random CHAR: 0 + ] [ random-letter ] if ;
+
+: random-name ( n -- string )
+ [ random-ch ] "" replicate-as ;
+
+PRIVATE>
+
+: (make-unique-file) ( path prefix suffix -- path )
+ '[
+ _ _ _ unique-length get random-name glue append-path
+ dup touch-unique-file
+ ] unique-retries get retry ;
+
+: make-unique-file ( prefix suffix -- path )
+ [ temporary-path ] 2dip (make-unique-file) ;
+
+: make-unique-file* ( prefix suffix -- path )
+ [ current-directory get ] 2dip (make-unique-file) ;
+
+: with-unique-file ( prefix suffix quot: ( path -- ) -- )
+ [ make-unique-file ] dip [ delete-file ] bi ; inline
+
+: make-unique-directory ( -- path )
+ [
+ temporary-path unique-length get random-name append-path
+ dup make-directory
+ ] unique-retries get retry ;
+
+: with-unique-directory ( quot: ( -- ) -- )
+ [ make-unique-directory ] dip
+ '[ _ with-directory ] [ delete-tree ] bi ; inline
+
+{
+ { [ os unix? ] [ "io.unix.files.unique" ] }
+ { [ os windows? ] [ "io.windows.files.unique" ] }
+} cond require
{ $description "Launches a process and redirects its input and output via a pair of pipes which may be read and written as a stream of the given encoding." } ;
HELP: wait-for-process
-{ $values { "process" process } { "status" integer } }
-{ $description "If the process is still running, waits for it to exit, otherwise outputs the exit code immediately. Can be called multiple times on the same process." } ;
+{ $values { "process" process } { "status" object } }
+{ $description "If the process is still running, waits for it to exit, otherwise outputs the status code immediately. Can be called multiple times on the same process." }
+{ $notes "The status code is operating system specific; it may be an integer, or another object (the latter is the case on Unix if the process was killed by a signal). However, one cross-platform behavior code can rely on is that a status code of 0 indicates success." } ;
ARTICLE: "io.launcher.descriptors" "Launch descriptors"
"Words which launch processes can take either a command line string, a sequence of command line arguments, or a " { $link process } "."
assocs combinators vocabs.loader init threads continuations
math accessors concurrency.flags destructors environment
io io.backend io.timeouts io.pipes io.pipes.private io.encodings
-io.streams.duplex io.ports debugger prettyprint summary ;
+io.streams.duplex io.ports debugger prettyprint summary
+calendar ;
IN: io.launcher
TUPLE: process < identity-tuple
: wait-loop ( -- )
processes get assoc-empty?
[ wait-flag get-global lower-flag ]
- [ wait-for-processes [ 100 sleep ] when ] if ;
+ [ wait-for-processes [ 100 milliseconds sleep ] when ] if ;
: start-wait-thread ( -- )
<flag> wait-flag set-global
process>> . ;
: wait-for-success ( process -- )
- dup wait-for-process dup zero?
+ dup wait-for-process dup 0 =
[ 2drop ] [ process-failed ] if ;
: try-process ( desc -- )
: <process-reader*> ( desc encoding -- stream process )
[
- >r (pipe) {
- [ |dispose drop ]
- [
- swap >process
- [ swap out>> or ] change-stdout
- run-detached
- ]
- [ out>> dispose ]
- [ in>> <input-port> ]
- } cleave r> <decoder> swap
+ [
+ (pipe) {
+ [ |dispose drop ]
+ [
+ swap >process
+ [ swap out>> or ] change-stdout
+ run-detached
+ ]
+ [ out>> dispose ]
+ [ in>> <input-port> ]
+ } cleave
+ ] dip <decoder> swap
] with-destructors ;
: <process-reader> ( desc encoding -- stream )
: <process-writer*> ( desc encoding -- stream process )
[
- >r (pipe) {
- [ |dispose drop ]
- [
- swap >process
- [ swap in>> or ] change-stdin
- run-detached
- ]
- [ in>> dispose ]
- [ out>> <output-port> ]
- } cleave r> <encoder> swap
+ [
+ (pipe) {
+ [ |dispose drop ]
+ [
+ swap >process
+ [ swap in>> or ] change-stdin
+ run-detached
+ ]
+ [ in>> dispose ]
+ [ out>> <output-port> ]
+ } cleave
+ ] dip <encoder> swap
] with-destructors ;
: <process-writer> ( desc encoding -- stream )
: <process-stream*> ( desc encoding -- stream process )
[
- >r (pipe) (pipe) {
- [ [ |dispose drop ] bi@ ]
- [
- rot >process
- [ swap in>> or ] change-stdin
- [ swap out>> or ] change-stdout
- run-detached
- ]
- [ [ out>> dispose ] [ in>> dispose ] bi* ]
- [ [ in>> <input-port> ] [ out>> <output-port> ] bi* ]
- } 2cleave r> <encoder-duplex> swap
+ [
+ (pipe) (pipe) {
+ [ [ |dispose drop ] bi@ ]
+ [
+ rot >process
+ [ swap in>> or ] change-stdin
+ [ swap out>> or ] change-stdout
+ run-detached
+ ]
+ [ [ out>> dispose ] [ in>> dispose ] bi* ]
+ [ [ in>> <input-port> ] [ out>> <output-port> ] bi* ]
+ } 2cleave
+ ] dip <encoder-duplex> swap
] with-destructors ;
: <process-stream> ( desc encoding -- stream )
f >>handle
drop ;
-GENERIC: underlying-handle ( stream -- handle )
-
-M: port underlying-handle handle>> ;
-
-ERROR: invalid-duplex-stream ;
-
-M: duplex-stream underlying-handle
- [ in>> underlying-handle ]
- [ out>> underlying-handle ] bi
- [ = [ invalid-duplex-stream ] when ] keep ;
-
-M: encoder underlying-handle
- stream>> underlying-handle ;
-
-M: decoder underlying-handle
- stream>> underlying-handle ;
-
{
{ [ os unix? ] [ "io.unix.launcher" require ] }
{ [ os winnt? ] [ "io.windows.nt.launcher" require ] }
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.alien ;
+IN: io.mmap.alien
+
+<< "void*" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.bool ;
+IN: io.mmap.bool
+
+<< "bool" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.char ;
+IN: io.mmap.char
+
+<< "char" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.double ;
+IN: io.mmap.double
+
+<< "double" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.float ;
+IN: io.mmap.float
+
+<< "float" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: io.mmap functors accessors alien.c-types math kernel
+words fry ;
+IN: io.mmap.functor
+
+SLOT: address
+SLOT: length
+
+: mapped-file>direct ( mapped-file type -- alien length )
+ [ [ address>> ] [ length>> ] bi ] dip
+ heap-size [ 1- + ] keep /i ;
+
+FUNCTOR: define-mapped-array ( T -- )
+
+<mapped-A> DEFINES <mapped-${T}-array>
+<A> IS <direct-${T}-array>
+with-mapped-A-file DEFINES with-mapped-${T}-file
+
+WHERE
+
+: <mapped-A> ( mapped-file -- direct-array )
+ T mapped-file>direct <A> execute ; inline
+
+: with-mapped-A-file ( path length quot -- )
+ '[ <mapped-A> execute @ ] with-mapped-file ; inline
+
+;FUNCTOR
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.int ;
+IN: io.mmap.int
+
+<< "int" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.long ;
+IN: io.mmap.long
+
+<< "long" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.longlong ;
+IN: io.mmap.longlong
+
+<< "longlong" define-mapped-array >>
\ No newline at end of file
} ;
HELP: <mapped-file>
-{ $values { "path" "a pathname string" } { "length" integer } { "mmap" mapped-file } }
-{ $contract "Opens a file and maps the first " { $snippet "length" } " bytes into memory. The length is permitted to exceed the length of the file on disk, in which case the remaining space is padded with zero bytes." }
-{ $notes "You must call " { $link close-mapped-file } " when you are finished working with the returned object, to reclaim resources. The " { $link with-mapped-file } " provides an abstraction which can close the mapped file for you." }
+{ $values { "path" "a pathname string" } { "mmap" mapped-file } }
+{ $contract "Opens a file and maps its contents into memory. The length is permitted to exceed the length of the file on disk, in which case the remaining space is padded with zero bytes." }
+{ $notes "You must call " { $link dispose } " when you are finished working with the returned object, to reclaim resources. The " { $link with-mapped-file } " provides an abstraction which can close the mapped file for you." }
{ $errors "Throws an error if a memory mapping could not be established." } ;
HELP: with-mapped-file
-{ $values { "path" "a pathname string" } { "length" integer } { "quot" { $quotation "( mmap -- )" } } }
+{ $values { "path" "a pathname string" } { "quot" { $quotation "( mmap -- )" } } }
{ $contract "Opens a file and maps its contents into memory, passing the " { $link mapped-file } " instance to the quotation. The mapped file is disposed of when the quotation returns, or if an error is thrown." }
{ $errors "Throws an error if a memory mapping could not be established." } ;
{ $contract "Releases system resources associated with the mapped file. This word should not be called by user code; use " { $link dispose } " instead." }
{ $errors "Throws an error if a memory mapping could not be established." } ;
+ARTICLE: "io.mmap.arrays" "Memory-mapped arrays"
+"Mapped file can be viewed as a sequence using the words in sub-vocabularies of " { $vocab-link "io.mmap" } ". For each primitive C type " { $snippet "T" } ", a set of words are defined in the vocabulary named " { $snippet "io.mmap.T" } ":"
+{ $table
+ { { $snippet "<mapped-T-array>" } { "Wraps a " { $link mapped-file } " in a sequence; stack effect " { $snippet "( mapped-file -- direct-array )" } } }
+ { { $snippet "with-mapped-T-file" } { "Maps a file into memory and wraps it in a sequence by combining " { $link with-mapped-file } " and " { $snippet "<mapped-T-array>" } "; stack effect " { $snippet "( path quot -- )" } } }
+}
+"The primitive C types for which mapped arrays exist:"
+{ $list
+ { $snippet "char" }
+ { $snippet "uchar" }
+ { $snippet "short" }
+ { $snippet "ushort" }
+ { $snippet "int" }
+ { $snippet "uint" }
+ { $snippet "long" }
+ { $snippet "ulong" }
+ { $snippet "longlong" }
+ { $snippet "ulonglong" }
+ { $snippet "float" }
+ { $snippet "double" }
+ { $snippet "void*" }
+ { $snippet "bool" }
+} ;
+
+ARTICLE: "io.mmap.low-level" "Reading and writing mapped files directly"
+"Data can be read and written from the " { $link mapped-file } " by applying low-level alien words to the " { $slot "address" } " slot. See " { $link "reading-writing-memory" } "." ;
+
ARTICLE: "io.mmap" "Memory-mapped files"
"The " { $vocab-link "io.mmap" } " vocabulary implements support for memory-mapped files."
{ $subsection <mapped-file> }
$nl
"A utility combinator which wraps the above:"
{ $subsection with-mapped-file }
-"Memory mapped files implement the " { $link "sequence-protocol" } " and present themselves as a sequence of bytes. The underlying memory area can also be accessed directly with the " { $snippet "address" } " slot." $nl
-"Data can be read and written from the memory area using alien words. See " { $link "reading-writing-memory" } "." ;
+"Instances of " { $link mapped-file } " don't support any interesting operations in themselves. There are two facilities for accessing their contents:"
+{ $subsection "io.mmap.arrays" }
+{ $subsection "io.mmap.low-level" } ;
ABOUT: "io.mmap"
-USING: io io.mmap io.files kernel tools.test continuations
-sequences io.encodings.ascii accessors ;
+USING: io io.mmap io.mmap.char io.files kernel tools.test
+continuations sequences io.encodings.ascii accessors ;
IN: io.mmap.tests
[ "mmap-test-file.txt" temp-file delete-file ] ignore-errors
[ ] [ "12345" "mmap-test-file.txt" temp-file ascii set-file-contents ] unit-test
-[ ] [ "mmap-test-file.txt" temp-file dup file-info size>> [ CHAR: 2 0 pick set-nth drop ] with-mapped-file ] unit-test
-[ 5 ] [ "mmap-test-file.txt" temp-file dup file-info size>> [ length ] with-mapped-file ] unit-test
+[ ] [ "mmap-test-file.txt" temp-file [ CHAR: 2 0 pick set-nth drop ] with-mapped-char-file ] unit-test
+[ 5 ] [ "mmap-test-file.txt" temp-file [ length ] with-mapped-char-file ] unit-test
[ "22345" ] [ "mmap-test-file.txt" temp-file ascii file-contents ] unit-test
[ "mmap-test-file.txt" temp-file delete-file ] ignore-errors
! Copyright (C) 2007, 2008 Doug Coleman, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: continuations destructors io.backend kernel quotations
-sequences system alien alien.accessors accessors
-sequences.private system vocabs.loader combinators ;
+USING: continuations destructors io.files io.backend kernel
+quotations system alien alien.accessors accessors system
+vocabs.loader combinators alien.c-types ;
IN: io.mmap
TUPLE: mapped-file address handle length disposed ;
-M: mapped-file length dup check-disposed length>> ;
-
-M: mapped-file nth-unsafe
- dup check-disposed address>> swap alien-unsigned-1 ;
-
-M: mapped-file set-nth-unsafe
- dup check-disposed address>> swap set-alien-unsigned-1 ;
-
-INSTANCE: mapped-file sequence
-
HOOK: (mapped-file) io-backend ( path length -- address handle )
-: <mapped-file> ( path length -- mmap )
- [ >r normalize-path r> (mapped-file) ] keep
+: <mapped-file> ( path -- mmap )
+ [ normalize-path ] [ file-info size>> ] bi [ (mapped-file) ] keep
f mapped-file boa ;
HOOK: close-mapped-file io-backend ( mmap -- )
M: mapped-file dispose* ( mmap -- ) close-mapped-file ;
-: with-mapped-file ( path length quot -- )
- >r <mapped-file> r> with-disposal ; inline
+: with-mapped-file ( path quot -- )
+ [ <mapped-file> ] dip with-disposal ; inline
{
{ [ os unix? ] [ "io.unix.mmap" require ] }
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.short ;
+IN: io.mmap.short
+
+<< "short" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.uchar ;
+IN: io.mmap.uchar
+
+<< "uchar" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.uint ;
+IN: io.mmap.uint
+
+<< "uint" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.ulong ;
+IN: io.mmap.ulong
+
+<< "ulong" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.ulonglong ;
+IN: io.mmap.ulonglong
+
+<< "ulonglong" define-mapped-array >>
\ No newline at end of file
--- /dev/null
+USING: io.mmap.functor specialized-arrays.direct.ushort ;
+IN: io.mmap.ushort
+
+<< "ushort" define-mapped-array >>
\ No newline at end of file
SYMBOL: +rename-file+
: with-monitor ( path recursive? quot -- )
- >r <monitor> r> with-disposal ; inline
+ [ <monitor> ] dip with-disposal ; inline
{
{ [ os macosx? ] [ "io.unix.macosx.monitors" require ] }
USING: accessors sequences assocs arrays continuations
destructors combinators kernel threads concurrency.messaging
concurrency.mailboxes concurrency.promises io.files io.monitors
-debugger ;
+debugger fry ;
IN: io.monitors.recursive
! Simulate recursive monitors on platforms that don't have them
qualify-path dup link-info directory? [
[ add-child-monitors ]
[
- [
- [ f my-mailbox (monitor) ] keep
+ '[
+ _ [ f my-mailbox (monitor) ] keep
monitor tget children>> set-at
- ] curry ignore-errors
+ ] ignore-errors
] bi
] [ drop ] if ;
monitor tget children>> [ nip dispose ] assoc-each ;
: pump-step ( msg -- )
- first3 path>> swap >r prepend-path r> monitor tget 3array
+ first3 path>> swap [ prepend-path ] dip monitor tget 3array
monitor tget queue>>
mailbox-put ;
: pump-loop ( -- )
receive dup synchronous? [
- >r stop-pump t r> reply-synchronous
+ [ stop-pump t ] dip reply-synchronous
] [
- [ [ update-hierarchy ] curry ignore-errors ] [ pump-step ] bi
+ [ '[ _ update-hierarchy ] ignore-errors ] [ pump-step ] bi
pump-loop
] if ;
pump-loop ;
: start-pump-thread ( monitor -- )
- dup [ pump-thread ] curry
+ dup '[ _ pump-thread ]
"Recursive monitor pump" spawn
>>thread drop ;
ready>> ?promise ?linked drop ;
: <recursive-monitor> ( path mailbox -- monitor )
- >r (normalize-path) r>
+ [ (normalize-path) ] dip
recursive-monitor new-monitor
H{ } clone >>children
<promise> >>ready
--- /dev/null
+Doug Coleman
--- /dev/null
+USING: io.paths kernel tools.test io.files.unique sequences
+io.files namespaces sorting ;
+IN: io.paths.tests
+
+[ t ] [
+ [
+ 10 [ "io.paths.test" "gogogo" make-unique-file* ] replicate
+ current-directory get t [ ] find-all-files
+ ] with-unique-directory
+ [ natural-sort ] bi@ =
+] unit-test
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays deques dlists io.files
+kernel sequences system vocabs.loader fry continuations ;
+IN: io.paths
+
+TUPLE: directory-iterator path bfs queue ;
+
+<PRIVATE
+
+: qualified-directory ( path -- seq )
+ dup directory-files [ append-path ] with map ;
+
+: push-directory ( path iter -- )
+ [ qualified-directory ] dip [
+ dup queue>> swap bfs>>
+ [ push-front ] [ push-back ] if
+ ] curry each ;
+
+: <directory-iterator> ( path bfs? -- iterator )
+ <dlist> directory-iterator boa
+ dup path>> over push-directory ;
+
+: next-file ( iter -- file/f )
+ dup queue>> deque-empty? [ drop f ] [
+ dup queue>> pop-back dup link-info directory?
+ [ over push-directory next-file ] [ nip ] if
+ ] if ;
+
+: iterate-directory ( iter quot: ( obj -- ? ) -- obj )
+ over next-file [
+ over call
+ [ 2nip ] [ iterate-directory ] if*
+ ] [
+ 2drop f
+ ] if* ; inline recursive
+
+PRIVATE>
+
+: find-file ( path bfs? quot: ( obj -- ? ) -- path/f )
+ [ <directory-iterator> ] dip
+ [ keep and ] curry iterate-directory ; inline
+
+: each-file ( path bfs? quot: ( obj -- ? ) -- )
+ [ <directory-iterator> ] dip
+ [ f ] compose iterate-directory drop ; inline
+
+: find-all-files ( path bfs? quot: ( obj -- ? ) -- paths )
+ [ <directory-iterator> ] dip
+ pusher [ [ f ] compose iterate-directory drop ] dip ; inline
+
+: recursive-directory ( path bfs? -- paths )
+ [ ] accumulator [ each-file ] dip ;
+
+: find-in-directories ( directories bfs? quot -- path' )
+ '[ _ _ find-file ] attempt-all ; inline
+
+os windows? [ "io.paths.windows" require ] when
--- /dev/null
+Doug Coleman
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays continuations fry io.files io.paths
+kernel windows.shell32 sequences ;
+IN: io.paths.windows
+
+: program-files-directories ( -- array )
+ program-files program-files-x86 2array ; inline
+
+: find-in-program-files ( base-directory bfs? quot -- path )
+ [
+ [ program-files-directories ] dip '[ _ append-path ] map
+ ] 2dip find-in-directories ; inline
: <pipe> ( encoding -- stream )
[
- >r (pipe) |dispose
- [ in>> <input-port> ] [ out>> <output-port> ] bi
- r> <encoder-duplex>
+ [
+ (pipe) |dispose
+ [ in>> <input-port> ] [ out>> <output-port> ] bi
+ ] dip <encoder-duplex>
] with-destructors ;
<PRIVATE
M: callable run-pipeline-element
[
- >r [ ?reader ] [ ?writer ] bi*
- r> with-streams*
+ [ [ ?reader ] [ ?writer ] bi* ] dip with-streams*
] with-destructors ;
: <pipes> ( n -- pipes )
: run-pipeline ( seq -- results )
[ length dup zero? [ drop { } ] [ 1- <pipes> ] if ] keep
[
- >r [ first in>> ] [ second out>> ] bi
- r> run-pipeline-element
+ [ [ first in>> ] [ second out>> ] bi ] dip
+ run-pipeline-element
] 2parallel-map ;
{
[ nip call ] [ drop return-connection ] 3bi ; inline
: with-pooled-connection ( pool quot -- )
- >r [ acquire-connection ] keep r>
+ [ [ acquire-connection ] keep ] dip
[ (with-pooled-connection) ] [ ] [ 2drop dispose ] cleanup ; inline
M: return-connection dispose
! See http://factorcode.org/license.txt for BSD license.
USING: math kernel io sequences io.buffers io.timeouts generic
byte-vectors system io.encodings math.order io.backend
-continuations debugger classes byte-arrays namespaces splitting
+continuations classes byte-arrays namespaces splitting
grouping dlists assocs io.encodings.binary summary accessors
destructors combinators ;
IN: io.ports
M: input-port stream-read-partial ( max stream -- byte-array/f )
dup check-disposed
- >r 0 max >integer r> read-step ;
+ [ 0 max >integer ] dip read-step ;
: read-loop ( count port accum -- )
pick over length - dup 0 > [
M: input-port stream-read
dup check-disposed
- >r 0 max >fixnum r>
+ [ 0 max >fixnum ] dip
2dup read-step dup [
pick over length > [
pick <byte-vector>
: read-until-loop ( seps port buf -- separator/f )
2over read-until-step over [
- >r over push-all r> dup [
- >r 3drop r>
+ [ over push-all ] dip dup [
+ [ 3drop ] dip
] [
drop read-until-loop
] if
] [
- >r 2drop 2drop r>
+ [ 2drop 2drop ] dip
] if ;
M: input-port stream-read-until ( seps port -- str/f sep/f )
- 2dup read-until-step dup [ >r 2nip r> ] [
+ 2dup read-until-step dup [ [ 2drop ] 2dip ] [
over [
drop
BV{ } like [ read-until-loop ] keep B{ } like swap
- ] [ >r 2nip r> ] if
+ ] [ [ 2drop ] 2dip ] if
] if ;
TUPLE: output-port < buffered-port ;
[ [ stream-write ] curry ] bi
each
] [
- [ >r length r> wait-to-write ]
+ [ [ length ] dip wait-to-write ]
[ buffer>> >buffer ] 2bi
] if ;
bi
] with-destructors ;
+GENERIC: underlying-port ( stream -- port )
+
+M: port underlying-port ;
+
+M: encoder underlying-port stream>> underlying-port ;
+
+M: decoder underlying-port stream>> underlying-port ;
+
+GENERIC: underlying-handle ( stream -- handle )
+
+M: object underlying-handle underlying-port handle>> ;
+
! Fast-path optimization
USING: hints strings io.encodings.utf8 io.encodings.ascii
io.encodings.private ;
"Stopping the server:"
{ $subsection stop-server }
"From within the dynamic scope of a client handler, several words can be used to interact with the threaded server:"
-{ $subsection remote-address }
{ $subsection stop-this-server }
{ $subsection secure-port }
{ $subsection insecure-port }
-"Additionally, the " { $link local-address } " variable is set, as in " { $link with-client } "." ;
+"Additionally, the " { $link local-address } " and "
+{ $subsection remote-address } " variables are set, as in " { $link with-client } "." ;
ABOUT: "io.servers.connection"
! Copyright (C) 2003, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: continuations destructors kernel math math.parser
-namespaces parser sequences strings prettyprint debugger
+namespaces parser sequences strings prettyprint
quotations combinators logging calendar assocs present
fry accessors arrays io io.sockets io.encodings.ascii
io.sockets.secure io.files io.streams.duplex io.timeouts
: <threaded-server> ( -- threaded-server )
threaded-server new-threaded-server ;
-SYMBOL: remote-address
-
GENERIC: handle-client* ( threaded-server -- )
<PRIVATE
\ handle-client ERROR add-error-logging
: thread-name ( server-name addrspec -- string )
- unparse-short " connection from " swap 3append ;
+ unparse-short " connection from " glue ;
: accept-connection ( threaded-server -- )
[ accept ] [ addr>> ] bi
] when*
] unless ;
+: (start-server) ( threaded-server -- )
+ init-server
+ dup threaded-server [
+ dup name>> [
+ [ listen-on [ start-accept-loop ] parallel-each ]
+ [ ready>> raise-flag ]
+ bi
+ ] with-logging
+ ] with-variable ;
+
PRIVATE>
: start-server ( threaded-server -- )
- init-server
- dup secure-config>> [
- dup threaded-server [
- dup name>> [
- [ listen-on [ start-accept-loop ] parallel-each ]
- [ ready>> raise-flag ]
- bi
- ] with-logging
- ] with-variable
- ] with-secure-context ;
+ #! Only create a secure-context if we want to listen on
+ #! a secure port, otherwise start-server won't work at
+ #! all if SSL is not available.
+ dup secure>> [
+ dup secure-config>> [
+ (start-server)
+ ] with-secure-context
+ ] [
+ (start-server)
+ ] if ;
: wait-for-server ( threaded-server -- )
ready>> wait-for-flag ;
--- /dev/null
+! Copyright (C) 2007, 2008, Slava Pestov, Elie CHAFTARI.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors byte-arrays kernel sequences
+namespaces math math.order combinators init alien alien.c-types
+alien.strings libc continuations destructors summary
+splitting assocs random math.parser locals unicode.case openssl
+openssl.libcrypto openssl.libssl io.backend io.ports io.files
+io.encodings.8-bit io.timeouts io.sockets.secure ;
+IN: io.sockets.secure.openssl
+
+GENERIC: ssl-method ( symbol -- method )
+
+M: SSLv2 ssl-method drop SSLv2_client_method ;
+M: SSLv23 ssl-method drop SSLv23_method ;
+M: SSLv3 ssl-method drop SSLv3_method ;
+M: TLSv1 ssl-method drop TLSv1_method ;
+
+TUPLE: openssl-context < secure-context aliens sessions ;
+
+: set-session-cache ( ctx -- )
+ handle>>
+ [ SSL_SESS_CACHE_BOTH SSL_CTX_set_session_cache_mode ssl-error ]
+ [ 32 random-bits >hex dup length SSL_CTX_set_session_id_context ssl-error ]
+ bi ;
+
+: load-certificate-chain ( ctx -- )
+ dup config>> key-file>> [
+ [ handle>> ] [ config>> key-file>> (normalize-path) ] bi
+ SSL_CTX_use_certificate_chain_file
+ ssl-error
+ ] [ drop ] if ;
+
+: password-callback ( -- alien )
+ "int" { "void*" "int" "bool" "void*" } "cdecl"
+ [| buf size rwflag password! |
+ password [ B{ 0 } password! ] unless
+
+ [let | len [ password strlen ] |
+ buf password len 1+ size min memcpy
+ len
+ ]
+ ] alien-callback ;
+
+: default-pasword ( ctx -- alien )
+ [ config>> password>> latin1 malloc-string ] [ aliens>> ] bi
+ [ push ] [ drop ] 2bi ;
+
+: set-default-password ( ctx -- )
+ [ handle>> password-callback SSL_CTX_set_default_passwd_cb ]
+ [
+ [ handle>> ] [ default-pasword ] bi
+ SSL_CTX_set_default_passwd_cb_userdata
+ ] bi ;
+
+: use-private-key-file ( ctx -- )
+ dup config>> key-file>> [
+ [ handle>> ] [ config>> key-file>> (normalize-path) ] bi
+ SSL_FILETYPE_PEM SSL_CTX_use_PrivateKey_file
+ ssl-error
+ ] [ drop ] if ;
+
+: load-verify-locations ( ctx -- )
+ dup config>> [ ca-file>> ] [ ca-path>> ] bi or [
+ [ handle>> ]
+ [
+ config>>
+ [ ca-file>> dup [ (normalize-path) ] when ]
+ [ ca-path>> dup [ (normalize-path) ] when ] bi
+ ] bi
+ SSL_CTX_load_verify_locations
+ ] [ handle>> SSL_CTX_set_default_verify_paths ] if ssl-error ;
+
+: set-verify-depth ( ctx -- )
+ dup config>> verify-depth>> [
+ [ handle>> ] [ config>> verify-depth>> ] bi
+ SSL_CTX_set_verify_depth
+ ] [ drop ] if ;
+
+TUPLE: bio handle disposed ;
+
+: <bio> ( handle -- bio ) f bio boa ;
+
+M: bio dispose* handle>> BIO_free ssl-error ;
+
+: <file-bio> ( path -- bio )
+ normalize-path "r" BIO_new_file dup ssl-error <bio> ;
+
+: load-dh-params ( ctx -- )
+ dup config>> dh-file>> [
+ [ handle>> ] [ config>> dh-file>> ] bi <file-bio> &dispose
+ handle>> f f f PEM_read_bio_DHparams dup ssl-error
+ SSL_CTX_set_tmp_dh ssl-error
+ ] [ drop ] if ;
+
+TUPLE: rsa handle disposed ;
+
+: <rsa> ( handle -- rsa ) f rsa boa ;
+
+M: rsa dispose* handle>> RSA_free ;
+
+: generate-eph-rsa-key ( ctx -- )
+ [ handle>> ]
+ [
+ config>> ephemeral-key-bits>> RSA_F4 f f RSA_generate_key
+ dup ssl-error <rsa> &dispose handle>>
+ ] bi
+ SSL_CTX_set_tmp_rsa ssl-error ;
+
+: <openssl-context> ( config ctx -- context )
+ openssl-context new
+ swap >>handle
+ swap >>config
+ V{ } clone >>aliens
+ H{ } clone >>sessions ;
+
+M: openssl <secure-context> ( config -- context )
+ maybe-init-ssl
+ [
+ dup method>> ssl-method SSL_CTX_new
+ dup ssl-error <openssl-context> |dispose
+ {
+ [ set-session-cache ]
+ [ load-certificate-chain ]
+ [ set-default-password ]
+ [ use-private-key-file ]
+ [ load-verify-locations ]
+ [ set-verify-depth ]
+ [ load-dh-params ]
+ [ generate-eph-rsa-key ]
+ [ ]
+ } cleave
+ ] with-destructors ;
+
+M: openssl-context dispose*
+ [ aliens>> [ free ] each ]
+ [ sessions>> values [ SSL_SESSION_free ] each ]
+ [ handle>> SSL_CTX_free ]
+ tri ;
+
+TUPLE: ssl-handle file handle connected disposed ;
+
+SYMBOL: default-secure-context
+
+: context-expired? ( context -- ? )
+ dup [ handle>> expired? ] [ drop t ] if ;
+
+: current-secure-context ( -- ctx )
+ secure-context get [
+ default-secure-context get dup context-expired? [
+ drop
+ <secure-config> <secure-context> default-secure-context set-global
+ current-secure-context
+ ] when
+ ] unless* ;
+
+: <ssl-handle> ( fd -- ssl )
+ current-secure-context handle>> SSL_new dup ssl-error
+ f f ssl-handle boa ;
+
+M: ssl-handle dispose*
+ [ handle>> SSL_free ] [ file>> dispose ] bi ;
+
+: check-verify-result ( ssl-handle -- )
+ SSL_get_verify_result dup X509_V_OK =
+ [ drop ] [ verify-message certificate-verify-error ] if ;
+
+: common-name ( certificate -- host )
+ X509_get_subject_name
+ NID_commonName 256 <byte-array>
+ [ 256 X509_NAME_get_text_by_NID ] keep
+ swap -1 = [ drop f ] [ latin1 alien>string ] if ;
+
+: common-names-match? ( expected actual -- ? )
+ [ >lower ] bi@ "*." ?head [ tail? ] [ = ] if ;
+
+: check-common-name ( host ssl-handle -- )
+ SSL_get_peer_certificate common-name
+ 2dup common-names-match?
+ [ 2drop ] [ common-name-verify-error ] if ;
+
+M: openssl check-certificate ( host ssl -- )
+ current-secure-context config>> verify>> [
+ handle>>
+ [ nip check-verify-result ]
+ [ check-common-name ]
+ 2bi
+ ] [ 2drop ] if ;
+
+: get-session ( addrspec -- session/f )
+ current-secure-context sessions>> at
+ dup expired? [ drop f ] when ;
+
+: save-session ( session addrspec -- )
+ current-secure-context sessions>> set-at ;
+
+openssl secure-socket-backend set-global
+USING: io help.markup help.syntax calendar quotations io.sockets ;
IN: io.sockets.secure
-USING: help.markup help.syntax calendar quotations io.sockets ;
HELP: secure-socket-timeout
{ $var-description "Timeout for operations not associated with a constructed port instance, such as SSL handshake and shutdown. Represented as a " { $link duration } "." } ;
{ $subsection <secure> }
"Instances of this class can wrap an " { $link inet } ", " { $link inet4 } " or an " { $link inet6 } ", although note that certificate validation is only performed for instances of " { $link inet } " since otherwise the host name is not available." ;
+HELP: send-secure-handshake
+{ $contract "Upgrades the socket connection of the current " { $link with-client } " scope to a secure connection and initiates a SSL/TLS handshake." }
+{ $errors "Throws " { $link upgrade-on-non-socket } " or " { $link upgrade-buffers-full } " if used improperly." }
+{ $examples "This word is used by the " { $vocab-link "smtp" } " library to implement SMTP-TLS." } ;
+
+HELP: accept-secure-handshake
+{ $contract "Upgrades the socket connection stored in the " { $link input-stream } " and " { $link output-stream } " variables to a secure connection and waits for an SSL/TLS handshake." }
+{ $errors "Throws " { $link upgrade-on-non-socket } " or " { $link upgrade-buffers-full } " if used improperly." } ;
+
+ARTICLE: "ssl-upgrade" "Upgrading existing connections"
+"Some protocols, such as HTTPS, require that the connection be established as an SSL/TLS connection. Others, such as secure SMTP and POP3 require that the client and server initiate an SSL/TLS handshake upon the client sending a plain-text request. The latter use-case is accomodated by a pair of words."
+$nl
+"Upgrading a connection to a secure socket by initiating an SSL/TLS handshake with the server:"
+{ $subsection send-secure-handshake }
+"Upgrading a connection to a secure socket by waiting for an SSL/TLS handshake from the client:"
+{ $subsection accept-secure-handshake } ;
+
HELP: premature-close
{ $error-description "Thrown if an SSL connection is closed without the proper " { $snippet "close_notify" } " sequence. This error is never reported for " { $link SSLv2 } " connections because there is no distinction between expected and unexpected connection closure in that case." } ;
{ $error-description "Thrown if certificate verification failed. The " { $snippet "result" } " slot contains an object identifying the low-level error that occurred." } ;
HELP: common-name-verify-error
-{ $error-description "Thrown during certificate verification if the host name on the certificate does not match the host name the socket was connected to. This indicates a potential man-in-the-middle attack. The " { $snippet "expected" } " and " { $snippet "got" } " slots contain the mismatched host names." } ;
+{ $error-description "Thrown during certificate verification if the host name on the certificate does not match the host name the socket was connected to. This indicates a potential man-in-the-middle attack. The " { $slot "expected" } " and " { $slot "got" } " slots contain the mismatched host names." } ;
+
+HELP: upgrade-on-non-socket
+{ $error-description "Thrown if " { $link send-secure-handshake } " or " { $link accept-secure-handshake } " is called with the " { $link input-stream } " and " { $link output-stream } " variables not set to a socket. This error can also indicate that the connection has already been upgraded to a secure connection." } ;
+
+HELP: upgrade-buffers-full
+{ $error-description "Thrown if " { $link send-secure-handshake } " or " { $link accept-secure-handshake } " is called when there is still data which hasn't been read or written." }
+{ $notes "Clients should ensure to " { $link flush } " their last command to the server before calling " { $link send-secure-handshake } "." } ;
ARTICLE: "ssl-errors" "Secure socket errors"
"Secure sockets can throw one of several errors in addition to the usual I/O errors:"
{ $subsection premature-close }
{ $subsection certificate-verify-error }
-{ $subsection common-name-verify-error } ;
+{ $subsection common-name-verify-error }
+"The " { $link send-secure-handshake } " word can throw one of two errors:"
+{ $subsection upgrade-on-non-socket }
+{ $subsection upgrade-buffers-full } ;
ARTICLE: "io.sockets.secure" "Secure sockets (SSL, TLS)"
"The " { $vocab-link "io.sockets.secure" } " vocabulary implements secure, encrypted sockets using the OpenSSL library."
+$nl
+"At present, this vocabulary only works on Unix, and not on Windows."
+$nl
+"This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (" { $url "http://www.openssl.org/" } "), cryptographic software written by Eric Young (eay@cryptsoft.com) and software written by Tim Hudson (tjh@cryptsoft.com)."
{ $subsection "ssl-config" }
{ $subsection "ssl-contexts" }
{ $subsection "ssl-addresses" }
-{ $subsection "ssl-errors" }
-"This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (" { $url "http://www.openssl.org/" } "), cryptographic software written by Eric Young (eay@cryptsoft.com) and software written by Tim Hudson (tjh@cryptsoft.com)." ;
+{ $subsection "ssl-upgrade" }
+{ $subsection "ssl-errors" } ;
ABOUT: "io.sockets.secure"
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel symbols namespaces continuations
-destructors io.sockets sequences summary calendar delegate
-system vocabs.loader combinators present ;
+destructors io debugger io.sockets sequences summary calendar
+delegate system vocabs.loader combinators present ;
IN: io.sockets.secure
SYMBOL: secure-socket-timeout
HOOK: check-certificate secure-socket-backend ( host handle -- )
-<PRIVATE
-
PREDICATE: secure-inet < secure addrspec>> inet? ;
+<PRIVATE
+
M: secure-inet (client)
[
[ resolve-host (client) [ |dispose ] dip ] keep
M: common-name-verify-error summary
drop "Common name verification failed" ;
+ERROR: upgrade-on-non-socket ;
+
+M: upgrade-on-non-socket summary
+ drop
+ "send-secure-handshake can only be used if input-stream and" print
+ "output-stream are a socket" ;
+
+ERROR: upgrade-buffers-full ;
+
+M: upgrade-buffers-full summary
+ drop
+ "send-secure-handshake can only be used if buffers are empty" ;
+
+HOOK: send-secure-handshake secure-socket-backend ( -- )
+
+HOOK: accept-secure-handshake secure-socket-backend ( -- )
+
{
{ [ os unix? ] [ "io.unix.sockets.secure" require ] }
{ [ os windows? ] [ "openssl" require ] }
HELP: with-client
{ $values { "remote" "an address specifier" } { "encoding" "an encoding descriptor" } { "quot" quotation } }
-{ $description "Opens a network connection and calls the quotation in a new dynamic scope with " { $link input-stream } " and " { $link output-stream } " rebound to the network streams. The local address the socket is bound to is stored in the " { $link local-address } " variable." }
+{ $description "Opens a network connection and calls the quotation in a new dynamic scope with " { $link input-stream } " and " { $link output-stream } " rebound to the network streams. The local address the socket is connected to is stored in the " { $link local-address } " variable, and the remote address is stored in the " { $link remote-address } " variable." }
{ $errors "Throws an error if the connection cannot be established." } ;
HELP: <server>
USING: generic kernel io.backend namespaces continuations
sequences arrays io.encodings io.ports io.streams.duplex
io.encodings.ascii alien.strings io.binary accessors destructors
-classes debugger byte-arrays system combinators parser
+classes byte-arrays system combinators parser
alien.c-types math.parser splitting grouping math assocs summary
-system vocabs.loader combinators present ;
+system vocabs.loader combinators present fry ;
IN: io.sockets
<< {
rot inet-pton *uint over set-sockaddr-in-addr ;
M: inet4 parse-sockaddr
- >r dup sockaddr-in-addr <uint> r> inet-ntop
+ [ dup sockaddr-in-addr <uint> ] dip inet-ntop
swap sockaddr-in-port ntohs <inet4> ;
TUPLE: inet6 < abstract-inet ;
: pad-inet6 ( string1 string2 -- seq )
2dup [ length ] bi@ + 8 swap -
dup 0 < [ "More than 8 components" throw ] when
- <byte-array> swap 3append ;
+ <byte-array> glue ;
: inet6-bytes ( seq -- bytes )
[ 2 >be ] { } map-as concat >byte-array ;
rot inet-pton over set-sockaddr-in6-addr ;
M: inet6 parse-sockaddr
- >r dup sockaddr-in6-addr r> inet-ntop
+ [ dup sockaddr-in6-addr ] dip inet-ntop
swap sockaddr-in6-port ntohs <inet6> ;
: addrspec-of-family ( af -- addrspec )
[
[ ((client)) ] keep
[
- >r <ports> [ |dispose ] bi@ dup r>
+ [ <ports> [ |dispose ] bi@ dup ] dip
establish-connection
]
[ get-local-address ]
] with-destructors ;
: <client> ( remote encoding -- stream local )
- >r (client) -rot r> <encoder-duplex> swap ;
+ [ (client) -rot ] dip <encoder-duplex> swap ;
SYMBOL: local-address
+SYMBOL: remote-address
+
: with-client ( remote encoding quot -- )
- >r <client> [ local-address set ] curry
- r> compose with-stream ; inline
+ [
+ [
+ over remote-address set
+ <client> local-address set
+ ] dip with-stream
+ ] with-scope ; inline
TUPLE: server-port < port addr encoding ;
GENERIC: (server) ( addrspec -- handle )
: <server> ( addrspec encoding -- server )
- >r
- [ (server) ] keep
- [ drop server-port <port> ] [ get-local-address ] 2bi
- >>addr r> >>encoding ;
+ [
+ [ (server) ] keep
+ [ drop server-port <port> ] [ get-local-address ] 2bi
+ >>addr
+ ] dip >>encoding ;
GENERIC: (accept) ( server addrspec -- handle sockaddr )
IPPROTO_TCP over set-addrinfo-protocol ;
: fill-in-ports ( addrspecs port -- addrspecs )
- [ >>port ] curry map ;
+ '[ _ >>port ] map ;
M: inet resolve-host
[ port>> ] [ host>> ] bi [
--- /dev/null
+USING: help.syntax help.markup io byte-arrays quotations ;
+IN: io.streams.byte-array
+
+ABOUT: "io.streams.byte-array"
+
+ARTICLE: "io.streams.byte-array" "Byte-array streams"
+"Byte array streams:"
+{ $subsection <byte-reader> }
+{ $subsection <byte-writer> }
+"Utility combinators:"
+{ $subsection with-byte-reader }
+{ $subsection with-byte-writer } ;
+
+HELP: <byte-reader>
+{ $values { "byte-array" byte-array }
+ { "encoding" "an encoding descriptor" }
+ { "stream" "a new byte reader" } }
+{ $description "Creates an input stream reading from a byte array using an encoding." } ;
+
+HELP: <byte-writer>
+{ $values { "encoding" "an encoding descriptor" }
+ { "stream" "a new byte writer" } }
+{ $description "Creates an output stream writing data to a byte array using an encoding." } ;
+
+HELP: with-byte-reader
+{ $values { "encoding" "an encoding descriptor" }
+ { "quot" quotation } { "byte-array" byte-array } }
+{ $description "Calls the quotation in a new dynamic scope with " { $link input-stream } " rebound to an input stream for reading from a byte array using an encoding." } ;
+
+HELP: with-byte-writer
+{ $values { "encoding" "an encoding descriptor" }
+ { "quot" quotation }
+ { "byte-array" byte-array } }
+{ $description "Calls the quotation in a new dynamic scope with " { $link output-stream } " rebound to an output stream writing data to a byte array using an encoding." } ;
--- /dev/null
+USING: tools.test io.streams.byte-array io.encodings.binary
+io.encodings.utf8 io kernel arrays strings ;
+
+[ B{ 1 2 3 } ] [ binary [ { 1 2 3 } write ] with-byte-writer ] unit-test
+[ B{ 1 2 3 } ] [ { 1 2 3 } binary [ 3 read ] with-byte-reader ] unit-test
+
+[ B{ BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 BIN: 11101111 BIN: 10000000 BIN: 10111111 BIN: 11011111 BIN: 10000000 CHAR: x } ]
+[ { BIN: 101111111000000111111 BIN: 1111000000111111 BIN: 11111000000 CHAR: x } utf8 [ write ] with-byte-writer ] unit-test
+[ { BIN: 101111111000000111111 } t ] [ { BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 } utf8 <byte-reader> contents dup >array swap string? ] unit-test
--- /dev/null
+USING: byte-arrays byte-vectors kernel io.encodings io.streams.string
+sequences io namespaces io.encodings.private accessors ;
+IN: io.streams.byte-array
+
+: <byte-writer> ( encoding -- stream )
+ 512 <byte-vector> swap <encoder> ;
+
+: with-byte-writer ( encoding quot -- byte-array )
+ [ <byte-writer> ] dip [ output-stream get ] compose with-output-stream*
+ dup encoder? [ stream>> ] when >byte-array ; inline
+
+: <byte-reader> ( byte-array encoding -- stream )
+ [ >byte-vector dup reverse-here ] dip <decoder> ;
+
+: with-byte-reader ( byte-array encoding quot -- )
+ [ <byte-reader> ] dip with-input-stream* ; inline
! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel continuations destructors io io.encodings
-io.encodings.private io.timeouts debugger summary listener
+io.encodings.private io.timeouts io.ports summary
accessors delegate delegate.protocols ;
IN: io.streams.duplex
] with-destructors ;
: <encoder-duplex> ( stream-in stream-out encoding -- duplex )
- tuck re-encode >r re-decode r> <duplex-stream> ;
+ tuck [ re-decode ] [ re-encode ] 2bi* <duplex-stream> ;
: with-stream* ( stream quot -- )
- >r [ in>> ] [ out>> ] bi r> with-streams* ; inline
+ [ [ in>> ] [ out>> ] bi ] dip with-streams* ; inline
: with-stream ( stream quot -- )
- >r [ in>> ] [ out>> ] bi r> with-streams ; inline
+ [ [ in>> ] [ out>> ] bi ] dip with-streams ; inline
+
+ERROR: invalid-duplex-stream ;
+
+M: duplex-stream underlying-handle
+ [ in>> underlying-handle ]
+ [ out>> underlying-handle ] bi
+ [ = [ invalid-duplex-stream ] when ] keep ;
+
! Copyright (C) 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math io io.encodings destructors accessors
-sequences namespaces ;
+sequences namespaces byte-vectors ;
IN: io.streams.limited
TUPLE: limited-stream stream count limit ;
! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: hashtables io colors ;
+USING: hashtables io colors summary make accessors splitting
+kernel ;
IN: io.styles
SYMBOL: plain
C: <input> input
+M: input summary
+ [
+ "Input: " %
+ string>> "\n" split1 swap %
+ "..." "" ? %
+ ] "" make ;
+
: write-object ( str obj -- ) presented associate format ;
! Copyright (C) 2008 Slava Pestov, Doug Coleman\r
! See http://factorcode.org/license.txt for BSD license.\r
USING: kernel calendar alarms io io.encodings accessors\r
-namespaces ;\r
+namespaces fry ;\r
IN: io.timeouts\r
\r
GENERIC: timeout ( obj -- dt/f )\r
GENERIC: cancel-operation ( obj -- )\r
\r
: queue-timeout ( obj timeout -- alarm )\r
- >r [ cancel-operation ] curry r> later ;\r
+ [ '[ _ cancel-operation ] ] dip later ;\r
\r
: with-timeout* ( obj timeout quot -- )\r
- 3dup drop queue-timeout >r nip call r> cancel-alarm ;\r
+ 3dup drop queue-timeout [ nip call ] dip cancel-alarm ;\r
inline\r
\r
: with-timeout ( obj quot -- )\r
- over timeout [ >r dup timeout r> with-timeout* ] [ call ] if ;\r
+ over timeout [ [ dup timeout ] dip with-timeout* ] [ call ] if ;\r
inline\r
\r
: timeouts ( dt -- )\r
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien alien.c-types generic assocs kernel kernel.private
-math io.ports sequences strings sbufs threads unix
-vectors io.buffers io.backend io.encodings math.parser
+USING: alien alien.c-types alien.syntax generic assocs kernel
+kernel.private math io.ports sequences strings sbufs threads
+unix vectors io.buffers io.backend io.encodings math.parser
continuations system libc qualified namespaces make io.timeouts
io.encodings.utf8 destructors accessors summary combinators
-locals unix.time ;
+locals unix.time fry io.unix.multiplexers ;
QUALIFIED: io
IN: io.unix.backend
M: fd handle-fd dup check-disposed fd>> ;
-! I/O multiplexers
-TUPLE: mx fd reads writes ;
-
-: new-mx ( class -- obj )
- new
- H{ } clone >>reads
- H{ } clone >>writes ; inline
-
-GENERIC: add-input-callback ( thread fd mx -- )
-
-M: mx add-input-callback reads>> push-at ;
-
-GENERIC: add-output-callback ( thread fd mx -- )
-
-M: mx add-output-callback writes>> push-at ;
-
-GENERIC: remove-input-callbacks ( fd mx -- callbacks )
-
-M: mx remove-input-callbacks reads>> delete-at* drop ;
-
-GENERIC: remove-output-callbacks ( fd mx -- callbacks )
-
-M: mx remove-output-callbacks writes>> delete-at* drop ;
-
-GENERIC: wait-for-events ( ms mx -- )
-
-: input-available ( fd mx -- )
- remove-input-callbacks [ resume ] each ;
-
-: output-available ( fd mx -- )
- remove-output-callbacks [ resume ] each ;
-
M: fd cancel-operation ( fd -- )
dup disposed>> [ drop ] [
fd>>
: wait-for-fd ( handle event -- )
dup +retry+ eq? [ 2drop ] [
- [
- >r
- swap handle-fd
- mx get-global
- r> {
+ '[
+ swap handle-fd mx get-global _ {
{ +input+ [ add-input-callback ] }
{ +output+ [ add-output-callback ] }
} case
- ] curry "I/O" suspend nip [ io-timeout ] when
+ ] "I/O" suspend nip [ io-timeout ] when
] if ;
: wait-for-port ( port event -- )
- [ >r handle>> r> wait-for-fd ] curry with-timeout ;
+ '[ handle>> _ wait-for-fd ] with-timeout ;
! Some general stuff
: file-mode OCT: 0666 ;
M: stdin refill
[ buffer>> ] [ dup wait-for-stdin ] bi* refill-stdin f ;
-: control-write-fd ( -- fd ) "control_write" f dlsym *uint ;
+: control-write-fd ( -- fd ) &: control_write *uint ;
-: size-read-fd ( -- fd ) "size_read" f dlsym *uint ;
+: size-read-fd ( -- fd ) &: size_read *uint ;
-: data-read-fd ( -- fd ) "stdin_read" f dlsym *uint ;
+: data-read-fd ( -- fd ) &: stdin_read *uint ;
: <stdin> ( -- stdin )
stdin new
: <mx-port> ( mx -- port )
dup fd>> mx-port <port> swap >>mx ;
-: multiplexer-error ( n -- )
- 0 < [
+: multiplexer-error ( n -- n )
+ dup 0 < [
err_no [ EAGAIN = ] [ EINTR = ] bi or
- [ (io-error) ] unless
+ [ drop 0 ] [ (io-error) ] if
] when ;
: ?flag ( n mask symbol -- n )
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-IN: io.unix.bsd
USING: namespaces system kernel accessors assocs continuations
-unix io.backend io.unix.backend io.unix.select ;
+unix io.backend io.unix.backend io.unix.multiplexers
+io.unix.multiplexers.kqueue ;
+IN: io.unix.bsd
M: bsd init-io ( -- )
- <select-mx> mx set-global ;
-! <kqueue-mx> kqueue-mx set-global
-! kqueue-mx get-global <mx-port> <mx-task>
-! dup io-task-fd
-! [ mx get-global reads>> set-at ]
-! [ mx get-global writes>> set-at ] 2bi ;
+ <kqueue-mx> mx set-global ;
! M: bsd (monitor) ( path recursive? mailbox -- )
! swap [ "Recursive kqueue monitors not supported" throw ] when
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.c-types kernel io.ports io.unix.backend
-bit-arrays sequences assocs unix unix.linux.epoll math
-namespaces unix.time ;
+USING: accessors alien.c-types kernel io.ports io.unix.backend
+bit-arrays sequences assocs struct-arrays math namespaces locals
+fry unix unix.linux.epoll unix.time ;
IN: io.unix.epoll
TUPLE: epoll-mx < mx events ;
: <epoll-mx> ( -- mx )
epoll-mx new-mx
- max-events epoll_create dup io-error over set-mx-fd
- max-events "epoll-event" <c-array> over set-epoll-mx-events ;
+ max-events epoll_create dup io-error >>fd
+ max-events "epoll-event" <struct-array> >>events ;
-GENERIC: io-task-events ( task -- n )
-
-M: input-task io-task-events drop EPOLLIN ;
+: make-event ( fd events -- event )
+ "epoll-event" <c-object>
+ [ set-epoll-event-events ] keep
+ [ set-epoll-event-fd ] keep ;
-M: output-task io-task-events drop EPOLLOUT ;
+:: do-epoll-ctl ( fd mx what events -- )
+ mx fd>> what fd fd events make-event epoll_ctl io-error ;
-: make-event ( task -- event )
- "epoll-event" <c-object>
- over io-task-events over set-epoll-event-events
- swap io-task-fd over set-epoll-event-fd ;
+: do-epoll-add ( fd mx events -- )
+ EPOLL_CTL_ADD swap EPOLLONESHOT bitor do-epoll-ctl ;
-: do-epoll-ctl ( task mx what -- )
- >r mx-fd r> rot dup io-task-fd swap make-event
- epoll_ctl io-error ;
+: do-epoll-del ( fd mx events -- )
+ EPOLL_CTL_DEL swap do-epoll-ctl ;
-M: epoll-mx register-io-task ( task mx -- )
- [ EPOLL_CTL_ADD do-epoll-ctl ] [ call-next-method ] 2bi ;
+M: epoll-mx add-input-callback ( thread fd mx -- )
+ [ EPOLLIN do-epoll-add ] [ call-next-method ] 2bi ;
-M: epoll-mx unregister-io-task ( task mx -- )
- [ call-next-method ] [ EPOLL_CTL_DEL do-epoll-ctl ] 2bi ;
+M: epoll-mx add-output-callback ( thread fd mx -- )
+ [ EPOLLOUT do-epoll-add ] [ call-next-method ] 2bi ;
-: wait-event ( mx timeout -- n )
- >r { mx-fd epoll-mx-events } get-slots max-events
- r> epoll_wait dup multiplexer-error ;
+M: epoll-mx remove-input-callbacks ( fd mx -- seq )
+ 2dup reads>> key? [
+ [ call-next-method ] [ EPOLLIN do-epoll-del ] 2bi
+ ] [ 2drop f ] if ;
-: epoll-read-task ( mx fd -- )
- over mx-reads at* [ perform-io-task ] [ 2drop ] if ;
+M: epoll-mx remove-output-callbacks ( fd mx -- seq )
+ 2dup writes>> key? [
+ [ EPOLLOUT do-epoll-del ] [ call-next-method ] 2bi
+ ] [ 2drop f ] if ;
-: epoll-write-task ( mx fd -- )
- over mx-writes at* [ perform-io-task ] [ 2drop ] if ;
+: wait-event ( mx us -- n )
+ [ [ fd>> ] [ events>> ] bi [ underlying>> ] [ length ] bi ] [ 1000 /i ] bi*
+ epoll_wait multiplexer-error ;
-: handle-event ( mx kevent -- )
- epoll-event-fd 2dup epoll-read-task epoll-write-task ;
+: handle-event ( event mx -- )
+ [ epoll-event-fd ] dip
+ [ EPOLLIN EPOLLOUT bitor do-epoll-del ]
+ [ input-available ] [ output-available ] 2tri ;
: handle-events ( mx n -- )
- [
- over epoll-mx-events epoll-event-nth handle-event
- ] with each ;
+ [ dup events>> ] dip head-slice swap '[ _ handle-event ] each ;
-M: epoll-mx wait-for-events ( ms mx -- )
- dup rot wait-event handle-events ;
+M: epoll-mx wait-for-events ( us mx -- )
+ swap 60000000 or dupd wait-event handle-events ;
io.encodings.binary accessors sequences strings system
io.files.private destructors vocabs.loader calendar.unix
unix.stat alien.c-types arrays unix.users unix.groups
-environment fry io.encodings.utf8 alien.strings unix.statfs ;
+environment fry io.encodings.utf8 alien.strings
+combinators.short-circuit ;
IN: io.unix.files
M: unix cwd ( -- path )
[ swap file-info permissions>> chmod io-error ]
2bi ;
-HOOK: stat>file-info os ( stat -- file-info )
+TUPLE: unix-file-system-info < file-system-info
+block-size preferred-block-size
+blocks blocks-free blocks-available
+files files-free files-available
+name-max flags id ;
-HOOK: stat>type os ( stat -- file-info )
+HOOK: new-file-system-info os ( -- file-system-info )
+
+M: unix new-file-system-info ( -- ) unix-file-system-info new ;
+
+HOOK: file-system-statfs os ( path -- statfs )
+
+M: unix file-system-statfs drop f ;
+
+HOOK: file-system-statvfs os ( path -- statvfs )
+
+M: unix file-system-statvfs drop f ;
+
+HOOK: statfs>file-system-info os ( file-system-info statfs -- file-system-info' )
+
+M: unix statfs>file-system-info drop ;
+
+HOOK: statvfs>file-system-info os ( file-system-info statvfs -- file-system-info' )
+
+M: unix statvfs>file-system-info drop ;
+
+: file-system-calculations ( file-system-info -- file-system-info' )
+ {
+ [ dup [ blocks-available>> ] [ block-size>> ] bi * >>available-space drop ]
+ [ dup [ blocks-free>> ] [ block-size>> ] bi * >>free-space drop ]
+ [ dup [ blocks>> ] [ block-size>> ] bi * >>total-space drop ]
+ [ dup [ total-space>> ] [ free-space>> ] bi - >>used-space drop ]
+ [ ]
+ } cleave ;
+
+M: unix file-system-info
+ normalize-path
+ [ new-file-system-info ] dip
+ [ file-system-statfs statfs>file-system-info ]
+ [ file-system-statvfs statvfs>file-system-info ] bi
+ file-system-calculations ;
-HOOK: new-file-info os ( -- class )
+os {
+ { linux [ "io.unix.files.linux" require ] }
+ { macosx [ "io.unix.files.macosx" require ] }
+ { freebsd [ "io.unix.files.freebsd" require ] }
+ { netbsd [ "io.unix.files.netbsd" require ] }
+ { openbsd [ "io.unix.files.openbsd" require ] }
+} case
TUPLE: unix-file-info < file-info uid gid dev ino
nlink rdev blocks blocksize ;
+HOOK: new-file-info os ( -- file-info )
+
+HOOK: stat>file-info os ( stat -- file-info )
+
+HOOK: stat>type os ( stat -- file-info )
+
M: unix file-info ( path -- info )
normalize-path file-status stat>file-info ;
[ stat-st_blksize >>blocksize ]
} cleave ;
-M: unix stat>type ( stat -- type )
- stat-st_mode S_IFMT bitand {
+: n>file-type ( n -- type )
+ S_IFMT bitand {
{ S_IFREG [ +regular-file+ ] }
{ S_IFDIR [ +directory+ ] }
{ S_IFCHR [ +character-device+ ] }
[ drop +unknown+ ]
} case ;
+M: unix stat>type ( stat -- type )
+ stat-st_mode n>file-type ;
+
! Linux has no extra fields in its stat struct
os {
{ macosx [ "io.unix.files.bsd" require ] }
M: unix >directory-entry ( byte-array -- directory-entry )
[ dirent-d_name utf8 alien>string ]
- [ dirent-d_type ] bi directory-entry boa ;
+ [ dirent-d_type dirent-type>file-type ] bi directory-entry boa ;
M: unix (directory-entries) ( path -- seq )
[
: stat-mode ( path -- mode )
normalize-path file-status stat-st_mode ;
-
-: chmod-set-bit ( path mask ? -- )
- [ dup stat-mode ] 2dip
+
+: chmod-set-bit ( path mask ? -- )
+ [ dup stat-mode ] 2dip
[ bitor ] [ unmask ] if chmod io-error ;
-: file-mode? ( path mask -- ? ) [ stat-mode ] dip mask? ;
+GENERIC# file-mode? 1 ( obj mask -- ? )
+
+M: integer file-mode? mask? ;
+M: string file-mode? [ stat-mode ] dip mask? ;
+M: file-info file-mode? [ permissions>> ] dip mask? ;
PRIVATE>
: ch>file-type ( ch -- type )
{
{ CHAR: b [ +block-device+ ] }
- { CHAR: c [ +character-device+ ] }
+ { CHAR: c [ +character-device+ ] }
{ CHAR: d [ +directory+ ] }
{ CHAR: l [ +symbolic-link+ ] }
{ CHAR: s [ +socket+ ] }
: STICKY OCT: 0001000 ; inline
: USER-ALL OCT: 0000700 ; inline
: USER-READ OCT: 0000400 ; inline
-: USER-WRITE OCT: 0000200 ; inline
-: USER-EXECUTE OCT: 0000100 ; inline
+: USER-WRITE OCT: 0000200 ; inline
+: USER-EXECUTE OCT: 0000100 ; inline
: GROUP-ALL OCT: 0000070 ; inline
-: GROUP-READ OCT: 0000040 ; inline
-: GROUP-WRITE OCT: 0000020 ; inline
-: GROUP-EXECUTE OCT: 0000010 ; inline
+: GROUP-READ OCT: 0000040 ; inline
+: GROUP-WRITE OCT: 0000020 ; inline
+: GROUP-EXECUTE OCT: 0000010 ; inline
: OTHER-ALL OCT: 0000007 ; inline
: OTHER-READ OCT: 0000004 ; inline
-: OTHER-WRITE OCT: 0000002 ; inline
-: OTHER-EXECUTE OCT: 0000001 ; inline
-
-GENERIC: uid? ( obj -- ? )
-GENERIC: gid? ( obj -- ? )
-GENERIC: sticky? ( obj -- ? )
-GENERIC: user-read? ( obj -- ? )
-GENERIC: user-write? ( obj -- ? )
-GENERIC: user-execute? ( obj -- ? )
-GENERIC: group-read? ( obj -- ? )
-GENERIC: group-write? ( obj -- ? )
-GENERIC: group-execute? ( obj -- ? )
-GENERIC: other-read? ( obj -- ? )
-GENERIC: other-write? ( obj -- ? )
-GENERIC: other-execute? ( obj -- ? )
-
-M: integer uid? ( integer -- ? ) UID mask? ;
-M: integer gid? ( integer -- ? ) GID mask? ;
-M: integer sticky? ( integer -- ? ) STICKY mask? ;
-M: integer user-read? ( integer -- ? ) USER-READ mask? ;
-M: integer user-write? ( integer -- ? ) USER-WRITE mask? ;
-M: integer user-execute? ( integer -- ? ) USER-EXECUTE mask? ;
-M: integer group-read? ( integer -- ? ) GROUP-READ mask? ;
-M: integer group-write? ( integer -- ? ) GROUP-WRITE mask? ;
-M: integer group-execute? ( integer -- ? ) GROUP-EXECUTE mask? ;
-M: integer other-read? ( integer -- ? ) OTHER-READ mask? ;
-M: integer other-write? ( integer -- ? ) OTHER-WRITE mask? ;
-M: integer other-execute? ( integer -- ? ) OTHER-EXECUTE mask? ;
-
-M: file-info uid? ( file-info -- ? ) permissions>> uid? ;
-M: file-info gid? ( file-info -- ? ) permissions>> gid? ;
-M: file-info sticky? ( file-info -- ? ) permissions>> sticky? ;
-M: file-info user-read? ( file-info -- ? ) permissions>> user-read? ;
-M: file-info user-write? ( file-info -- ? ) permissions>> user-write? ;
-M: file-info user-execute? ( file-info -- ? ) permissions>> user-execute? ;
-M: file-info group-read? ( file-info -- ? ) permissions>> group-read? ;
-M: file-info group-write? ( file-info -- ? ) permissions>> group-write? ;
-M: file-info group-execute? ( file-info -- ? ) permissions>> group-execute? ;
-M: file-info other-read? ( file-info -- ? ) permissions>> other-read? ;
-M: file-info other-write? ( file-info -- ? ) permissions>> other-write? ;
-M: file-info other-execute? ( file-info -- ? ) permissions>> other-execute? ;
-
-M: string uid? ( path -- ? ) UID file-mode? ;
-M: string gid? ( path -- ? ) GID file-mode? ;
-M: string sticky? ( path -- ? ) STICKY file-mode? ;
-M: string user-read? ( path -- ? ) USER-READ file-mode? ;
-M: string user-write? ( path -- ? ) USER-WRITE file-mode? ;
-M: string user-execute? ( path -- ? ) USER-EXECUTE file-mode? ;
-M: string group-read? ( path -- ? ) GROUP-READ file-mode? ;
-M: string group-write? ( path -- ? ) GROUP-WRITE file-mode? ;
-M: string group-execute? ( path -- ? ) GROUP-EXECUTE file-mode? ;
-M: string other-read? ( path -- ? ) OTHER-READ file-mode? ;
-M: string other-write? ( path -- ? ) OTHER-WRITE file-mode? ;
-M: string other-execute? ( path -- ? ) OTHER-EXECUTE file-mode? ;
+: OTHER-WRITE OCT: 0000002 ; inline
+: OTHER-EXECUTE OCT: 0000001 ; inline
+
+: uid? ( obj -- ? ) UID file-mode? ;
+: gid? ( obj -- ? ) GID file-mode? ;
+: sticky? ( obj -- ? ) STICKY file-mode? ;
+: user-read? ( obj -- ? ) USER-READ file-mode? ;
+: user-write? ( obj -- ? ) USER-WRITE file-mode? ;
+: user-execute? ( obj -- ? ) USER-EXECUTE file-mode? ;
+: group-read? ( obj -- ? ) GROUP-READ file-mode? ;
+: group-write? ( obj -- ? ) GROUP-WRITE file-mode? ;
+: group-execute? ( obj -- ? ) GROUP-EXECUTE file-mode? ;
+: other-read? ( obj -- ? ) OTHER-READ file-mode? ;
+: other-write? ( obj -- ? ) OTHER-WRITE file-mode? ;
+: other-execute? ( obj -- ? ) OTHER-EXECUTE file-mode? ;
+
+: any-read? ( obj -- ? )
+ { [ user-read? ] [ group-read? ] [ other-read? ] } 1|| ;
+
+: any-write? ( obj -- ? )
+ { [ user-write? ] [ group-write? ] [ other-write? ] } 1|| ;
+
+: any-execute? ( obj -- ? )
+ { [ user-execute? ] [ group-execute? ] [ other-execute? ] } 1|| ;
: set-uid ( path ? -- ) UID swap chmod-set-bit ;
: set-gid ( path ? -- ) GID swap chmod-set-bit ;
: set-sticky ( path ? -- ) STICKY swap chmod-set-bit ;
: set-user-read ( path ? -- ) USER-READ swap chmod-set-bit ;
-: set-user-write ( path ? -- ) USER-WRITE swap chmod-set-bit ;
+: set-user-write ( path ? -- ) USER-WRITE swap chmod-set-bit ;
: set-user-execute ( path ? -- ) USER-EXECUTE swap chmod-set-bit ;
: set-group-read ( path ? -- ) GROUP-READ swap chmod-set-bit ;
-: set-group-write ( path ? -- ) GROUP-WRITE swap chmod-set-bit ;
+: set-group-write ( path ? -- ) GROUP-WRITE swap chmod-set-bit ;
: set-group-execute ( path ? -- ) GROUP-EXECUTE swap chmod-set-bit ;
: set-other-read ( path ? -- ) OTHER-READ swap chmod-set-bit ;
-: set-other-write ( path ? -- ) OTHER-WRITE swap chmod-set-bit ;
+: set-other-write ( path ? -- ) OTHER-WRITE swap chmod-set-bit ;
: set-other-execute ( path ? -- ) OTHER-EXECUTE swap chmod-set-bit ;
: set-file-permissions ( path n -- )
<PRIVATE
: make-timeval-array ( array -- byte-array )
- [ length "timeval" <c-array> ] keep
- dup length [ over [ pick set-timeval-nth ] [ 2drop ] if ] 2each ;
+ [ [ "timeval" <c-object> ] unless* ] map concat ;
: timestamp>timeval ( timestamp -- timeval )
- unix-1970 time- duration>milliseconds make-timeval ;
+ unix-1970 time- duration>microseconds make-timeval ;
: timestamps>byte-array ( timestamps -- byte-array )
[ dup [ timestamp>timeval ] when ] map make-timeval-array ;
M: string set-file-user ( path string -- )
user-id f set-file-ids ;
-
+
M: integer set-file-group ( path gid -- )
f swap set-file-ids ;
-
+
M: string set-file-group ( path string -- )
group-id
f swap set-file-ids ;
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types alien.syntax combinators
+io.backend io.files io.unix.files kernel math system unix
+unix.statfs.freebsd unix.statvfs.freebsd unix.getfsstat.freebsd
+sequences grouping alien.strings io.encodings.utf8
+specialized-arrays.direct.uint arrays ;
+IN: io.unix.files.freebsd
+
+TUPLE: freebsd-file-system-info < unix-file-system-info
+version io-size owner syncreads syncwrites asyncreads asyncwrites ;
+
+M: freebsd new-file-system-info freebsd-file-system-info new ;
+
+M: freebsd file-system-statfs ( path -- byte-array )
+ "statfs" <c-object> tuck statfs io-error ;
+
+M: freebsd statfs>file-system-info ( file-system-info statvfs -- file-system-info )
+ {
+ [ statfs-f_version >>version ]
+ [ statfs-f_type >>type ]
+ [ statfs-f_flags >>flags ]
+ [ statfs-f_bsize >>block-size ]
+ [ statfs-f_iosize >>io-size ]
+ [ statfs-f_blocks >>blocks ]
+ [ statfs-f_bfree >>blocks-free ]
+ [ statfs-f_bavail >>blocks-available ]
+ [ statfs-f_files >>files ]
+ [ statfs-f_ffree >>files-free ]
+ [ statfs-f_syncwrites >>syncwrites ]
+ [ statfs-f_asyncwrites >>asyncwrites ]
+ [ statfs-f_syncreads >>syncreads ]
+ [ statfs-f_asyncreads >>asyncreads ]
+ [ statfs-f_namemax >>name-max ]
+ [ statfs-f_owner >>owner ]
+ [ statfs-f_fsid 2 <direct-uint-array> >array >>id ]
+ [ statfs-f_fstypename utf8 alien>string >>type ]
+ [ statfs-f_mntfromname utf8 alien>string >>device-name ]
+ [ statfs-f_mntonname utf8 alien>string >>mount-point ]
+ } cleave ;
+
+M: freebsd file-system-statvfs ( path -- byte-array )
+ "statvfs" <c-object> tuck statvfs io-error ;
+
+M: freebsd statvfs>file-system-info ( file-system-info statvfs -- file-system-info )
+ {
+ [ statvfs-f_favail >>files-available ]
+ [ statvfs-f_frsize >>preferred-block-size ]
+ } cleave ;
+
+M: freebsd file-systems ( -- array )
+ f 0 0 getfsstat dup io-error
+ "statfs" <c-array> dup dup length 0 getfsstat io-error
+ "statfs" heap-size group
+ [ statfs-f_mntonname alien>native-string file-system-info ] map ;
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types alien.syntax combinators csv
+io.backend io.encodings.utf8 io.files io.streams.string
+io.unix.files kernel math.order namespaces sequences sorting
+system unix unix.statfs.linux unix.statvfs.linux
+specialized-arrays.direct.uint arrays ;
+IN: io.unix.files.linux
+
+TUPLE: linux-file-system-info < unix-file-system-info
+namelen ;
+
+M: linux new-file-system-info linux-file-system-info new ;
+
+M: linux file-system-statfs ( path -- byte-array )
+ "statfs64" <c-object> tuck statfs64 io-error ;
+
+M: linux statfs>file-system-info ( struct -- statfs )
+ {
+ [ statfs64-f_type >>type ]
+ [ statfs64-f_bsize >>block-size ]
+ [ statfs64-f_blocks >>blocks ]
+ [ statfs64-f_bfree >>blocks-free ]
+ [ statfs64-f_bavail >>blocks-available ]
+ [ statfs64-f_files >>files ]
+ [ statfs64-f_ffree >>files-free ]
+ [ statfs64-f_fsid 2 <direct-uint-array> >array >>id ]
+ [ statfs64-f_namelen >>namelen ]
+ [ statfs64-f_frsize >>preferred-block-size ]
+ ! [ statfs64-f_spare >>spare ]
+ } cleave ;
+
+M: linux file-system-statvfs ( path -- byte-array )
+ "statvfs64" <c-object> tuck statvfs64 io-error ;
+
+M: linux statvfs>file-system-info ( struct -- statfs )
+ {
+ [ statvfs64-f_flag >>flags ]
+ [ statvfs64-f_namemax >>name-max ]
+ } cleave ;
+
+TUPLE: mtab-entry file-system-name mount-point type options
+frequency pass-number ;
+
+: mtab-csv>mtab-entry ( csv -- mtab-entry )
+ [ mtab-entry new ] dip
+ {
+ [ first >>file-system-name ]
+ [ second >>mount-point ]
+ [ third >>type ]
+ [ fourth <string-reader> csv first >>options ]
+ [ 4 swap nth >>frequency ]
+ [ 5 swap nth >>pass-number ]
+ } cleave ;
+
+: parse-mtab ( -- array )
+ [
+ "/etc/mtab" utf8 <file-reader>
+ CHAR: \s delimiter set csv
+ ] with-scope
+ [ mtab-csv>mtab-entry ] map ;
+
+M: linux file-systems
+ parse-mtab [
+ [ mount-point>> file-system-info ] keep
+ {
+ [ file-system-name>> >>device-name ]
+ [ mount-point>> >>mount-point ]
+ [ type>> >>type ]
+ } cleave
+ ] map ;
+
+ERROR: file-system-not-found ;
+
+M: linux file-system-info ( path -- )
+ normalize-path
+ [
+ [ new-file-system-info ] dip
+ [ file-system-statfs statfs>file-system-info ]
+ [ file-system-statvfs statvfs>file-system-info ] bi
+ file-system-calculations
+ ] keep
+
+ parse-mtab [ [ mount-point>> ] bi@ <=> invert-comparison ] sort
+ [ mount-point>> head? ] with find nip [ file-system-not-found ] unless*
+ {
+ [ file-system-name>> >>device-name drop ]
+ [ mount-point>> >>mount-point drop ]
+ [ type>> >>type ]
+ } 2cleave ;
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types alien.strings combinators
+grouping io.encodings.utf8 io.files kernel math sequences
+system unix io.unix.files specialized-arrays.direct.uint arrays
+unix.statfs.macosx unix.statvfs.macosx unix.getfsstat.macosx ;
+IN: io.unix.files.macosx
+
+TUPLE: macosx-file-system-info < unix-file-system-info
+io-size owner type-id filesystem-subtype ;
+
+M: macosx file-systems ( -- array )
+ f <void*> dup 0 getmntinfo64 dup io-error
+ [ *void* ] dip
+ "statfs64" heap-size [ * memory>byte-array ] keep group
+ [ statfs64-f_mntonname utf8 alien>string file-system-info ] map ;
+ ! [ [ new-file-system-info ] dip statfs>file-system-info ] map ;
+
+M: macosx new-file-system-info macosx-file-system-info new ;
+
+M: macosx file-system-statfs ( normalized-path -- statfs )
+ "statfs64" <c-object> tuck statfs64 io-error ;
+
+M: macosx file-system-statvfs ( normalized-path -- statvfs )
+ "statvfs" <c-object> tuck statvfs io-error ;
+
+M: macosx statfs>file-system-info ( file-system-info byte-array -- file-system-info' )
+ {
+ [ statfs64-f_bsize >>block-size ]
+ [ statfs64-f_iosize >>io-size ]
+ [ statfs64-f_blocks >>blocks ]
+ [ statfs64-f_bfree >>blocks-free ]
+ [ statfs64-f_bavail >>blocks-available ]
+ [ statfs64-f_files >>files ]
+ [ statfs64-f_ffree >>files-free ]
+ [ statfs64-f_fsid 2 <direct-uint-array> >array >>id ]
+ [ statfs64-f_owner >>owner ]
+ [ statfs64-f_type >>type-id ]
+ [ statfs64-f_flags >>flags ]
+ [ statfs64-f_fssubtype >>filesystem-subtype ]
+ [ statfs64-f_fstypename utf8 alien>string >>type ]
+ [ statfs64-f_mntonname utf8 alien>string >>mount-point ]
+ [ statfs64-f_mntfromname utf8 alien>string >>device-name ]
+ } cleave ;
+
+M: macosx statvfs>file-system-info ( file-system-info byte-array -- file-system-info' )
+ {
+ [ statvfs-f_frsize >>preferred-block-size ]
+ [ statvfs-f_favail >>files-available ]
+ [ statvfs-f_namemax >>name-max ]
+ } cleave ;
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax kernel unix.stat math unix
+combinators system io.backend accessors alien.c-types
+io.encodings.utf8 alien.strings unix.types io.unix.files
+io.files unix.statvfs.netbsd unix.getfsstat.netbsd arrays
+grouping sequences io.encodings.utf8 specialized-arrays.direct.uint ;
+IN: io.unix.files.netbsd
+
+TUPLE: netbsd-file-system-info < unix-file-system-info
+blocks-reserved files-reserved
+owner io-size sync-reads sync-writes async-reads async-writes
+idx mount-from ;
+
+M: netbsd new-file-system-info netbsd-file-system-info new ;
+
+M: netbsd file-system-statvfs
+ "statvfs" <c-object> tuck statvfs io-error ;
+
+M: netbsd statvfs>file-system-info ( file-system-info statvfs -- file-system-info' )
+ {
+ [ statvfs-f_flag >>flags ]
+ [ statvfs-f_bsize >>block-size ]
+ [ statvfs-f_frsize >>preferred-block-size ]
+ [ statvfs-f_iosize >>io-size ]
+ [ statvfs-f_blocks >>blocks ]
+ [ statvfs-f_bfree >>blocks-free ]
+ [ statvfs-f_bavail >>blocks-available ]
+ [ statvfs-f_bresvd >>blocks-reserved ]
+ [ statvfs-f_files >>files ]
+ [ statvfs-f_ffree >>files-free ]
+ [ statvfs-f_favail >>files-available ]
+ [ statvfs-f_fresvd >>files-reserved ]
+ [ statvfs-f_syncreads >>sync-reads ]
+ [ statvfs-f_syncwrites >>sync-writes ]
+ [ statvfs-f_asyncreads >>async-reads ]
+ [ statvfs-f_asyncwrites >>async-writes ]
+ [ statvfs-f_fsidx 2 <direct-uint-array> >array >>idx ]
+ [ statvfs-f_fsid >>id ]
+ [ statvfs-f_namemax >>name-max ]
+ [ statvfs-f_owner >>owner ]
+ ! [ statvfs-f_spare >>spare ]
+ [ statvfs-f_fstypename utf8 alien>string >>type ]
+ [ statvfs-f_mntonname utf8 alien>string >>mount-point ]
+ [ statvfs-f_mntfromname utf8 alien>string >>device-name ]
+ } cleave ;
+
+M: netbsd file-systems ( -- array )
+ f 0 0 getvfsstat dup io-error
+ "statvfs" <c-array> dup dup length 0 getvfsstat io-error
+ "statvfs" heap-size group
+ [ statvfs-f_mntonname utf8 alien>string file-system-info ] map ;
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types alien.strings alien.syntax
+combinators io.backend io.files io.unix.files kernel math
+sequences system unix unix.getfsstat.openbsd grouping
+unix.statfs.openbsd unix.statvfs.openbsd unix.types
+specialized-arrays.direct.uint arrays ;
+IN: io.unix.files.openbsd
+
+TUPLE: freebsd-file-system-info < unix-file-system-info
+io-size sync-writes sync-reads async-writes async-reads
+owner ;
+
+M: openbsd new-file-system-info freebsd-file-system-info new ;
+
+M: openbsd file-system-statfs
+ "statfs" <c-object> tuck statfs io-error ;
+
+M: openbsd statfs>file-system-info ( file-system-info statfs -- file-system-info' )
+ {
+ [ statfs-f_flags >>flags ]
+ [ statfs-f_bsize >>block-size ]
+ [ statfs-f_iosize >>io-size ]
+ [ statfs-f_blocks >>blocks ]
+ [ statfs-f_bfree >>blocks-free ]
+ [ statfs-f_bavail >>blocks-available ]
+ [ statfs-f_files >>files ]
+ [ statfs-f_ffree >>files-free ]
+ [ statfs-f_favail >>files-available ]
+ [ statfs-f_syncwrites >>sync-writes ]
+ [ statfs-f_syncreads >>sync-reads ]
+ [ statfs-f_asyncwrites >>async-writes ]
+ [ statfs-f_asyncreads >>async-reads ]
+ [ statfs-f_fsid 2 <direct-uint-array> >array >>id ]
+ [ statfs-f_namemax >>name-max ]
+ [ statfs-f_owner >>owner ]
+ ! [ statfs-f_spare >>spare ]
+ [ statfs-f_fstypename alien>native-string >>type ]
+ [ statfs-f_mntonname alien>native-string >>mount-point ]
+ [ statfs-f_mntfromname alien>native-string >>device-name ]
+ } cleave ;
+
+M: openbsd file-system-statvfs ( normalized-path -- statvfs )
+ "statvfs" <c-object> tuck statvfs io-error ;
+
+M: openbsd statvfs>file-system-info ( file-system-info statvfs -- file-system-info' )
+ {
+ [ statvfs-f_frsize >>preferred-block-size ]
+ } cleave ;
+
+M: openbsd file-systems ( -- seq )
+ f 0 0 getfsstat dup io-error
+ "statfs" <c-array> dup dup length 0 getfsstat io-error
+ "statfs" heap-size group
+ [ statfs-f_mntonname alien>native-string file-system-info ] map ;
--- /dev/null
+unportable
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel io.ports io.unix.backend math.bitwise
-unix io.files.unique.backend system ;
+unix system io.files.unique ;
IN: io.unix.files.unique
: open-unique-flags ( -- flags )
{ O_RDWR O_CREAT O_EXCL } flags ;
-M: unix (make-unique-file) ( path -- )
+M: unix touch-unique-file ( path -- )
open-unique-flags file-mode open-file close-file ;
M: unix temporary-path ( -- path ) "/tmp" ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.c-types kernel math math.bitwise namespaces
-locals accessors combinators threads vectors hashtables
-sequences assocs continuations sets
-unix unix.time unix.kqueue unix.process
-io.ports io.unix.backend io.launcher io.unix.launcher
-io.monitors ;
+USING: accessors alien.c-types combinators io.unix.backend
+kernel math.bitwise sequences struct-arrays unix unix.kqueue
+unix.time assocs ;
IN: io.unix.kqueue
-TUPLE: kqueue-mx < mx events monitors ;
+TUPLE: kqueue-mx < mx events ;
: max-events ( -- n )
#! We read up to 256 events at a time. This is an arbitrary
: <kqueue-mx> ( -- mx )
kqueue-mx new-mx
- H{ } clone >>monitors
kqueue dup io-error >>fd
- max-events "kevent" <c-array> >>events ;
+ max-events "kevent" <struct-array> >>events ;
-GENERIC: io-task-filter ( task -- n )
-
-M: input-task io-task-filter drop EVFILT_READ ;
-
-M: output-task io-task-filter drop EVFILT_WRITE ;
-
-GENERIC: io-task-fflags ( task -- n )
-
-M: io-task io-task-fflags drop 0 ;
-
-: make-kevent ( task flags -- event )
+: make-kevent ( fd filter flags -- event )
"kevent" <c-object>
- tuck set-kevent-flags
- over io-task-fd over set-kevent-ident
- over io-task-fflags over set-kevent-fflags
- swap io-task-filter over set-kevent-filter ;
+ [ set-kevent-flags ] keep
+ [ set-kevent-filter ] keep
+ [ set-kevent-ident ] keep ;
: register-kevent ( kevent mx -- )
- fd>> swap 1 f 0 f kevent
- 0 < [ err_no ESRCH = [ (io-error) ] unless ] when ;
-
-M: kqueue-mx register-io-task ( task mx -- )
- [ >r EV_ADD make-kevent r> register-kevent ]
- [ call-next-method ]
- 2bi ;
-
-M: kqueue-mx unregister-io-task ( task mx -- )
- [ call-next-method ]
- [ >r EV_DELETE make-kevent r> register-kevent ]
- 2bi ;
+ fd>> swap 1 f 0 f kevent io-error ;
+
+M: kqueue-mx add-input-callback ( thread fd mx -- )
+ [ call-next-method ] [
+ [ EVFILT_READ { EV_ADD EV_ONESHOT } flags make-kevent ] dip
+ register-kevent
+ ] 2bi ;
+
+M: kqueue-mx add-output-callback ( thread fd mx -- )
+ [ call-next-method ] [
+ [ EVFILT_WRITE { EV_ADD EV_ONESHOT } flags make-kevent ] dip
+ register-kevent
+ ] 2bi ;
+
+M: kqueue-mx remove-input-callbacks ( fd mx -- seq )
+ 2dup reads>> key? [
+ [ call-next-method ] [
+ [ EVFILT_READ EV_DELETE make-kevent ] dip
+ register-kevent
+ ] 2bi
+ ] [ 2drop f ] if ;
+
+M: kqueue-mx remove-output-callbacks ( fd mx -- seq )
+ 2dup writes>> key? [
+ [
+ [ EVFILT_WRITE EV_DELETE make-kevent ] dip
+ register-kevent
+ ] [ call-next-method ] 2bi
+ ] [ 2drop f ] if ;
: wait-kevent ( mx timespec -- n )
- >r [ fd>> f 0 ] keep events>> max-events r> kevent
- dup multiplexer-error ;
-
-:: kevent-read-task ( mx fd kevent -- )
- mx fd mx reads>> at perform-io-task ;
-
-:: kevent-write-task ( mx fd kevent -- )
- mx fd mx writes>> at perform-io-task ;
-
-:: kevent-proc-task ( mx pid kevent -- )
- pid wait-for-pid
- pid find-process
- dup [ swap notify-exit ] [ 2drop ] if ;
-
-: parse-action ( mask -- changed )
[
- NOTE_DELETE +remove-file+ ?flag
- NOTE_WRITE +modify-file+ ?flag
- NOTE_EXTEND +modify-file+ ?flag
- NOTE_ATTRIB +modify-file+ ?flag
- NOTE_RENAME +rename-file+ ?flag
- NOTE_REVOKE +remove-file+ ?flag
- drop
- ] { } make prune ;
-
-:: kevent-vnode-task ( mx kevent fd -- )
- ""
- kevent kevent-fflags parse-action
- fd mx monitors>> at queue-change ;
+ [ fd>> f 0 ]
+ [ events>> [ underlying>> ] [ length ] bi ] bi
+ ] dip kevent multiplexer-error ;
: handle-kevent ( mx kevent -- )
- [ ] [ kevent-ident ] [ kevent-filter ] tri {
- { [ dup EVFILT_READ = ] [ drop kevent-read-task ] }
- { [ dup EVFILT_WRITE = ] [ drop kevent-write-task ] }
- { [ dup EVFILT_PROC = ] [ drop kevent-proc-task ] }
- { [ dup EVFILT_VNODE = ] [ drop kevent-vnode-task ] }
- } cond ;
+ [ kevent-ident swap ] [ kevent-filter ] bi {
+ { EVFILT_READ [ input-available ] }
+ { EVFILT_WRITE [ output-available ] }
+ } case ;
: handle-kevents ( mx n -- )
- [ over events>> kevent-nth handle-kevent ] with each ;
+ [ dup events>> ] dip head-slice [ handle-kevent ] with each ;
-M: kqueue-mx wait-for-events ( ms mx -- )
+M: kqueue-mx wait-for-events ( us mx -- )
swap dup [ make-timespec ] when
dupd wait-kevent handle-kevents ;
-
-! Procs
-: make-proc-kevent ( pid -- kevent )
- "kevent" <c-object>
- tuck set-kevent-ident
- EV_ADD over set-kevent-flags
- EVFILT_PROC over set-kevent-filter
- NOTE_EXIT over set-kevent-fflags ;
-
-: register-pid-task ( pid mx -- )
- swap make-proc-kevent swap register-kevent ;
-
-! VNodes
-TUPLE: vnode-monitor < monitor fd ;
-
-: vnode-fflags ( -- n )
- {
- NOTE_DELETE
- NOTE_WRITE
- NOTE_EXTEND
- NOTE_ATTRIB
- NOTE_LINK
- NOTE_RENAME
- NOTE_REVOKE
- } flags ;
-
-: make-vnode-kevent ( fd flags -- kevent )
- "kevent" <c-object>
- tuck set-kevent-flags
- tuck set-kevent-ident
- EVFILT_VNODE over set-kevent-filter
- vnode-fflags over set-kevent-fflags ;
-
-: register-monitor ( monitor mx -- )
- >r dup fd>> r>
- [ >r EV_ADD EV_CLEAR bitor make-vnode-kevent r> register-kevent drop ]
- [ monitors>> set-at ] 3bi ;
-
-: unregister-monitor ( monitor mx -- )
- >r fd>> r>
- [ monitors>> delete-at ]
- [ >r EV_DELETE make-vnode-kevent r> register-kevent ] 2bi ;
-
-: <vnode-monitor> ( path mailbox -- monitor )
- >r [ O_RDONLY 0 open dup io-error ] keep r>
- vnode-monitor new-monitor swap >>fd
- [ dup kqueue-mx get register-monitor ] [ ] [ fd>> close ] cleanup ;
-
-M: vnode-monitor dispose
- [ kqueue-mx get unregister-monitor ] [ fd>> close ] bi ;
USING: io.files tools.test io.launcher arrays io namespaces
continuations math io.encodings.binary io.encodings.ascii
accessors kernel sequences io.encodings.utf8 destructors
-io.streams.duplex ;
+io.streams.duplex locals concurrency.promises threads
+unix.process ;
[ ] [
[ "launcher-test-1" temp-file delete-file ] ignore-errors
input-stream get contents
] with-stream
] unit-test
+
+! Killed processes were exiting with code 0 on FreeBSD
+[ f ] [
+ [let | p [ <promise> ]
+ s [ <promise> ] |
+ [
+ "sleep 1000" run-detached
+ [ p fulfill ] [ wait-for-process s fulfill ] bi
+ ] in-thread
+
+ p ?promise handle>> 9 kill drop
+ s ?promise 0 =
+ ]
+] unit-test
! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel namespaces math system sequences debugger
+USING: kernel namespaces math system sequences
continuations arrays assocs combinators alien.c-types strings
threads accessors environment
io io.backend io.launcher io.ports io.files
command>> dup string? [ tokenize-command ] when ;
: assoc>env ( assoc -- env )
- [ "=" swap 3append ] { } assoc>map ;
+ [ "=" glue ] { } assoc>map ;
: setup-priority ( process -- process )
dup priority>> [
: redirect-fd ( oldfd fd -- )
2dup = [ 2drop ] [ dup2 io-error ] if ;
-: redirect-inherit ( obj mode fd -- )
- 3drop ;
-
: redirect-file ( obj mode fd -- )
- >r >r normalize-path r> file-mode
- open-file r> redirect-fd ;
+ [ [ normalize-path ] dip file-mode open-file ] dip redirect-fd ;
: redirect-file-append ( obj mode fd -- )
- >r drop path>> normalize-path open-append r> redirect-fd ;
+ [ drop path>> normalize-path open-append ] dip redirect-fd ;
: redirect-closed ( obj mode fd -- )
- >r >r drop "/dev/null" r> r> redirect-file ;
+ [ drop "/dev/null" ] 2dip redirect-file ;
: redirect ( obj mode fd -- )
{
- { [ pick not ] [ redirect-inherit ] }
+ { [ pick not ] [ 3drop ] }
{ [ pick string? ] [ redirect-file ] }
{ [ pick appender? ] [ redirect-file-append ] }
{ [ pick +closed+ eq? ] [ redirect-closed ] }
- { [ pick fd? ] [ >r drop fd>> dup reset-fd r> redirect-fd ] }
- [ >r >r underlying-handle r> r> redirect ]
+ { [ pick fd? ] [ [ drop fd>> dup reset-fd ] dip redirect-fd ] }
+ [ [ underlying-handle ] 2dip redirect ]
} cond ;
: ?closed ( obj -- obj' )
processes get swap [ nip swap handle>> = ] curry
assoc-find 2drop ;
+TUPLE: signal n ;
+
+: code>status ( code -- obj )
+ dup WIFEXITED [ WEXITSTATUS ] [ WTERMSIG signal boa ] if ;
+
M: unix wait-for-processes ( -- ? )
-1 0 <int> tuck WNOHANG waitpid
dup 0 <= [
2drop t
] [
- find-process dup [
- swap *int WEXITSTATUS notify-exit f
- ] [
- 2drop f
- ] if
+ find-process dup
+ [ swap *int code>status notify-exit f ] [ 2drop f ] if
] if ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel io.backend io.monitors io.unix.backend
-io.unix.select io.unix.linux.monitors system namespaces ;
+USING: kernel system namespaces io.backend io.unix.backend
+io.unix.multiplexers io.unix.multiplexers.epoll ;
IN: io.unix.linux
M: linux init-io ( -- )
- <select-mx> mx set-global ;
+ <epoll-mx> mx set-global ;
linux set-io-backend
! See http://factorcode.org/license.txt for BSD license.
USING: kernel io.backend io.monitors io.monitors.recursive
io.files io.buffers io.monitors io.ports io.timeouts
-io.unix.backend io.unix.select io.encodings.utf8
-unix.linux.inotify assocs namespaces make threads continuations
-init math math.bitwise sets alien alien.strings alien.c-types
-vocabs.loader accessors system hashtables destructors unix ;
+io.unix.backend io.encodings.utf8 unix.linux.inotify assocs
+namespaces make threads continuations init math math.bitwise
+sets alien alien.strings alien.c-types vocabs.loader accessors
+system hashtables destructors unix ;
IN: io.unix.linux.monitors
SYMBOL: watches
inotify-fd -rot inotify_add_watch dup io-error dup check-existing ;
: add-watch ( path mask mailbox -- monitor )
- >r
- >r (normalize-path) r>
- [ (add-watch) ] [ drop ] 2bi r>
+ [ [ (normalize-path) ] dip [ (add-watch) ] [ drop ] 2bi ] dip
<linux-monitor> [ ] [ ] [ wd>> ] tri watches get set-at ;
: check-inotify ( -- )
: next-event ( i buffer -- i buffer )
2dup inotify-event@
inotify-event-len "inotify-event" heap-size +
- swap >r + r> ;
+ swap [ + ] dip ;
: parse-file-notifications ( i buffer -- )
2dup events-exhausted? [ 2drop ] [
2dup inotify-event@ dup inotify-event-wd wd>monitor
- >r parse-file-notify r> queue-change
+ [ parse-file-notify ] dip queue-change
next-event parse-file-notifications
] if ;
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
+USING: io.backend system namespaces io.unix.multiplexers
+io.unix.multiplexers.run-loop ;
IN: io.unix.macosx
-USING: io.unix.bsd io.backend system ;
+
+M: macosx init-io ( -- )
+ <run-loop-mx> mx set-global ;
macosx set-io-backend
! See http://factorcode.org/license.txt for BSD license.
USING: io.backend io.monitors
core-foundation.fsevents continuations kernel sequences
-namespaces arrays system locals accessors destructors ;
+namespaces arrays system locals accessors destructors fry ;
IN: io.unix.macosx.monitors
TUPLE: macosx-monitor < monitor handle ;
: enqueue-notifications ( triples monitor -- )
- [
- >r first { +modify-file+ } r> queue-change
- ] curry each ;
+ '[ first { +modify-file+ } _ queue-change ] each ;
M:: macosx (monitor) ( path recursive? mailbox -- monitor )
[let | path [ path normalize-path ] |
--- /dev/null
+Slava Pestov
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types kernel destructors bit-arrays
+sequences assocs struct-arrays math namespaces locals fry unix
+unix.linux.epoll unix.time io.ports io.unix.backend
+io.unix.multiplexers ;
+IN: io.unix.multiplexers.epoll
+
+TUPLE: epoll-mx < mx events ;
+
+: max-events ( -- n )
+ #! We read up to 256 events at a time. This is an arbitrary
+ #! constant...
+ 256 ; inline
+
+: <epoll-mx> ( -- mx )
+ epoll-mx new-mx
+ max-events epoll_create dup io-error >>fd
+ max-events "epoll-event" <struct-array> >>events ;
+
+M: epoll-mx dispose fd>> close-file ;
+
+: make-event ( fd events -- event )
+ "epoll-event" <c-object>
+ [ set-epoll-event-events ] keep
+ [ set-epoll-event-fd ] keep ;
+
+:: do-epoll-ctl ( fd mx what events -- )
+ mx fd>> what fd fd events make-event epoll_ctl io-error ;
+
+: do-epoll-add ( fd mx events -- )
+ EPOLL_CTL_ADD swap EPOLLONESHOT bitor do-epoll-ctl ;
+
+: do-epoll-del ( fd mx events -- )
+ EPOLL_CTL_DEL swap do-epoll-ctl ;
+
+M: epoll-mx add-input-callback ( thread fd mx -- )
+ [ EPOLLIN do-epoll-add ] [ call-next-method ] 2bi ;
+
+M: epoll-mx add-output-callback ( thread fd mx -- )
+ [ EPOLLOUT do-epoll-add ] [ call-next-method ] 2bi ;
+
+M: epoll-mx remove-input-callbacks ( fd mx -- seq )
+ 2dup reads>> key? [
+ [ call-next-method ] [ EPOLLIN do-epoll-del ] 2bi
+ ] [ 2drop f ] if ;
+
+M: epoll-mx remove-output-callbacks ( fd mx -- seq )
+ 2dup writes>> key? [
+ [ EPOLLOUT do-epoll-del ] [ call-next-method ] 2bi
+ ] [ 2drop f ] if ;
+
+: wait-event ( mx us -- n )
+ [ [ fd>> ] [ events>> ] bi [ underlying>> ] [ length ] bi ] [ 1000 /i ] bi*
+ epoll_wait multiplexer-error ;
+
+: handle-event ( event mx -- )
+ [ epoll-event-fd ] dip
+ [ EPOLLIN EPOLLOUT bitor do-epoll-del ]
+ [ input-available ] [ output-available ] 2tri ;
+
+: handle-events ( mx n -- )
+ [ dup events>> ] dip head-slice swap '[ _ handle-event ] each ;
+
+M: epoll-mx wait-for-events ( us mx -- )
+ swap 60000000 or dupd wait-event handle-events ;
--- /dev/null
+unportable
--- /dev/null
+Slava Pestov
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types combinators destructors
+io.unix.backend kernel math.bitwise sequences struct-arrays unix
+unix.kqueue unix.time assocs io.unix.multiplexers ;
+IN: io.unix.multiplexers.kqueue
+
+TUPLE: kqueue-mx < mx events ;
+
+: max-events ( -- n )
+ #! We read up to 256 events at a time. This is an arbitrary
+ #! constant...
+ 256 ; inline
+
+: <kqueue-mx> ( -- mx )
+ kqueue-mx new-mx
+ kqueue dup io-error >>fd
+ max-events "kevent" <struct-array> >>events ;
+
+M: kqueue-mx dispose fd>> close-file ;
+
+: make-kevent ( fd filter flags -- event )
+ "kevent" <c-object>
+ [ set-kevent-flags ] keep
+ [ set-kevent-filter ] keep
+ [ set-kevent-ident ] keep ;
+
+: register-kevent ( kevent mx -- )
+ fd>> swap 1 f 0 f kevent io-error ;
+
+M: kqueue-mx add-input-callback ( thread fd mx -- )
+ [ call-next-method ] [
+ [ EVFILT_READ { EV_ADD EV_ONESHOT } flags make-kevent ] dip
+ register-kevent
+ ] 2bi ;
+
+M: kqueue-mx add-output-callback ( thread fd mx -- )
+ [ call-next-method ] [
+ [ EVFILT_WRITE { EV_ADD EV_ONESHOT } flags make-kevent ] dip
+ register-kevent
+ ] 2bi ;
+
+M: kqueue-mx remove-input-callbacks ( fd mx -- seq )
+ 2dup reads>> key? [
+ [ call-next-method ] [
+ [ EVFILT_READ EV_DELETE make-kevent ] dip
+ register-kevent
+ ] 2bi
+ ] [ 2drop f ] if ;
+
+M: kqueue-mx remove-output-callbacks ( fd mx -- seq )
+ 2dup writes>> key? [
+ [
+ [ EVFILT_WRITE EV_DELETE make-kevent ] dip
+ register-kevent
+ ] [ call-next-method ] 2bi
+ ] [ 2drop f ] if ;
+
+: wait-kevent ( mx timespec -- n )
+ [
+ [ fd>> f 0 ]
+ [ events>> [ underlying>> ] [ length ] bi ] bi
+ ] dip kevent multiplexer-error ;
+
+: handle-kevent ( mx kevent -- )
+ [ kevent-ident swap ] [ kevent-filter ] bi {
+ { EVFILT_READ [ input-available ] }
+ { EVFILT_WRITE [ output-available ] }
+ } case ;
+
+: handle-kevents ( mx n -- )
+ [ dup events>> ] dip head-slice [ handle-kevent ] with each ;
+
+M: kqueue-mx wait-for-events ( us mx -- )
+ swap dup [ make-timespec ] when
+ dupd wait-kevent handle-kevents ;
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel accessors assocs sequences threads ;
+IN: io.unix.multiplexers
+
+TUPLE: mx fd reads writes ;
+
+: new-mx ( class -- obj )
+ new
+ H{ } clone >>reads
+ H{ } clone >>writes ; inline
+
+GENERIC: add-input-callback ( thread fd mx -- )
+
+M: mx add-input-callback reads>> push-at ;
+
+GENERIC: add-output-callback ( thread fd mx -- )
+
+M: mx add-output-callback writes>> push-at ;
+
+GENERIC: remove-input-callbacks ( fd mx -- callbacks )
+
+M: mx remove-input-callbacks reads>> delete-at* drop ;
+
+GENERIC: remove-output-callbacks ( fd mx -- callbacks )
+
+M: mx remove-output-callbacks writes>> delete-at* drop ;
+
+GENERIC: wait-for-events ( ms mx -- )
+
+: input-available ( fd mx -- )
+ reads>> delete-at* drop [ resume ] each ;
+
+: output-available ( fd mx -- )
+ writes>> delete-at* drop [ resume ] each ;
--- /dev/null
+USING: io.unix.multiplexers.run-loop tools.test
+destructors ;
+IN: io.unix.multiplexers.run-loop.tests
+
+[ ] [ <run-loop-mx> dispose ] unit-test
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel namespaces math accessors threads alien locals
+destructors combinators io.unix.multiplexers
+io.unix.multiplexers.kqueue core-foundation
+core-foundation.run-loop core-foundation.file-descriptors ;
+IN: io.unix.multiplexers.run-loop
+
+TUPLE: run-loop-mx kqueue-mx fd source ;
+
+: kqueue-callback ( -- callback )
+ "void" { "CFFileDescriptorRef" "CFOptionFlags" "void*" }
+ "cdecl" [
+ 3drop
+ 0 mx get kqueue-mx>> wait-for-events
+ mx get fd>> enable-all-callbacks
+ yield
+ ]
+ alien-callback ;
+
+SYMBOL: kqueue-run-loop-source
+
+: create-kqueue-source ( fd -- source )
+ f swap 0 CFFileDescriptorCreateRunLoopSource ;
+
+: add-kqueue-to-run-loop ( mx -- )
+ CFRunLoopGetMain swap source>> CFRunLoopDefaultMode CFRunLoopAddSource ;
+
+: remove-kqueue-from-run-loop ( source -- )
+ CFRunLoopGetMain swap source>> CFRunLoopDefaultMode CFRunLoopRemoveSource ;
+
+: <run-loop-mx> ( -- mx )
+ [
+ <kqueue-mx> |dispose
+ dup fd>> kqueue-callback <CFFileDescriptor> |dispose
+ dup create-kqueue-source run-loop-mx boa
+ dup add-kqueue-to-run-loop
+ ] with-destructors ;
+
+M: run-loop-mx dispose
+ [
+ {
+ [ fd>> &dispose drop ]
+ [ source>> &dispose drop ]
+ [ remove-kqueue-from-run-loop ]
+ [ kqueue-mx>> &dispose drop ]
+ } cleave
+ ] with-destructors ;
+
+M: run-loop-mx add-input-callback kqueue-mx>> add-input-callback ;
+M: run-loop-mx add-output-callback kqueue-mx>> add-output-callback ;
+M: run-loop-mx remove-input-callbacks kqueue-mx>> remove-input-callbacks ;
+M: run-loop-mx remove-output-callbacks kqueue-mx>> remove-output-callbacks ;
+
+M:: run-loop-mx wait-for-events ( us mx -- )
+ mx fd>> enable-all-callbacks
+ CFRunLoopDefaultMode us [ 1000000 /f ] [ 60 ] if* t CFRunLoopRunInMode
+ kCFRunLoopRunHandledSource = [ 0 mx wait-for-events ] when ;
--- /dev/null
+unportable
--- /dev/null
+Slava Pestov
--- /dev/null
+! Copyright (C) 2004, 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.c-types kernel bit-arrays sequences assocs unix
+math namespaces accessors math.order locals unix.time fry
+io.ports io.unix.backend io.unix.multiplexers ;
+IN: io.unix.multiplexers.select
+
+TUPLE: select-mx < mx read-fdset write-fdset ;
+
+! Factor's bit-arrays are an array of bytes, OS X expects
+! FD_SET to be an array of cells, so we have to account for
+! byte order differences on big endian platforms
+: munge ( i -- i' )
+ little-endian? [ BIN: 11000 bitxor ] unless ; inline
+
+: <select-mx> ( -- mx )
+ select-mx new-mx
+ FD_SETSIZE 8 * <bit-array> >>read-fdset
+ FD_SETSIZE 8 * <bit-array> >>write-fdset ;
+
+: clear-nth ( n seq -- ? )
+ [ nth ] [ [ f ] 2dip set-nth ] 2bi ;
+
+:: check-fd ( fd fdset mx quot -- )
+ fd munge fdset clear-nth [ fd mx quot call ] when ; inline
+
+: check-fdset ( fds fdset mx quot -- )
+ [ check-fd ] 3curry each ; inline
+
+: init-fdset ( fds fdset -- )
+ '[ t swap munge _ set-nth ] each ;
+
+: read-fdset/tasks ( mx -- seq fdset )
+ [ reads>> keys ] [ read-fdset>> ] bi ;
+
+: write-fdset/tasks ( mx -- seq fdset )
+ [ writes>> keys ] [ write-fdset>> ] bi ;
+
+: max-fd ( assoc -- n )
+ dup assoc-empty? [ drop 0 ] [ keys supremum ] if ;
+
+: num-fds ( mx -- n )
+ [ reads>> max-fd ] [ writes>> max-fd ] bi max 1+ ;
+
+: init-fdsets ( mx -- nfds read write except )
+ [ num-fds ]
+ [ read-fdset/tasks [ init-fdset ] [ underlying>> ] bi ]
+ [ write-fdset/tasks [ init-fdset ] [ underlying>> ] bi ] tri
+ f ;
+
+M:: select-mx wait-for-events ( us mx -- )
+ mx
+ [ init-fdsets us dup [ make-timeval ] when select multiplexer-error drop ]
+ [ [ read-fdset/tasks ] keep [ input-available ] check-fdset ]
+ [ [ write-fdset/tasks ] keep [ output-available ] check-fdset ]
+ tri ;
--- /dev/null
+unportable
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: system alien.c-types kernel unix math sequences
-qualified io.unix.backend io.ports ;
+USING: system kernel unix math sequences qualified
+io.unix.backend io.ports specialized-arrays.int accessors ;
IN: io.unix.pipes
QUALIFIED: io.pipes
M: unix io.pipes:(pipe) ( -- pair )
- 2 "int" <c-array>
- dup pipe io-error
- 2 c-int-array> first2 [ <fd> init-fd ] bi@ io.pipes:pipe boa ;
+ 2 <int-array>
+ [ underlying>> pipe io-error ]
+ [ first2 [ <fd> init-fd ] bi@ io.pipes:pipe boa ] bi ;
! See http://factorcode.org/license.txt for BSD license.
USING: alien.c-types kernel io.ports io.unix.backend
bit-arrays sequences assocs unix math namespaces
-accessors math.order locals unix.time ;
+accessors math.order locals unix.time fry ;
IN: io.unix.select
TUPLE: select-mx < mx read-fdset write-fdset ;
FD_SETSIZE 8 * <bit-array> >>write-fdset ;
: clear-nth ( n seq -- ? )
- [ nth ] [ f -rot set-nth ] 2bi ;
+ [ nth ] [ [ f ] 2dip set-nth ] 2bi ;
:: check-fd ( fd fdset mx quot -- )
fd munge fdset clear-nth [ fd mx quot call ] when ; inline
[ check-fd ] 3curry each ; inline
: init-fdset ( fds fdset -- )
- [ >r t swap munge r> set-nth ] curry each ;
+ '[ t swap munge _ set-nth ] each ;
: read-fdset/tasks ( mx -- seq fdset )
[ reads>> keys ] [ read-fdset>> ] bi ;
[ write-fdset/tasks [ init-fdset ] [ underlying>> ] bi ] tri
f ;
-M:: select-mx wait-for-events ( ms mx -- )
+M:: select-mx wait-for-events ( us mx -- )
mx
- [ init-fdsets ms dup [ make-timeval ] when select multiplexer-error ]
+ [ init-fdsets us dup [ make-timeval ] when select multiplexer-error drop ]
[ [ read-fdset/tasks ] keep [ input-available ] check-fdset ]
[ [ write-fdset/tasks ] keep [ output-available ] check-fdset ]
tri ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors io.sockets.secure kernel ;
+IN: io.unix.sockets.secure.debug
+
+: with-test-context ( quot -- )
+ <secure-config>
+ "resource:basis/openssl/test/server.pem" >>key-file
+ "resource:basis/openssl/test/dh1024.pem" >>dh-file
+ "password" >>password
+ swap with-secure-context ; inline
USING: accessors kernel namespaces io io.sockets
io.sockets.secure io.encodings.ascii io.streams.duplex
io.unix.backend classes words destructors threads tools.test
-concurrency.promises byte-arrays locals calendar io.timeouts ;
+concurrency.promises byte-arrays locals calendar io.timeouts
+io.unix.sockets.secure.debug ;
\ <secure-config> must-infer
{ 1 0 } [ [ ] with-secure-context ] must-infer-as
[ ] [ <promise> "port" set ] unit-test
-: with-test-context ( quot -- )
- <secure-config>
- "resource:basis/openssl/test/server.pem" >>key-file
- "resource:basis/openssl/test/dh1024.pem" >>dh-file
- "password" >>password
- swap with-secure-context ; inline
-
:: server-test ( quot -- )
[
[
! Copyright (C) 2007, 2008, Slava Pestov, Elie CHAFTARI.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors unix byte-arrays kernel debugger sequences namespaces math
-math.order combinators init alien alien.c-types alien.strings libc
-continuations destructors
-openssl openssl.libcrypto openssl.libssl
-io.files io.ports io.unix.backend io.unix.sockets
-io.encodings.ascii io.buffers io.sockets io.sockets.secure
-io.timeouts system summary ;
+USING: accessors unix byte-arrays kernel sequences
+namespaces math math.order combinators init alien alien.c-types
+alien.strings libc continuations destructors openssl
+openssl.libcrypto openssl.libssl io io.files io.ports
+io.unix.backend io.unix.sockets io.encodings.ascii io.buffers
+io.sockets io.sockets.secure io.sockets.secure.openssl
+io.timeouts system summary fry ;
IN: io.unix.sockets.secure
M: ssl-handle handle-fd file>> handle-fd ;
{ -1 [ err_no ECONNRESET = [ premature-close ] [ (io-error) ] if ] }
{ 0 [ premature-close ] }
} case
- ] [
- nip (ssl-error)
- ] if ;
+ ] [ nip (ssl-error) ] if ;
: check-accept-response ( handle r -- event )
over handle>> over SSL_get_error
: do-ssl-accept ( ssl-handle -- )
dup dup handle>> SSL_accept check-accept-response dup
- [ >r dup file>> r> wait-for-fd do-ssl-accept ] [ 2drop ] if ;
+ [ [ dup file>> ] dip wait-for-fd do-ssl-accept ] [ 2drop ] if ;
: maybe-handshake ( ssl-handle -- )
dup connected>> [ drop ] [
[ [ handle>> SSL_get1_session ] dip save-session ]
2bi ;
-: secure-connection ( ssl-handle addrspec -- )
- dup get-session [ resume-session ] [ begin-session ] ?if ;
+: secure-connection ( client-out addrspec -- )
+ [ handle>> ] dip
+ [
+ '[
+ _ dup get-session
+ [ resume-session ] [ begin-session ] ?if
+ ] with-timeout
+ ] [ drop t >>connected drop ] 2bi ;
M: secure establish-connection ( client-out remote -- )
- addrspec>>
- [ establish-connection ]
- [
- [ handle>> ] dip
- [ [ secure-connection ] curry with-timeout ]
- [ drop t >>connected drop ]
- 2bi
- ] 2bi ;
+ addrspec>> [ establish-connection ] [ secure-connection ] 2bi ;
M: secure (server) addrspec>> (server) ;
M: secure (accept)
[
- addrspec>> (accept) >r |dispose <ssl-socket> r>
+ addrspec>> (accept) [ |dispose <ssl-socket> ] dip
] with-destructors ;
: check-shutdown-response ( handle r -- event )
dup connected>> [
f >>connected [ (shutdown) ] with-timeout
] [ drop ] if ;
+
+: check-buffer ( port -- port )
+ dup buffer>> buffer-empty? [ upgrade-buffers-full ] unless ;
+
+: input/output-ports ( -- input output )
+ input-stream output-stream
+ [ get underlying-port check-buffer ] bi@
+ 2dup [ handle>> ] bi@ eq? [ upgrade-on-non-socket ] unless ;
+
+: make-input/output-secure ( input output -- )
+ dup handle>> fd? [ upgrade-on-non-socket ] unless
+ [ <ssl-socket> ] change-handle
+ handle>> >>handle drop ;
+
+: (send-secure-handshake) ( output -- )
+ remote-address get [ upgrade-on-non-socket ] unless*
+ secure-connection ;
+
+M: openssl send-secure-handshake
+ input/output-ports
+ [ make-input/output-secure ] keep
+ [ (send-secure-handshake) ] keep
+ remote-address get dup inet? [
+ host>> swap handle>> check-certificate
+ ] [ 2drop ] if ;
+
+M: openssl accept-secure-handshake
+ input/output-ports
+ make-input/output-secure ;
0 socket dup io-error <fd> init-fd |dispose ;
: set-socket-option ( fd level opt -- )
- >r >r handle-fd r> r> 1 <int> "int" heap-size setsockopt io-error ;
+ [ handle-fd ] 2dip 1 <int> "int" heap-size setsockopt io-error ;
M: unix addrinfo-error ( n -- )
dup zero? [ drop ] [ gai_strerror throw ] if ;
! Client sockets - TCP and Unix domain
M: object (get-local-address) ( handle remote -- sockaddr )
- >r handle-fd r> empty-sockaddr/size <int>
+ [ handle-fd ] dip empty-sockaddr/size <int>
[ getsockname io-error ] 2keep drop ;
M: object (get-remote-address) ( handle local -- sockaddr )
- >r handle-fd r> empty-sockaddr/size <int>
+ [ handle-fd ] dip empty-sockaddr/size <int>
[ getpeername io-error ] 2keep drop ;
: init-client-socket ( fd -- )
SOL_SOCKET SO_REUSEADDR set-socket-option ;
: server-socket-fd ( addrspec type -- fd )
- >r dup protocol-family r> socket-fd
+ [ dup protocol-family ] dip socket-fd
dup init-server-socket
dup handle-fd rot make-sockaddr/size bind io-error ;
M: object (accept) ( server addrspec -- fd sockaddr )
2dup do-accept
{
- { [ over 0 >= ] [ >r 2nip <fd> init-fd r> ] }
+ { [ over 0 >= ] [ [ 2nip <fd> init-fd ] dip ] }
{ [ err_no EINTR = ] [ 2drop (accept) ] }
{ [ err_no EAGAIN = ] [
2drop
] call ;
M: unix (receive) ( datagram -- packet sockaddr )
- dup do-receive dup [ rot drop ] [
+ dup do-receive dup [ [ drop ] 2dip ] [
2drop [ +input+ wait-for-port ] [ (receive) ] bi
] if ;
"Receive 1" print
- "d" get receive >r reverse r>
+ "d" get receive [ reverse ] dip
"Send 1" print
dup .
"Receive 2" print
- "d" get receive >r " world" append r>
+ "d" get receive [ " world" append ] dip
"Send 1" print
dup .
[ "olleh" t ] [
"d" get receive
datagram-server <local> =
- >r >string r>
+ [ >string ] dip
] unit-test
[ ] [
[ "hello world" t ] [
"d" get receive
datagram-server <local> =
- >r >string r>
+ [ >string ] dip
] unit-test
[ ] [ "d" get dispose ] unit-test
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien.c-types io.binary io.backend io.files io.buffers
-io.windows kernel math splitting fry alien.strings
-windows windows.kernel32 windows.time calendar combinators
-math.functions sequences namespaces make words symbols system
-io.ports destructors accessors math.bitwise continuations
-windows.errors arrays byte-arrays ;
+io.encodings.utf16n io.ports io.windows kernel math splitting
+fry alien.strings windows windows.kernel32 windows.time calendar
+combinators math.functions sequences namespaces make words
+symbols system destructors accessors math.bitwise continuations
+windows.errors arrays byte-arrays generalizations ;
IN: io.windows.files
: open-file ( path access-mode create-mode flags -- handle )
[
- >r >r share-mode default-security-attributes r> r>
+ [ share-mode default-security-attributes ] 2dip
CreateFile-flags f CreateFile opened-file
] with-destructors ;
GetLastError ERROR_ALREADY_EXISTS = not ;
: set-file-pointer ( handle length method -- )
- >r dupd d>w/w <uint> r> SetFilePointer
+ [ dupd d>w/w <uint> ] dip SetFilePointer
INVALID_SET_FILE_POINTER = [
CloseHandle "SetFilePointer failed" throw
] when drop ;
normalize-path
RemoveDirectory win32-error=0/f ;
-M: windows >directory-entry ( byte-array -- directory-entry )
- [ WIN32_FIND_DATA-cFileName utf16n alien>string ]
- [ WIN32_FIND_DATA-dwFileAttributes ]
- bi directory-entry boa ;
-
: find-first-file ( path -- WIN32_FIND_DATA handle )
"WIN32_FIND_DATA" <c-object> tuck
FindFirstFile
- [ INVALID_HANDLE_VALUE = [ win32-error ] when ] keep ;
+ [ INVALID_HANDLE_VALUE = [ win32-error-string throw ] when ] keep ;
: find-next-file ( path -- WIN32_FIND_DATA/f )
"WIN32_FIND_DATA" <c-object> tuck
: win32-file-type ( n -- symbol )
FILE_ATTRIBUTE_DIRECTORY mask? +directory+ +regular-file+ ? ;
+TUPLE: windows-directory-entry < directory-entry attributes ;
+
+M: windows >directory-entry ( byte-array -- directory-entry )
+ [ WIN32_FIND_DATA-cFileName utf16n alien>string ]
+ [ WIN32_FIND_DATA-dwFileAttributes win32-file-type ]
+ [ WIN32_FIND_DATA-dwFileAttributes win32-file-attributes ]
+ tri
+ dupd remove windows-directory-entry boa ;
+
: WIN32_FIND_DATA>file-info ( WIN32_FIND_DATA -- file-info )
[ \ windows-file-info new ] dip
{
HOOK: root-directory os ( string -- string' )
-TUPLE: winnt-file-system-info < file-system-info
-total-bytes total-free-bytes ;
-
-: file-system-type ( normalized-path -- str )
- MAX_PATH 1+ <byte-array>
- MAX_PATH 1+
- "DWORD" <c-object> "DWORD" <c-object> "DWORD" <c-object>
- MAX_PATH 1+ <byte-array>
- MAX_PATH 1+
- [ GetVolumeInformation win32-error=0/f ] 2keep drop
+: volume-information ( normalized-path -- volume-name volume-serial max-component flags type )
+ MAX_PATH 1+ [ <byte-array> ] keep
+ "DWORD" <c-object>
+ "DWORD" <c-object>
+ "DWORD" <c-object>
+ MAX_PATH 1+ [ <byte-array> ] keep
+ [ GetVolumeInformation win32-error=0/f ] 7 nkeep
+ drop 5 nrot drop
+ [ utf16n alien>string ] 4 ndip
utf16n alien>string ;
-: file-system-space ( normalized-path -- free-space total-bytes total-free-bytes )
+: file-system-space ( normalized-path -- available-space total-space free-space )
"ULARGE_INTEGER" <c-object>
"ULARGE_INTEGER" <c-object>
"ULARGE_INTEGER" <c-object>
[ GetDiskFreeSpaceEx win32-error=0/f ] 3keep ;
+: calculate-file-system-info ( file-system-info -- file-system-info' )
+ {
+ [ dup [ total-space>> ] [ free-space>> ] bi - >>used-space drop ]
+ [ ]
+ } cleave ;
+
+TUPLE: win32-file-system-info < file-system-info max-component flags device-serial ;
+
M: winnt file-system-info ( path -- file-system-info )
normalize-path root-directory
- dup [ file-system-type ] [ file-system-space ] bi
- \ winnt-file-system-info new
- swap *ulonglong >>total-free-bytes
- swap *ulonglong >>total-bytes
+ dup [ volume-information ] [ file-system-space ] bi
+ \ win32-file-system-info new
swap *ulonglong >>free-space
+ swap *ulonglong >>total-space
+ swap *ulonglong >>available-space
swap >>type
- swap >>mount-point ;
+ swap *uint >>flags
+ swap *uint >>max-component
+ swap *uint >>device-serial
+ swap >>device-name
+ swap >>mount-point
+ calculate-file-system-info ;
: volume>paths ( string -- array )
16384 "ushort" <c-array> tuck dup length
] if ;
: find-first-volume ( -- string handle )
- MAX_PATH 1+ <byte-array> dup length
+ MAX_PATH 1+ [ <byte-array> ] keep
dupd
FindFirstVolume dup win32-error=0/f
[ utf16n alien>string ] dip ;
: find-next-volume ( handle -- string/f )
- MAX_PATH 1+ <byte-array> dup length
- over [ FindNextVolume ] dip swap 0 = [
+ MAX_PATH 1+ [ <byte-array> tuck ] keep
+ FindNextVolume 0 = [
GetLastError ERROR_NO_MORE_FILES =
- [ drop f ] [ win32-error ] if
+ [ drop f ] [ win32-error-string throw ] if
] [
utf16n alien>string
] if ;
find-volumes [ volume>paths ] map
concat [
[ file-system-info ]
- [ drop winnt-file-system-info new swap >>mount-point ] recover
+ [ drop \ file-system-info new swap >>mount-point ] recover
] map ;
: file-times ( path -- timestamp timestamp timestamp )
: set-file-times ( path timestamp/f timestamp/f timestamp/f -- )
#! timestamp order: creation access write
[
- >r >r >r
+ [
normalize-path open-existing &dispose handle>>
- r> r> r> (set-file-times)
+ ] 3dip (set-file-times)
] with-destructors ;
: set-file-create-time ( path timestamp -- )
f f set-file-times ;
: set-file-access-time ( path timestamp -- )
- >r f r> f set-file-times ;
+ [ f ] dip f set-file-times ;
: set-file-write-time ( path timestamp -- )
- >r f f r> set-file-times ;
+ [ f f ] dip set-file-times ;
M: winnt touch-file ( path -- )
[
normalize-path
- maybe-create-file >r &dispose r>
+ maybe-create-file [ &dispose ] dip
[ drop ] [ handle>> f now dup (set-file-times) ] if
] with-destructors ;
-USING: kernel system io.files.unique.backend
-windows.kernel32 io.windows io.windows.files io.ports windows
-destructors environment ;
+USING: kernel system windows.kernel32 io.windows
+io.windows.files io.ports windows destructors environment
+io.files.unique ;
IN: io.windows.files.unique
-M: windows (make-unique-file) ( path -- )
+M: windows touch-unique-file ( path -- )
GENERIC_WRITE CREATE_NEW 0 open-file dispose ;
M: windows temporary-path ( -- path )
namespaces make io.launcher kernel sequences windows.errors
splitting system threads init strings combinators
io.backend accessors concurrency.flags io.files assocs
-io.files.private windows destructors ;
+io.files.private windows destructors specialized-arrays.ushort
+specialized-arrays.alien ;
IN: io.windows.launcher
TUPLE: CreateProcess-args
CreateProcess win32-error=0/f ;
: count-trailing-backslashes ( str n -- str n )
- >r "\\" ?tail r> swap [
+ [ "\\" ?tail ] dip swap [
1+ count-trailing-backslashes
] when ;
: escape-argument ( str -- newstr )
CHAR: \s over member? [
- "\"" swap fix-trailing-backslashes "\"" 3append
+ fix-trailing-backslashes "\"" dup surround
] when ;
: join-arguments ( args -- cmd-line )
: fill-lpApplicationName ( process args -- process args )
over app-name/cmd-line
- >r >>lpApplicationName
- r> >>lpCommandLine ;
+ [ >>lpApplicationName ] [ >>lpCommandLine ] bi* ;
: fill-lpCommandLine ( process args -- process args )
over cmd-line >>lpCommandLine ;
over get-environment
[ swap % "=" % % "\0" % ] assoc-each
"\0" %
- ] "" make >c-ushort-array
+ ] ushort-array{ } make underlying>>
>>lpEnvironment
] when ;
M: windows wait-for-processes ( -- ? )
processes get keys dup
- [ handle>> PROCESS_INFORMATION-hProcess ] map
- dup length swap >c-void*-array 0 0
+ [ handle>> PROCESS_INFORMATION-hProcess ] void*-array{ } map-as
+ [ length ] [ underlying>> ] bi 0 0
WaitForMultipleObjects
dup HEX: ffffffff = [ win32-error ] when
dup WAIT_TIMEOUT = [ 2drop t ] [ swap nth process-exited f ] if ;
+++ /dev/null
-USING: io io.mmap io.files kernel tools.test continuations
-sequences io.encodings.ascii accessors ;
-IN: io.windows.mmap.tests
-
-[ ] [ "a" "mmap-grow-test.txt" temp-file ascii set-file-contents ] unit-test
-[ 1 ] [ "mmap-grow-test.txt" temp-file file-info size>> ] unit-test
-[ ] [ "mmap-grow-test.txt" temp-file 100 [ [ ] change-each ] with-mapped-file ] unit-test
-[ 100 ] [ "mmap-grow-test.txt" temp-file file-info size>> ] unit-test
"OVERLAPPED" malloc-object &free ;
: make-overlapped ( port -- overlapped-ext )
- >r (make-overlapped)
- r> handle>> ptr>> [ over set-OVERLAPPED-offset ] when* ;
+ [ (make-overlapped) ] dip
+ handle>> ptr>> [ over set-OVERLAPPED-offset ] when* ;
: <completion-port> ( handle existing -- handle )
f 1 CreateIoCompletionPort dup win32-error=0/f ;
} cond
] with-timeout ;
-:: wait-for-overlapped ( ms -- bytes-transferred overlapped error? )
+:: wait-for-overlapped ( us -- bytes-transferred overlapped error? )
master-completion-port get-global
0 <int> [ ! bytes
f <void*> ! key
f <void*> [ ! overlapped
- ms INFINITE or ! timeout
+ us [ 1000 /i ] [ INFINITE ] if* ! timeout
GetQueuedCompletionStatus zero?
] keep *void*
] keep *int spin ;
: resume-callback ( result overlapped -- )
pending-overlapped get-global delete-at* drop resume-with ;
-: handle-overlapped ( timeout -- ? )
+: handle-overlapped ( us -- ? )
wait-for-overlapped [
dup [
- >r drop GetLastError 1array r> resume-callback t
- ] [
- 2drop f
- ] if
- ] [
- resume-callback t
- ] if ;
+ [ drop GetLastError 1array ] dip resume-callback t
+ ] [ 2drop f ] if
+ ] [ resume-callback t ] if ;
M: win32-handle cancel-operation
[ check-disposed ] [ handle>> CancelIo drop ] bi ;
-M: winnt io-multiplex ( ms -- )
+M: winnt io-multiplex ( us -- )
handle-overlapped [ 0 io-multiplex ] when ;
M: winnt init-io ( -- )
: wait-for-file ( FileArgs n port -- n )
swap file-error?
- [ 2drop 0 ] [ >r lpOverlapped>> r> twiddle-thumbs ] if ;
+ [ 2drop 0 ] [ [ lpOverlapped>> ] dip twiddle-thumbs ] if ;
: update-file-ptr ( n port -- )
handle>> dup ptr>> [ rot + >>ptr drop ] [ 2drop ] if* ;
USING: continuations destructors io.buffers io.files io.backend
-io.timeouts io.ports io.windows io.windows.files
-io.windows.nt.backend 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 io.files.private accessors tr ;
+io.timeouts io.ports io.files.private io.windows
+io.windows.files io.windows.nt.backend 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 ;
IN: io.windows.nt.files
M: winnt cwd
M: winnt open-append
[ dup file-info size>> ] [ drop 0 ] recover
- >r (open-append) r> >>ptr ;
+ [ (open-append) ] dip >>ptr ;
M: winnt home "USERPROFILE" os-env ;
-USING: io.launcher tools.test calendar accessors environment\r
-namespaces kernel system arrays io io.files io.encodings.ascii\r
-sequences parser assocs hashtables math continuations eval ;\r
-IN: io.windows.launcher.nt.tests\r
-\r
-[ ] [\r
- <process>\r
- "notepad" >>command\r
- 1/2 seconds >>timeout\r
- "notepad" set\r
-] unit-test\r
-\r
-[ f ] [ "notepad" get process-running? ] unit-test\r
-\r
-[ f ] [ "notepad" get process-started? ] unit-test\r
-\r
-[ ] [ "notepad" [ run-detached ] change ] unit-test\r
-\r
-[ "notepad" get wait-for-process ] must-fail\r
-\r
-[ t ] [ "notepad" get killed>> ] unit-test\r
-\r
-[ f ] [ "notepad" get process-running? ] unit-test\r
-\r
-[ ] [\r
- <process>\r
- vm "-quiet" "-run=hello-world" 3array >>command\r
- "out.txt" temp-file >>stdout\r
- try-process\r
-] unit-test\r
-\r
-[ "Hello world" ] [\r
- "out.txt" temp-file ascii file-lines first\r
-] unit-test\r
-\r
-[ ] [\r
- <process>\r
- vm "-run=listener" 2array >>command\r
- +closed+ >>stdin\r
- try-process\r
-] unit-test\r
-\r
-[ ] [\r
- "resource:basis/io/windows/nt/launcher/test" [\r
- <process>\r
- vm "-script" "stderr.factor" 3array >>command\r
- "out.txt" temp-file >>stdout\r
- "err.txt" temp-file >>stderr\r
- try-process\r
- ] with-directory\r
-] unit-test\r
-\r
-[ "output" ] [\r
- "out.txt" temp-file ascii file-lines first\r
-] unit-test\r
-\r
-[ "error" ] [\r
- "err.txt" temp-file ascii file-lines first\r
-] unit-test\r
-\r
-[ ] [\r
- "resource:basis/io/windows/nt/launcher/test" [\r
- <process>\r
- vm "-script" "stderr.factor" 3array >>command\r
- "out.txt" temp-file >>stdout\r
- +stdout+ >>stderr\r
- try-process\r
- ] with-directory\r
-] unit-test\r
-\r
-[ "outputerror" ] [\r
- "out.txt" temp-file ascii file-lines first\r
-] unit-test\r
-\r
-[ "output" ] [\r
- "resource:basis/io/windows/nt/launcher/test" [\r
- <process>\r
- vm "-script" "stderr.factor" 3array >>command\r
- "err2.txt" temp-file >>stderr\r
- ascii <process-reader> lines first\r
- ] with-directory\r
-] unit-test\r
-\r
-[ "error" ] [\r
- "err2.txt" temp-file ascii file-lines first\r
-] unit-test\r
-\r
-[ t ] [\r
- "resource:basis/io/windows/nt/launcher/test" [\r
- <process>\r
- vm "-script" "env.factor" 3array >>command\r
- ascii <process-reader> contents\r
- ] with-directory eval\r
-\r
- os-envs =\r
-] unit-test\r
-\r
-[ t ] [\r
- "resource:basis/io/windows/nt/launcher/test" [\r
- <process>\r
- vm "-script" "env.factor" 3array >>command\r
- +replace-environment+ >>environment-mode\r
- os-envs >>environment\r
- ascii <process-reader> contents\r
- ] with-directory eval\r
- \r
- os-envs =\r
-] unit-test\r
-\r
-[ "B" ] [\r
- "resource:basis/io/windows/nt/launcher/test" [\r
- <process>\r
- vm "-script" "env.factor" 3array >>command\r
- { { "A" "B" } } >>environment\r
- ascii <process-reader> contents\r
- ] with-directory eval\r
-\r
- "A" swap at\r
-] unit-test\r
-\r
-[ f ] [\r
- "resource:basis/io/windows/nt/launcher/test" [\r
- <process>\r
- vm "-script" "env.factor" 3array >>command\r
- { { "HOME" "XXX" } } >>environment\r
- +prepend-environment+ >>environment-mode\r
- ascii <process-reader> contents\r
- ] with-directory eval\r
-\r
- "HOME" swap at "XXX" =\r
-] unit-test\r
-\r
-2 [\r
- [ ] [\r
- <process>\r
- "cmd.exe /c dir" >>command\r
- "dir.txt" temp-file >>stdout\r
- try-process\r
- ] unit-test\r
-\r
- [ ] [ "dir.txt" temp-file delete-file ] unit-test\r
-] times\r
-\r
-[ "append-test" temp-file delete-file ] ignore-errors\r
-\r
-[ "Hello appender\r\nHello appender\r\n" ] [\r
- 2 [\r
- "resource:basis/io/windows/nt/launcher/test" [\r
- <process>\r
- vm "-script" "append.factor" 3array >>command\r
- "append-test" temp-file <appender> >>stdout\r
- try-process\r
- ] with-directory\r
- ] times\r
- \r
- "append-test" temp-file ascii file-contents\r
-] unit-test\r
+USING: io.launcher tools.test calendar accessors environment
+namespaces kernel system arrays io io.files io.encodings.ascii
+sequences parser assocs hashtables math continuations eval ;
+IN: io.windows.launcher.nt.tests
+
+[ ] [
+ <process>
+ "notepad" >>command
+ 1/2 seconds >>timeout
+ "notepad" set
+] unit-test
+
+[ f ] [ "notepad" get process-running? ] unit-test
+
+[ f ] [ "notepad" get process-started? ] unit-test
+
+[ ] [ "notepad" [ run-detached ] change ] unit-test
+
+[ "notepad" get wait-for-process ] must-fail
+
+[ t ] [ "notepad" get killed>> ] unit-test
+
+[ f ] [ "notepad" get process-running? ] unit-test
+
+[ ] [
+ <process>
+ vm "-quiet" "-run=hello-world" 3array >>command
+ "out.txt" temp-file >>stdout
+ try-process
+] unit-test
+
+[ "Hello world" ] [
+ "out.txt" temp-file ascii file-lines first
+] unit-test
+
+[ ] [
+ <process>
+ vm "-run=listener" 2array >>command
+ +closed+ >>stdin
+ try-process
+] unit-test
+
+[ ] [
+ "resource:basis/io/windows/nt/launcher/test" [
+ <process>
+ vm "-script" "stderr.factor" 3array >>command
+ "out.txt" temp-file >>stdout
+ "err.txt" temp-file >>stderr
+ try-process
+ ] with-directory
+] unit-test
+
+[ "output" ] [
+ "out.txt" temp-file ascii file-lines first
+] unit-test
+
+[ "error" ] [
+ "err.txt" temp-file ascii file-lines first
+] unit-test
+
+[ ] [
+ "resource:basis/io/windows/nt/launcher/test" [
+ <process>
+ vm "-script" "stderr.factor" 3array >>command
+ "out.txt" temp-file >>stdout
+ +stdout+ >>stderr
+ try-process
+ ] with-directory
+] unit-test
+
+[ "outputerror" ] [
+ "out.txt" temp-file ascii file-lines first
+] unit-test
+
+[ "output" ] [
+ "resource:basis/io/windows/nt/launcher/test" [
+ <process>
+ vm "-script" "stderr.factor" 3array >>command
+ "err2.txt" temp-file >>stderr
+ ascii <process-reader> lines first
+ ] with-directory
+] unit-test
+
+[ "error" ] [
+ "err2.txt" temp-file ascii file-lines first
+] unit-test
+
+[ t ] [
+ "resource:basis/io/windows/nt/launcher/test" [
+ <process>
+ vm "-script" "env.factor" 3array >>command
+ ascii <process-reader> contents
+ ] with-directory eval
+
+ os-envs =
+] unit-test
+
+[ t ] [
+ "resource:basis/io/windows/nt/launcher/test" [
+ <process>
+ vm "-script" "env.factor" 3array >>command
+ +replace-environment+ >>environment-mode
+ os-envs >>environment
+ ascii <process-reader> contents
+ ] with-directory eval
+
+ os-envs =
+] unit-test
+
+[ "B" ] [
+ "resource:basis/io/windows/nt/launcher/test" [
+ <process>
+ vm "-script" "env.factor" 3array >>command
+ { { "A" "B" } } >>environment
+ ascii <process-reader> contents
+ ] with-directory eval
+
+ "A" swap at
+] unit-test
+
+[ f ] [
+ "resource:basis/io/windows/nt/launcher/test" [
+ <process>
+ vm "-script" "env.factor" 3array >>command
+ { { "USERPROFILE" "XXX" } } >>environment
+ +prepend-environment+ >>environment-mode
+ ascii <process-reader> contents
+ ] with-directory eval
+
+ "USERPROFILE" swap at "XXX" =
+] unit-test
+
+2 [
+ [ ] [
+ <process>
+ "cmd.exe /c dir" >>command
+ "dir.txt" temp-file >>stdout
+ try-process
+ ] unit-test
+
+ [ ] [ "dir.txt" temp-file delete-file ] unit-test
+] times
+
+[ "append-test" temp-file delete-file ] ignore-errors
+
+[ "Hello appender\r\nHello appender\r\n" ] [
+ 2 [
+ "resource:basis/io/windows/nt/launcher/test" [
+ <process>
+ vm "-script" "append.factor" 3array >>command
+ "append-test" temp-file <appender> >>stdout
+ try-process
+ ] with-directory
+ ] times
+
+ "append-test" temp-file ascii file-contents
+] unit-test
CreateFile dup invalid-handle? <win32-file> &dispose handle>> ;
: redirect-append ( path access-mode create-mode -- handle )
- >r >r path>> r> r>
+ [ path>> ] 2dip
drop OPEN_ALWAYS
redirect-file
dup 0 FILE_END set-file-pointer ;
2drop handle>> duplicate-handle ;
: redirect-stream ( stream access-mode create-mode -- handle )
- >r >r underlying-handle handle>> r> r> redirect-handle ;
+ [ underlying-handle handle>> ] 2dip redirect-handle ;
: redirect ( obj access-mode create-mode -- handle )
{
! Copyright (C) 2008 Doug Coleman, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien alien.c-types libc destructors locals kernel math
-assocs namespaces make continuations sequences hashtables
-sorting arrays combinators math.bitwise strings system accessors
-threads splitting io.backend io.windows io.windows.nt.backend
-io.windows.nt.files io.monitors io.ports io.buffers io.files
-io.timeouts io windows windows.kernel32 windows.types ;
+USING: alien alien.c-types alien.strings libc destructors locals
+kernel math assocs namespaces make continuations sequences
+hashtables sorting arrays combinators math.bitwise strings
+system accessors threads splitting io.backend io.windows
+io.windows.nt.backend io.windows.nt.files io.monitors io.ports
+io.buffers io.files io.timeouts io.encodings.string
+io.encodings.utf16n io windows windows.kernel32 windows.types ;
IN: io.windows.nt.monitors
: open-directory ( path -- handle )
} case 1array ;
: memory>u16-string ( alien len -- string )
- [ memory>byte-array ] keep 2/ c-ushort-array> >string ;
+ memory>byte-array utf16n decode ;
: parse-notify-record ( buffer -- path changed )
[
"-" %
32 random-bits #
"-" %
- millis #
+ micros #
] "" make ;
M: winnt (pipe) ( -- pipe )
\r
: with-process-token ( quot -- )\r
#! quot: ( token-handle -- token-handle )\r
- >r open-process-token r>\r
+ [ open-process-token ] dip\r
[ keep ] curry\r
[ CloseHandle drop ] [ ] cleanup ; inline\r
\r
: lookup-privilege ( string -- luid )\r
- >r f r> "LUID" <c-object>\r
+ [ f ] dip "LUID" <c-object>\r
[ LookupPrivilegeValue win32-error=0/f ] keep ;\r
\r
: make-token-privileges ( name ? -- obj )\r
set-LUID_AND_ATTRIBUTES-Attributes\r
] when\r
\r
- >r lookup-privilege r>\r
+ [ lookup-privilege ] dip\r
[\r
TOKEN_PRIVILEGES-Privileges\r
- >r 0 r> LUID_AND_ATTRIBUTES-nth\r
set-LUID_AND_ATTRIBUTES-Luid\r
] keep ;\r
\r
: make-send-buffer ( packet -- WSABUF )
"WSABUF" malloc-object &free
- [ >r malloc-byte-array &free r> set-WSABUF-buf ]
- [ >r length r> set-WSABUF-len ]
+ [ [ malloc-byte-array &free ] dip set-WSABUF-buf ]
+ [ [ length ] dip set-WSABUF-len ]
[ nip ]
2tri ; inline
swap >>port
dup port>> handle>> handle>> >>s
swap make-sockaddr/size
- >r malloc-byte-array &free
- r> [ >>lpTo ] [ >>iToLen ] bi*
+ [ malloc-byte-array &free ] dip
+ [ >>lpTo ] [ >>iToLen ] bi*
swap make-send-buffer >>lpBuffers
1 >>dwBufferCount
0 >>dwFlags
<win32-socket> |dispose dup add-completion ;\r
\r
: open-socket ( addrspec type -- win32-socket )\r
- >r protocol-family r>\r
+ [ protocol-family ] dip\r
0 f 0 WSASocket-flags WSASocket\r
dup socket-error\r
opened-socket ;\r
\r
M: object (get-local-address) ( socket addrspec -- sockaddr )\r
- >r handle>> r> empty-sockaddr/size <int>\r
+ [ handle>> ] dip empty-sockaddr/size <int>\r
[ getsockname socket-error ] 2keep drop ;\r
\r
M: object (get-remote-address) ( socket addrspec -- sockaddr )\r
- >r handle>> r> empty-sockaddr/size <int>\r
+ [ handle>> ] dip empty-sockaddr/size <int>\r
[ getpeername socket-error ] 2keep drop ;\r
\r
: bind-socket ( win32-socket sockaddr len -- )\r
- >r >r handle>> r> r> bind socket-error ;\r
+ [ handle>> ] 2dip bind socket-error ;\r
\r
M: object ((client)) ( addrspec -- handle )\r
[ SOCK_STREAM open-socket ] keep\r
! Copyright (C) 2004, 2008 Mackenzie Straight, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types arrays destructors io io.backend
-io.buffers io.files io.ports io.sockets io.binary
-io.sockets io.timeouts windows.errors strings
-kernel math namespaces sequences windows windows.kernel32
-windows.shell32 windows.types windows.winsock splitting
-continuations math.bitwise system accessors ;
+io.buffers io.files io.ports io.binary io.timeouts
+windows.errors strings kernel math namespaces sequences windows
+windows.kernel32 windows.shell32 windows.types windows.winsock
+splitting continuations math.bitwise system accessors ;
IN: io.windows
: set-inherit ( handle ? -- )
- >r HANDLE_FLAG_INHERIT r> >BOOLEAN SetHandleInformation win32-error=0/f ;
+ [ HANDLE_FLAG_INHERIT ] dip
+ >BOOLEAN SetHandleInformation win32-error=0/f ;
TUPLE: win32-handle handle disposed ;
{ $values { "alien" c-ptr } }
{ $description "Deallocates a block of memory allocated by " { $link malloc } ", " { $link calloc } " or " { $link realloc } "." } ;
-HELP: with-malloc
-{ $values { "size" "a positive integer" } { "quot" { $quotation "( c-ptr -- )" } } }
-{ $description "Allocates a zeroed block of " { $snippet "n" } " bytes and passes it to the quotation. When the quotation returns, the block is freed." } ;
-
HELP: &free
{ $values { "alien" c-ptr } }
{ $description "Marks the block of memory for unconditional deallocation at the end of the current " { $link with-destructors } " scope." } ;
: memcpy ( dst src size -- )
"void" "libc" "memcpy" { "void*" "void*" "ulong" } alien-invoke ;
-: with-malloc ( size quot -- )
- swap 1 calloc [ swap keep ] [ free ] [ ] cleanup ; inline
-
: strlen ( alien -- len )
"size_t" "libc" "strlen" { "char*" } alien-invoke ;
[ 2dup assoc>> key? [ 2dup delete-at ] when add-to-dlist ] 2keep
assoc>> set-at ;
-: dlist>seq ( dlist -- seq )
- [ ] pusher [ dlist-each ] dip ;
-
M: linked-assoc >alist
dlist>> dlist>seq ;
USING: help.markup help.syntax kernel io system prettyprint ;
IN: listener
+ARTICLE: "listener-watch" "Watching variables in the listener"
+"The listener prints the concepts of the data and retain stacks after every expression. It can also print values of dynamic variables which are added to a watch list:"
+{ $subsection visible-vars }
+"To add or remove a single variable:"
+{ $subsection show-var }
+{ $subsection hide-var }
+"To add and remove multiple variables:"
+{ $subsection show-vars }
+{ $subsection hide-vars }
+"Hiding all visible variables:"
+{ $subsection hide-all-vars } ;
+
+HELP: show-var
+{ $values { "var" "a variable name" } }
+{ $description "Adds a variable to the watch list; its value will be printed by the listener after every expression." } ;
+
+HELP: show-vars
+{ $values { "seq" "a sequence of variable names" } }
+{ $description "Adds a sequence of variables to the watch list; their values will be printed by the listener after every expression." } ;
+
+HELP: hide-var
+{ $values { "var" "a variable name" } }
+{ $description "Removes a variable from the watch list." } ;
+
+HELP: hide-vars
+{ $values { "seq" "a sequence of variable names" } }
+{ $description "Removes a sequence of variables from the watch list." } ;
+
+HELP: hide-all-vars
+{ $description "Removes all variables from the watch list." } ;
+
ARTICLE: "listener" "The listener"
"The listener evaluates Factor expressions read from a stream. The listener is the primary interface to the Factor runtime. Typically, you write Factor code in a text editor, then load it using the listener and test it."
$nl
"The classical first program can be run in the listener:"
{ $example "\"Hello, world\" print" "Hello, world" }
-"Multi-line phrases are supported:"
+"Multi-line expressions are supported:"
{ $example "{ 1 2 3 } [\n .\n] each" "1\n2\n3" }
"The listener knows when to expect more input by looking at the height of the stack. Parsing words such as " { $link POSTPONE: { } " leave elements on the parser stack, and corresponding words such as " { $link POSTPONE: } } " pop them."
-$nl
-"A very common operation is to inspect the contents of the data stack in the listener:"
-{ $subsection .s }
-"Note that calls to " { $link .s } " can also be included inside words as a debugging aid, however a more convenient way to achieve this is to use the annotation facility. See " { $link "tools.annotations" } "."
-$nl
+{ $subsection "listener-watch" }
"You can start a nested listener or exit a listener using the following words:"
{ $subsection listener }
{ $subsection bye }
-"The following variables can be rebound inside a nested scope to customize the behavior of a listener; this can be done to create a development tool with a custom interaction loop:"
-{ $subsection listener-hook }
"Finally, the multi-line expression reading word can be used independently of the rest of the listener:"
{ $subsection read-quot } ;
ABOUT: "listener"
+<PRIVATE
+
HELP: quit-flag
{ $var-description "Variable set to true by " { $link bye } " word; it forces the next iteration of the " { $link listener } " loop to end." } ;
-HELP: listener-hook
-{ $var-description "Variable holding a quotation called by the listener before reading an input expression. The UI sets this variable to a quotation which updates the stack display in a listener gadget." } ;
+PRIVATE>
HELP: read-quot
{ $values { "quot/f" "a parsed quotation, or " { $link f } " indicating end of file" } }
USING: arrays hashtables io kernel math math.parser memory
namespaces parser lexer sequences strings io.styles
vectors words generic system combinators continuations debugger
-definitions compiler.units accessors colors ;
-
+definitions compiler.units accessors colors prettyprint fry
+sets ;
IN: listener
-SYMBOL: quit-flag
-
-SYMBOL: listener-hook
-
-[ ] listener-hook set-global
-
GENERIC: stream-read-quot ( stream -- quot/f )
: parse-lines-interactive ( lines -- quot/f )
: read-quot ( -- quot/f ) input-stream get stream-read-quot ;
+<PRIVATE
+
+SYMBOL: quit-flag
+
+PRIVATE>
+
: bye ( -- ) quit-flag on ;
-: prompt. ( -- )
- "( " in get " )" 3append
- H{ { background T{ rgba f 1 0.7 0.7 1 } } } format bl flush ;
+SYMBOL: visible-vars
+
+: show-var ( var -- ) visible-vars [ swap suffix ] change ;
+
+: show-vars ( seq -- ) visible-vars [ swap union ] change ;
+
+: hide-var ( var -- ) visible-vars [ remove ] change ;
+
+: hide-vars ( seq -- ) visible-vars [ swap diff ] change ;
+
+: hide-all-vars ( -- ) visible-vars off ;
SYMBOL: error-hook
[ print-error-and-restarts ] error-hook set-global
+<PRIVATE
+
+: title. ( string -- )
+ H{ { foreground T{ rgba f 0.3 0.3 0.3 1 } } } format nl ;
+
+: visible-vars. ( -- )
+ visible-vars get [
+ nl "--- Watched variables:" title.
+ standard-table-style [
+ [
+ [
+ [ [ short. ] with-cell ]
+ [ [ get short. ] with-cell ]
+ bi
+ ] with-row
+ ] each
+ ] tabular-output
+ ] unless-empty ;
+
+SYMBOL: display-stacks?
+
+t display-stacks? set-global
+
+: stacks. ( -- )
+ display-stacks? get [
+ datastack [ nl "--- Data stack:" title. stack. ] unless-empty
+ ] when ;
+
+: prompt. ( -- )
+ "( " in get auto-use? get [ " - auto" append ] when " )" 3append
+ H{ { background T{ rgba f 1 0.7 0.7 1 } } } format bl flush ;
+
: listen ( -- )
- listener-hook get call prompt.
+ visible-vars. stacks. prompt.
[ read-quot [ [ error-hook get call ] recover ] [ bye ] if* ]
[
dup lexer-error? [
: until-quit ( -- )
quit-flag get [ quit-flag off ] [ listen until-quit ] if ;
+PRIVATE>
+
: listener ( -- )
[ until-quit ] with-interactive-vocabs ;
IN: locals.backend.tests
USING: tools.test locals.backend kernel arrays ;
-[ 3 ] [ 3 >r 1 get-local r> drop ] unit-test
-
-[ 4 ] [ 3 4 >r >r 2 get-local 2 drop-locals ] unit-test
-
-: get-local-test-1 ( -- x ) 3 >r 1 get-local r> drop ;
+: get-local-test-1 ( -- x ) 3 1 load-locals 0 get-local 1 drop-locals ;
\ get-local-test-1 must-infer
[ 3 ] [ get-local-test-1 ] unit-test
-: get-local-test-2 ( -- x ) 3 4 >r >r 2 get-local 2 drop-locals ;
+: get-local-test-2 ( -- x ) 3 4 2 load-locals -1 get-local 2 drop-locals ;
\ get-local-test-2 must-infer
-[ 4 ] [ get-local-test-2 ] unit-test
-
-: get-local-test-3 ( -- a b ) 3 4 >r >r 2 get-local r> r> 2array ;
-
-\ get-local-test-3 must-infer
-
-[ 4 { 3 4 } ] [ get-local-test-3 ] unit-test
-
-: get-local-test-4 ( -- a b )
- 3 4 >r >r r> r> dup swap >r swap >r r> r> 2array ;
-
-\ get-local-test-4 must-infer
-
-[ 4 { 3 4 } ] [ get-local-test-4 ] unit-test
-
-[ 1 2 ] [ 1 2 2 load-locals r> r> ] unit-test
-
-: load-locals-test-1 ( -- a b ) 1 2 2 load-locals r> r> ;
-
-\ load-locals-test-1 must-infer
-
-[ 1 2 ] [ load-locals-test-1 ] unit-test
+[ 3 ] [ get-local-test-2 ] unit-test
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: math.private kernel slots.private sequences effects words ;
+USING: slots.private ;
IN: locals.backend
-: load-locals ( n -- )
- dup 0 eq? [ drop ] [ swap >r 1 fixnum-fast load-locals ] if ;
-
: local-value 2 slot ; inline
: set-local-value 2 set-slot ; inline
--- /dev/null
+! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors definitions effects generic kernel locals
+macros memoize prettyprint prettyprint.backend words ;
+IN: locals.definitions
+
+PREDICATE: lambda-word < word "lambda" word-prop >boolean ;
+
+M: lambda-word definer drop \ :: \ ; ;
+
+M: lambda-word definition
+ "lambda" word-prop body>> ;
+
+M: lambda-word reset-word
+ [ call-next-method ] [ f "lambda" set-word-prop ] bi ;
+
+INTERSECTION: lambda-macro macro lambda-word ;
+
+M: lambda-macro definer drop \ MACRO:: \ ; ;
+
+M: lambda-macro definition
+ "lambda" word-prop body>> ;
+
+M: lambda-macro reset-word
+ [ call-next-method ] [ f "lambda" set-word-prop ] bi ;
+
+INTERSECTION: lambda-method method-body lambda-word ;
+
+M: lambda-method definer drop \ M:: \ ; ;
+
+M: lambda-method definition
+ "lambda" word-prop body>> ;
+
+M: lambda-method reset-word
+ [ call-next-method ] [ f "lambda" set-word-prop ] bi ;
+
+INTERSECTION: lambda-memoized memoized lambda-word ;
+
+M: lambda-memoized definer drop \ MEMO:: \ ; ;
+
+M: lambda-memoized definition
+ "lambda" word-prop body>> ;
+
+M: lambda-memoized reset-word
+ [ call-next-method ] [ f "lambda" set-word-prop ] bi ;
+
+: method-stack-effect ( method -- effect )
+ dup "lambda" word-prop vars>>
+ swap "method-generic" word-prop stack-effect
+ dup [ out>> ] when
+ <effect> ;
+
+M: lambda-method synopsis*
+ dup dup dup definer.
+ "method-class" word-prop pprint-word
+ "method-generic" word-prop pprint-word
+ method-stack-effect effect>string comment. ;
--- /dev/null
+! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel summary ;
+IN: locals.errors
+
+ERROR: >r/r>-in-lambda-error ;
+
+M: >r/r>-in-lambda-error summary
+ drop
+ "Explicit retain stack manipulation is not permitted in lambda bodies" ;
+
+ERROR: binding-form-in-literal-error ;
+
+M: binding-form-in-literal-error summary
+ drop "[let, [let* and [wlet not permitted inside literals" ;
+
+ERROR: local-writer-in-literal-error ;
+
+M: local-writer-in-literal-error summary
+ drop "Local writer words not permitted inside literals" ;
+
+ERROR: local-word-in-literal-error ;
+
+M: local-word-in-literal-error summary
+ drop "Local words not permitted inside literals" ;
+
+ERROR: :>-outside-lambda-error ;
+
+M: :>-outside-lambda-error summary
+ drop ":> cannot be used outside of lambda expressions" ;
+
+ERROR: bad-lambda-rewrite output ;
+
+M: bad-lambda-rewrite summary
+ drop "You have found a bug in locals. Please report." ;
+
+ERROR: bad-local args obj ;
+
+M: bad-local summary
+ drop "You have bound a bug in locals. Please report." ;
--- /dev/null
+! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors fry fry.private generalizations kernel
+locals.types make sequences ;
+IN: locals.fry
+
+! Support for mixing locals with fry
+
+M: binding-form count-inputs body>> count-inputs ;
+
+M: lambda count-inputs body>> count-inputs ;
+
+M: lambda deep-fry
+ clone [ shallow-fry swap ] change-body
+ [ [ vars>> length ] keep '[ _ _ mnswap @ ] , ] [ drop [ncurry] % ] 2bi ;
+
+M: binding-form deep-fry
+ clone [ fry '[ @ call ] ] change-body , ;
USING: help.syntax help.markup kernel macros prettyprint
-memoize combinators arrays ;
+memoize combinators arrays generalizations ;
IN: locals
HELP: [|
}
} ;
+HELP: :>
+{ $syntax ":> binding" }
+{ $description "Introduces a new binding, lexically scoped to the enclosing quotation or definition." }
+{ $notes
+ "This word can only be used inside a lambda word, lambda quotation or let binding form."
+ $nl
+ "Lambda and let forms are really just syntax sugar for " { $link POSTPONE: :> } "."
+ $nl
+ "Lambdas desugar as follows:"
+ { $code
+ "[| a b | a b + b / ]"
+ "[ :> b :> a a b + b / ]"
+ }
+ "Let forms desugar as follows:"
+ { $code
+ "[|let | x [ 10 random ] | { x x } ]"
+ "10 random :> x { x x }"
+ }
+}
+{ $examples
+ { $code
+ "USING: locals math kernel ;"
+ "IN: scratchpad"
+ ":: quadratic ( a b c -- x y )"
+ " b sq 4 a c * * - sqrt :> disc"
+ " b neg disc [ + ] [ - ] 2bi [ 2 a * / ] bi@ ;"
+ }
+} ;
+
HELP: ::
{ $syntax ":: word ( bindings... -- outputs... ) body... ;" }
{ $description "Defines a word with named inputs; it reads stack values into bindings from left to right, then executes the body with those bindings in lexical scope." }
$nl
"Unlike some languages such as Python and Java, writing to mutable locals in outer scopes is fully supported and has the expected semantics." ;
+ARTICLE: "locals-fry" "Locals and fry"
+"Locals integrate with " { $link "fry" } " so that mixing locals with fried quotations gives intuitive results."
+$nl
+"Recall that the following two code snippets are equivalent:"
+{ $code "'[ sq _ + ]" }
+{ $code "[ [ sq ] dip + ] curry" }
+"The semantics of " { $link dip } " and " { $link curry } " are such that the first example behaves as if the top of the stack as ``inserted'' in the ``hole'' in the quotation's second element."
+$nl
+"Conceptually, " { $link curry } " is defined so that the following two code snippets are equivalent:"
+{ $code "3 [ - ] curry" }
+{ $code "[ 3 - ]" }
+"With lambdas, " { $link curry } " behaves differently. Rather than prepending an element, it fills in named parameters from right to left. The following two snippets are equivalent:"
+{ $code "3 [| a b | a b - ] curry" }
+{ $code "[| a | a 3 - ]" }
+"Because of this, the behavior of fry changes when applied to a lambda, to ensure that conceptually, fry behaves as with quotations. So the following snippets are no longer equivalent:"
+{ $code "'[ [| a | _ a - ] ]" }
+{ $code "'[ [| a | a - ] curry ] call" }
+"Instead, the first line above expands into something like the following:"
+{ $code "[ [ swap [| a | a - ] ] curry call ]" }
+"This ensures that the fried value appears ``underneath'' the local variable " { $snippet "a" } " when the quotation calls."
+$nl
+"The precise behavior is the following. When frying a lambda, a stack shuffle (" { $link mnswap } ") is prepended to the lambda so that the " { $snippet "m" } " curried values, which start off at the top of the stack, are transposed with the " { $snippet "n" } " inputs to the lambda." ;
+
ARTICLE: "locals-limitations" "Limitations of locals"
-"The first limitation is that the " { $link >r } " and " { $link r> } " words may not be used together with locals. Instead, use the " { $link dip } " combinator."
+"There are two main limitations of the current locals implementation, and both concern macros."
+{ $heading "Macro expansions with free variables" }
+"The expansion of a macro cannot reference local variables bound in the outer scope. For example, the following macro is invalid:"
+{ $code "MACRO:: twice ( quot -- ) [ quot call quot call ] ;" }
+"The following is fine, though:"
+{ $code "MACRO:: twice ( quot -- ) quot quot '[ @ @ ] ;" }
+{ $heading "Static stack effect inference and macros" }
+"Recall that a macro will only expand at compile-time, and the word containing it will only get a static stack effect, if all inputs to the macro are literal. When locals are used, there is an additional restriction; the literals must immediately precede the macro call, lexically."
$nl
-"Another limitation concerns combinators implemented as macros. Locals can only be used with such combinators if the input array immediately precedes the combinator call. For example, the following will work:"
+"For example, all of the following three examples are equivalent semantically, but only the first will have a static stack effect and compile with the optimizing compiler:"
{ $code
":: good-cond-usage ( a -- ... )"
" {"
" { [ a 0 = ] [ ... ] }"
" } cond ;"
}
-"But not the following:"
+"The following two will not, and will run slower as a result:"
{ $code
": my-cond ( alist -- ) cond ; inline"
""
" { [ a 0 = ] [ ... ] }"
" } my-cond ;"
}
+{ $code
+ ":: bad-cond-usage ( a -- ... )"
+ " {"
+ " { [ a 0 < ] [ ... ] }"
+ " { [ a 0 > ] [ ... ] }"
+ " { [ a 0 = ] [ ... ] }"
+ " } swap swap cond ;"
+}
"The reason is that locals are rewritten into stack code at parse time, whereas macro expansion is performed later during compile time. To circumvent this problem, the " { $vocab-link "macros.expander" } " vocabulary is used to rewrite simple macro usages prior to local transformation, however "{ $vocab-link "macros.expander" } " does not deal with more complicated cases where the literal inputs to the macro do not immediately precede the macro call in the source." ;
ARTICLE: "locals" "Local variables and lexical closures"
{ $subsection POSTPONE: [wlet }
"Lambda abstractions:"
{ $subsection POSTPONE: [| }
+"Lightweight binding form:"
+{ $subsection POSTPONE: :> }
"Additional topics:"
{ $subsection "locals-literals" }
{ $subsection "locals-mutable" }
+{ $subsection "locals-fry" }
{ $subsection "locals-limitations" }
"Locals complement dynamically scoped variables implemented in the " { $vocab-link "namespaces" } " vocabulary." ;
namespaces arrays strings prettyprint io.streams.string parser
accessors generic eval combinators combinators.short-circuit
combinators.short-circuit.smart math.order math.functions
-definitions compiler.units ;
+definitions compiler.units fry lexer ;
IN: locals.tests
:: foo ( a b -- a a ) a a ;
{ [ a b > ] [ 5 ] }
} cond ;
+\ cond-test must-infer
+
[ 3 ] [ 1 2 cond-test ] unit-test
[ 4 ] [ 2 2 cond-test ] unit-test
[ 5 ] [ 3 2 cond-test ] unit-test
:: 0&&-test ( a -- ? )
{ [ a integer? ] [ a even? ] [ a 10 > ] } 0&& ;
+\ 0&&-test must-infer
+
[ f ] [ 1.5 0&&-test ] unit-test
[ f ] [ 3 0&&-test ] unit-test
[ f ] [ 8 0&&-test ] unit-test
:: &&-test ( a -- ? )
{ [ a integer? ] [ a even? ] [ a 10 > ] } && ;
+\ &&-test must-infer
+
[ f ] [ 1.5 &&-test ] unit-test
[ f ] [ 3 &&-test ] unit-test
[ f ] [ 8 &&-test ] unit-test
{ 3 1 } [| from to seq | T{ slice f from to seq } ] must-infer-as
+ERROR: punned-class x ;
+
+[ T{ punned-class f 3 } ] [ 3 [| a | T{ punned-class f a } ] call ] unit-test
:: literal-identity-test ( -- a b )
{ } V{ } ;
swapd [ eq? ] [ eq? ] 2bi*
] unit-test
+:: mutable-local-in-literal-test ( a! -- b ) a 1 + a! { a } ;
+
+[ { 4 } ] [ 3 mutable-local-in-literal-test ] unit-test
+
:: compare-case ( obj1 obj2 lt-quot eq-quot gt-quot -- )
obj1 obj2 <=> {
{ +lt+ [ lt-quot call ] }
[ ] [ [ { integer lambda-method-forget-test } forget ] with-compilation-unit ] unit-test
-! :: wlet-&&-test ( a -- ? )
-! [wlet | is-integer? [ a integer? ]
-! is-even? [ a even? ]
-! >10? [ a 10 > ] |
-! { [ is-integer? ] [ is-even? ] [ >10? ] } &&
-! ] ;
-
-! [ f ] [ 1.5 wlet-&&-test ] unit-test
-! [ f ] [ 3 wlet-&&-test ] unit-test
-! [ f ] [ 8 wlet-&&-test ] unit-test
-! [ t ] [ 12 wlet-&&-test ] unit-test
\ No newline at end of file
+[ 10 ] [ 10 [| A | { [ A ] } ] call first call ] unit-test
+
+[
+ "USING: locals fry math ; [ 0 '[ [let | A [ 10 ] | A _ + ] ] ]" eval
+] [ error>> >r/r>-in-fry-error? ] must-fail-with
+
+:: (funny-macro-test) ( obj quot -- ? ) obj { quot } 1&& ; inline
+: funny-macro-test ( n -- ? ) [ odd? ] (funny-macro-test) ;
+
+\ funny-macro-test must-infer
+
+[ t ] [ 3 funny-macro-test ] unit-test
+[ f ] [ 2 funny-macro-test ] unit-test
+
+! Some odd parser corner cases
+[ "USE: locals [let" eval ] [ error>> unexpected-eof? ] must-fail-with
+[ "USE: locals [let |" eval ] [ error>> unexpected-eof? ] must-fail-with
+[ "USE: locals [let | a" eval ] [ error>> unexpected-eof? ] must-fail-with
+[ "USE: locals [|" eval ] [ error>> unexpected-eof? ] must-fail-with
+
+[ 25 ] [ 5 [| a | { [ a sq ] } cond ] call ] unit-test
+[ 25 ] [ 5 [| | { [| a | a sq ] } ] call first call ] unit-test
+
+:: FAILdog-1 ( -- b ) { [| c | c ] } ;
+
+\ FAILdog-1 must-infer
+
+:: FAILdog-2 ( a -- b ) a { [| c | c ] } cond ;
+
+\ FAILdog-2 must-infer
+
+[ 3 ] [ 3 [| a | \ a ] call ] unit-test
+
+[ "USE: locals [| | { [let | a [ 0 ] | a ] } ]" eval ] must-fail
+
+[ "USE: locals [| | { [wlet | a [ 0 ] | a ] } ]" eval ] must-fail
+
+[ "USE: locals [| | { [let* | a [ 0 ] | a ] } ]" eval ] must-fail
+
+[ "USE: locals [| | [let | a! [ 0 ] | { a! } ] ]" eval ] must-fail
+
+[ "USE: locals [| | [wlet | a [ 0 ] | { a } ] ]" eval ] must-fail
+
+[ "USE: locals [| | { :> a } ]" eval ] must-fail
+
+[ "USE: locals 3 :> a" eval ] must-fail
+
+[ 3 ] [ 3 [| | :> a a ] call ] unit-test
+
+[ 3 ] [ 3 [| | :> a! a ] call ] unit-test
+
+[ 3 ] [ 2 [| | :> a! a 1+ a! a ] call ] unit-test
+
+:: wlet-&&-test ( a -- ? )
+ [wlet | is-integer? [ a integer? ]
+ is-even? [ a even? ]
+ >10? [ a 10 > ] |
+ { [ is-integer? ] [ is-even? ] [ >10? ] } &&
+ ] ;
+
+\ wlet-&&-test must-infer
+[ f ] [ 1.5 wlet-&&-test ] unit-test
+[ f ] [ 3 wlet-&&-test ] unit-test
+[ f ] [ 8 wlet-&&-test ] unit-test
+[ t ] [ 12 wlet-&&-test ] unit-test
+
+: fry-locals-test-1 ( -- n )
+ [let | | 6 '[ [let | A [ 4 ] | A _ + ] ] call ] ;
+
+\ fry-locals-test-1 must-infer
+[ 10 ] [ fry-locals-test-1 ] unit-test
+
+:: fry-locals-test-2 ( -- n )
+ [let | | 6 '[ [let | A [ 4 ] | A _ + ] ] call ] ;
+
+\ fry-locals-test-2 must-infer
+[ 10 ] [ fry-locals-test-2 ] unit-test
+
+[ 1 ] [ 3 4 [| | '[ [ _ swap - ] call ] call ] call ] unit-test
+[ -1 ] [ 3 4 [| | [| a | a - ] call ] call ] unit-test
+[ -1 ] [ 3 4 [| | [| a | a - ] curry call ] call ] unit-test
+[ -1 ] [ 3 4 [| a | a - ] curry call ] unit-test
+[ 1 ] [ 3 4 [| | '[ [| a | _ a - ] call ] call ] call ] unit-test
+[ -1 ] [ 3 4 [| | '[ [| a | a _ - ] call ] call ] call ] unit-test
+
+[ { 1 2 3 4 } ] [
+ 1 3 2 4
+ [| | '[ [| a b | a _ b _ 4array ] call ] call ] call
+] unit-test
+
+[ 10 ] [
+ [| | 0 '[ [let | A [ 10 ] | A _ + ] ] call ] call
+] unit-test
\ No newline at end of file
! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel namespaces make sequences sequences.private assocs
-math vectors strings classes.tuple generalizations parser words
-quotations debugger macros arrays macros splitting combinators
-prettyprint.backend definitions prettyprint hashtables
-prettyprint.sections sets sequences.private effects
-effects.parser generic generic.parser compiler.units accessors
-locals.backend memoize macros.expander lexer classes ;
+USING: lexer macros memoize parser sequences vocabs
+vocabs.loader words kernel namespaces locals.parser locals.types
+locals.errors ;
IN: locals
-! Inspired by
-! http://cat-language.googlecode.com/svn/trunk/CatPointFreeForm.cs
-
-<PRIVATE
-
-TUPLE: lambda vars body ;
-
-C: <lambda> lambda
-
-TUPLE: binding-form bindings body ;
-
-TUPLE: let < binding-form ;
-
-C: <let> let
-
-TUPLE: let* < binding-form ;
-
-C: <let*> let*
-
-TUPLE: wlet < binding-form ;
-
-C: <wlet> wlet
-
-M: lambda expand-macros clone [ expand-macros ] change-body ;
-
-M: lambda expand-macros* expand-macros literal ;
-
-M: binding-form expand-macros
- clone
- [ [ expand-macros ] assoc-map ] change-bindings
- [ expand-macros ] change-body ;
-
-M: binding-form expand-macros* expand-macros literal ;
-
-PREDICATE: local < word "local?" word-prop ;
-
-: <local> ( name -- word )
- #! Create a local variable identifier
- f <word>
- dup t "local?" set-word-prop ;
-
-PREDICATE: local-word < word "local-word?" word-prop ;
-
-: <local-word> ( name -- word )
- f <word> dup t "local-word?" set-word-prop ;
-
-PREDICATE: local-reader < word "local-reader?" word-prop ;
-
-: <local-reader> ( name -- word )
- f <word>
- dup t "local-reader?" set-word-prop ;
-
-PREDICATE: local-writer < word "local-writer?" word-prop ;
-
-: <local-writer> ( reader -- word )
- dup name>> "!" append f <word> {
- [ nip t "local-writer?" set-word-prop ]
- [ swap "local-reader" set-word-prop ]
- [ "local-writer" set-word-prop ]
- [ nip ]
- } 2cleave ;
-
-TUPLE: quote local ;
-
-C: <quote> quote
-
-: local-index ( obj args -- n )
- [ dup quote? [ local>> ] when eq? ] with find drop ;
-
-: read-local-quot ( obj args -- quot )
- local-index 1+ [ get-local ] curry ;
-
-: localize-writer ( obj args -- quot )
- >r "local-reader" word-prop r>
- read-local-quot [ set-local-value ] append ;
-
-: localize ( obj args -- quot )
- {
- { [ over local? ] [ read-local-quot ] }
- { [ over quote? ] [ >r local>> r> read-local-quot ] }
- { [ over local-word? ] [ read-local-quot [ call ] append ] }
- { [ over local-reader? ] [ read-local-quot [ local-value ] append ] }
- { [ over local-writer? ] [ localize-writer ] }
- { [ over \ lambda eq? ] [ 2drop [ ] ] }
- { [ t ] [ drop 1quotation ] }
- } cond ;
-
-UNION: special local quote local-word local-reader local-writer ;
-
-: load-locals-quot ( args -- quot )
- [
- [ ]
- ] [
- dup [ local-reader? ] contains? [
- <reversed> [
- local-reader? [ 1array >r ] [ >r ] ?
- ] map concat
- ] [
- length [ load-locals ] curry >quotation
- ] if
- ] if-empty ;
-
-: drop-locals-quot ( args -- quot )
- [ [ ] ] [ length [ drop-locals ] curry ] if-empty ;
-
-: point-free-body ( quot args -- newquot )
- >r but-last-slice r> [ localize ] curry map concat ;
-
-: point-free-end ( quot args -- newquot )
- over peek special?
- [ dup drop-locals-quot >r >r peek r> localize r> append ]
- [ dup drop-locals-quot nip swap peek suffix ]
- if ;
-
-: (point-free) ( quot args -- newquot )
- [ nip load-locals-quot ]
- [ point-free-body ]
- [ point-free-end ]
- 2tri 3append >quotation ;
-
-: point-free ( quot args -- newquot )
- over empty?
- [ nip length \ drop <repetition> >quotation ]
- [ (point-free) ] if ;
-
-UNION: lexical local local-reader local-writer local-word ;
-
-GENERIC: free-vars* ( form -- )
-
-: free-vars ( form -- vars )
- [ free-vars* ] { } make prune ;
-
-: add-if-free ( object -- )
- {
- { [ dup local-writer? ] [ "local-reader" word-prop , ] }
- { [ dup lexical? ] [ , ] }
- { [ dup quote? ] [ local>> , ] }
- { [ t ] [ free-vars* ] }
- } cond ;
-
-M: object free-vars* drop ;
-
-M: quotation free-vars* [ add-if-free ] each ;
-
-M: lambda free-vars*
- [ vars>> ] [ body>> ] bi free-vars swap diff % ;
-
-GENERIC: lambda-rewrite* ( obj -- )
-
-GENERIC: local-rewrite* ( obj -- )
-
-: lambda-rewrite ( form -- form' )
- expand-macros
- [ local-rewrite* ] [ ] make
- [ [ lambda-rewrite* ] each ] [ ] make ;
-
-UNION: block callable lambda ;
-
-GENERIC: block-vars ( block -- seq )
-
-GENERIC: block-body ( block -- quot )
-
-M: callable block-vars drop { } ;
-
-M: callable block-body ;
-
-M: callable local-rewrite*
- [ [ local-rewrite* ] each ] [ ] make , ;
-
-M: lambda block-vars vars>> ;
-
-M: lambda block-body body>> ;
-
-M: lambda local-rewrite*
- [ vars>> ] [ body>> ] bi
- [ [ local-rewrite* ] each ] [ ] make <lambda> , ;
-
-M: block lambda-rewrite*
- #! Turn free variables into bound variables, curry them
- #! onto the body
- dup free-vars [ <quote> ] map dup % [
- over block-vars prepend
- swap block-body [ [ lambda-rewrite* ] each ] [ ] make
- swap point-free ,
- ] keep length \ curry <repetition> % ;
-
-GENERIC: rewrite-literal? ( obj -- ? )
-
-M: special rewrite-literal? drop t ;
-
-M: array rewrite-literal? [ rewrite-literal? ] contains? ;
-
-M: hashtable rewrite-literal? drop t ;
-
-M: vector rewrite-literal? drop t ;
-
-M: tuple rewrite-literal? drop t ;
-
-M: object rewrite-literal? drop f ;
-
-GENERIC: rewrite-element ( obj -- )
-
-: rewrite-elements ( seq -- )
- [ rewrite-element ] each ;
-
-: rewrite-sequence ( seq -- )
- [ rewrite-elements ] [ length , ] [ , ] tri \ nsequence , ;
-
-M: array rewrite-element
- dup rewrite-literal? [ rewrite-sequence ] [ , ] if ;
-
-M: vector rewrite-element rewrite-sequence ;
-
-M: hashtable rewrite-element >alist rewrite-sequence \ >hashtable , ;
-
-M: tuple rewrite-element
- [ tuple-slots rewrite-elements ] [ class , ] bi \ boa , ;
-
-M: local rewrite-element , ;
-
-M: word rewrite-element literalize , ;
-
-M: object rewrite-element , ;
-
-M: array local-rewrite* rewrite-element ;
-
-M: vector local-rewrite* rewrite-element ;
-
-M: tuple local-rewrite* rewrite-element ;
-
-M: hashtable local-rewrite* rewrite-element ;
-
-M: object lambda-rewrite* , ;
-
-M: object local-rewrite* , ;
-
-: make-local ( name -- word )
- "!" ?tail [
- <local-reader>
- dup <local-writer> dup name>> set
- ] [ <local> ] if
- dup dup name>> set ;
-
-: make-locals ( seq -- words assoc )
- [ [ make-local ] map ] H{ } make-assoc ;
-
-: make-local-word ( name -- word )
- <local-word> dup dup name>> set ;
-
-: push-locals ( assoc -- )
- use get push ;
-
-: pop-locals ( assoc -- )
- use get delete ;
-
-SYMBOL: in-lambda?
-
-: (parse-lambda) ( assoc end -- quot )
- t in-lambda? [ parse-until ] with-variable
- >quotation swap pop-locals ;
-
-: parse-lambda ( -- lambda )
- "|" parse-tokens make-locals dup push-locals
- \ ] (parse-lambda) <lambda> ;
-
-: parse-binding ( -- pair/f )
- scan dup "|" = [
- drop f
- ] [
- scan {
- { "[" [ \ ] parse-until >quotation ] }
- { "[|" [ parse-lambda ] }
- } case 2array
- ] if ;
-
-: (parse-bindings) ( -- )
- parse-binding [
- first2 >r make-local r> 2array ,
- (parse-bindings)
- ] when* ;
-
-: parse-bindings ( -- bindings vars )
- [
- [ (parse-bindings) ] H{ } make-assoc
- dup push-locals
- ] { } make swap ;
-
-: parse-bindings* ( -- words assoc )
- [
- [
- namespace push-locals
-
- (parse-bindings)
- ] { } make-assoc
- ] { } make swap ;
-
-: (parse-wbindings) ( -- )
- parse-binding [
- first2 >r make-local-word r> 2array ,
- (parse-wbindings)
- ] when* ;
-
-: parse-wbindings ( -- bindings vars )
- [
- [ (parse-wbindings) ] H{ } make-assoc
- dup push-locals
- ] { } make swap ;
-
-: let-rewrite ( body bindings -- )
- <reversed> [
- >r 1array r> spin <lambda> [ call ] curry compose
- ] assoc-each local-rewrite* \ call , ;
-
-M: let local-rewrite*
- [ body>> ] [ bindings>> ] bi let-rewrite ;
-
-M: let* local-rewrite*
- [ body>> ] [ bindings>> ] bi let-rewrite ;
-
-M: wlet local-rewrite*
- [ body>> ] [ bindings>> ] bi
- [ [ ] curry ] assoc-map
- let-rewrite ;
-
-: parse-locals ( -- vars assoc )
- ")" parse-effect
- word [ over "declared-effect" set-word-prop ] when*
- in>> [ dup pair? [ first ] when ] map make-locals dup push-locals ;
-
-: parse-locals-definition ( word -- word quot )
- scan "(" assert= parse-locals \ ; (parse-lambda) <lambda>
- 2dup "lambda" set-word-prop
- lambda-rewrite first ;
-
-: (::) ( -- word def ) CREATE-WORD parse-locals-definition ;
-
-: (M::) ( -- word def )
- CREATE-METHOD
- [ parse-locals-definition ] with-method-definition ;
-
-: parsed-lambda ( accum form -- accum )
- in-lambda? get [ parsed ] [ lambda-rewrite over push-all ] if ;
-
-PRIVATE>
+: :>
+ scan locals get [ :>-outside-lambda-error ] unless*
+ [ make-local ] bind <def> parsed ; parsing
: [| parse-lambda parsed-lambda ; parsing
: [let
- scan "|" assert= parse-bindings
+ "|" expect "|" parse-bindings
\ ] (parse-lambda) <let> parsed-lambda ; parsing
: [let*
- scan "|" assert= parse-bindings*
+ "|" expect "|" parse-bindings*
\ ] (parse-lambda) <let*> parsed-lambda ; parsing
: [wlet
- scan "|" assert= parse-wbindings
+ "|" expect "|" parse-wbindings
\ ] (parse-lambda) <wlet> parsed-lambda ; parsing
: :: (::) define ; parsing
: MEMO:: (::) define-memoized ; parsing
-<PRIVATE
-
-! Pretty-printing locals
-SYMBOL: |
-
-: pprint-var ( var -- )
- #! Prettyprint a read/write local as its writer, just like
- #! in the input syntax: [| x! | ... x 3 + x! ]
- dup local-reader? [
- "local-writer" word-prop
- ] when pprint-word ;
-
-: pprint-vars ( vars -- ) [ pprint-var ] each ;
-
-M: lambda pprint*
- <flow
- \ [| pprint-word
- dup vars>> pprint-vars
- \ | pprint-word
- f <inset body>> pprint-elements block>
- \ ] pprint-word
- block> ;
-
-: pprint-let ( let word -- )
- pprint-word
- [ body>> ] [ bindings>> ] bi
- \ | pprint-word
- t <inset
- <block
- [ <block >r pprint-var r> pprint* block> ] assoc-each
- block>
- \ | pprint-word
- <block pprint-elements block>
- block>
- \ ] pprint-word ;
-
-M: let pprint* \ [let pprint-let ;
-
-M: wlet pprint* \ [wlet pprint-let ;
-
-M: let* pprint* \ [let* pprint-let ;
-
-PREDICATE: lambda-word < word "lambda" word-prop >boolean ;
-
-M: lambda-word definer drop \ :: \ ; ;
-
-M: lambda-word definition
- "lambda" word-prop body>> ;
-
-M: lambda-word reset-word
- [ call-next-method ] [ f "lambda" set-word-prop ] bi ;
-
-INTERSECTION: lambda-macro macro lambda-word ;
-
-M: lambda-macro definer drop \ MACRO:: \ ; ;
-
-M: lambda-macro definition
- "lambda" word-prop body>> ;
-
-M: lambda-macro reset-word
- [ call-next-method ] [ f "lambda" set-word-prop ] bi ;
-
-INTERSECTION: lambda-method method-body lambda-word ;
-
-M: lambda-method definer drop \ M:: \ ; ;
-
-M: lambda-method definition
- "lambda" word-prop body>> ;
-
-M: lambda-method reset-word
- [ call-next-method ] [ f "lambda" set-word-prop ] bi ;
-
-INTERSECTION: lambda-memoized memoized lambda-word ;
-
-M: lambda-memoized definer drop \ MEMO:: \ ; ;
-
-M: lambda-memoized definition
- "lambda" word-prop body>> ;
-
-M: lambda-memoized reset-word
- [ call-next-method ] [ f "lambda" set-word-prop ] bi ;
-
-: method-stack-effect ( method -- effect )
- dup "lambda" word-prop vars>>
- swap "method-generic" word-prop stack-effect
- dup [ out>> ] when
- <effect> ;
-
-M: lambda-method synopsis*
- dup dup dup definer.
- "method-class" word-prop pprint-word
- "method-generic" word-prop pprint-word
- method-stack-effect effect>string comment. ;
+{
+ "locals.macros"
+ "locals.fry"
+} [ require ] each
-PRIVATE>
+"prettyprint" vocab [
+ "locals.definitions" require
+ "locals.prettyprint" require
+] when
--- /dev/null
+! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs kernel locals.types macros.expander ;
+IN: locals.macros
+
+M: lambda expand-macros clone [ expand-macros ] change-body ;
+
+M: lambda expand-macros* expand-macros literal ;
+
+M: binding-form expand-macros
+ clone
+ [ [ expand-macros ] assoc-map ] change-bindings
+ [ expand-macros ] change-body ;
+
+M: binding-form expand-macros* expand-macros literal ;
+
--- /dev/null
+! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays combinators effects.parser
+generic.parser kernel lexer locals.errors
+locals.rewrite.closures locals.types make namespaces parser
+quotations sequences splitting words ;
+IN: locals.parser
+
+: make-local ( name -- word )
+ "!" ?tail [
+ <local-reader>
+ dup <local-writer> dup name>> set
+ ] [ <local> ] if
+ dup dup name>> set ;
+
+: make-locals ( seq -- words assoc )
+ [ [ make-local ] map ] H{ } make-assoc ;
+
+: make-local-word ( name def -- word )
+ [ <local-word> [ dup name>> set ] [ ] [ ] tri ] dip
+ "local-word-def" set-word-prop ;
+
+SYMBOL: locals
+
+: push-locals ( assoc -- )
+ use get push ;
+
+: pop-locals ( assoc -- )
+ use get delete ;
+
+SYMBOL: in-lambda?
+
+: (parse-lambda) ( assoc end -- quot )
+ [
+ in-lambda? on
+ over locals set
+ over push-locals
+ parse-until >quotation
+ swap pop-locals
+ ] with-scope ;
+
+: parse-lambda ( -- lambda )
+ "|" parse-tokens make-locals
+ \ ] (parse-lambda) <lambda> ;
+
+: parse-binding ( end -- pair/f )
+ scan {
+ { [ dup not ] [ unexpected-eof ] }
+ { [ 2dup = ] [ 2drop f ] }
+ [ nip scan-object 2array ]
+ } cond ;
+
+: (parse-bindings) ( end -- )
+ dup parse-binding dup [
+ first2 [ make-local ] dip 2array ,
+ (parse-bindings)
+ ] [ 2drop ] if ;
+
+: parse-bindings ( end -- bindings vars )
+ [
+ [ (parse-bindings) ] H{ } make-assoc
+ ] { } make swap ;
+
+: parse-bindings* ( end -- words assoc )
+ [
+ [
+ namespace push-locals
+ (parse-bindings)
+ namespace pop-locals
+ ] { } make-assoc
+ ] { } make swap ;
+
+: (parse-wbindings) ( end -- )
+ dup parse-binding dup [
+ first2 [ make-local-word ] keep 2array ,
+ (parse-wbindings)
+ ] [ 2drop ] if ;
+
+: parse-wbindings ( end -- bindings vars )
+ [
+ [ (parse-wbindings) ] H{ } make-assoc
+ ] { } make swap ;
+
+: parse-locals ( -- vars assoc )
+ "(" expect ")" parse-effect
+ word [ over "declared-effect" set-word-prop ] when*
+ in>> [ dup pair? [ first ] when ] map make-locals ;
+
+: parse-locals-definition ( word -- word quot )
+ parse-locals \ ; (parse-lambda) <lambda>
+ 2dup "lambda" set-word-prop
+ rewrite-closures dup length 1 = [ first ] [ bad-lambda-rewrite ] if ;
+
+: (::) ( -- word def ) CREATE-WORD parse-locals-definition ;
+
+: (M::) ( -- word def )
+ CREATE-METHOD
+ [ parse-locals-definition ] with-method-definition ;
+
+: parsed-lambda ( accum form -- accum )
+ in-lambda? get [ parsed ] [ rewrite-closures over push-all ] if ;
--- /dev/null
+! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs kernel locals locals.types
+prettyprint.backend prettyprint.sections prettyprint.custom
+sequences words ;
+IN: locals.prettyprint
+
+SYMBOL: |
+
+: pprint-var ( var -- )
+ #! Prettyprint a read/write local as its writer, just like
+ #! in the input syntax: [| x! | ... x 3 + x! ]
+ dup local-reader? [
+ "local-writer" word-prop
+ ] when pprint-word ;
+
+: pprint-vars ( vars -- ) [ pprint-var ] each ;
+
+M: lambda pprint*
+ <flow
+ \ [| pprint-word
+ dup vars>> pprint-vars
+ \ | pprint-word
+ f <inset body>> pprint-elements block>
+ \ ] pprint-word
+ block> ;
+
+: pprint-let ( let word -- )
+ pprint-word
+ [ body>> ] [ bindings>> ] bi
+ \ | pprint-word
+ t <inset
+ <block
+ [ <block [ pprint-var ] dip pprint* block> ] assoc-each
+ block>
+ \ | pprint-word
+ <block pprint-elements block>
+ block>
+ \ ] pprint-word ;
+
+M: let pprint* \ [let pprint-let ;
+
+M: wlet pprint* \ [wlet pprint-let ;
+
+M: let* pprint* \ [let* pprint-let ;
+
+M: def pprint*
+ <block \ :> pprint-word local>> pprint-word block> ;
--- /dev/null
+! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel locals.rewrite.point-free
+locals.rewrite.sugar locals.types macros.expander make
+quotations sequences sets words ;
+IN: locals.rewrite.closures
+
+! Step 2: identify free variables and make them into explicit
+! parameters of lambdas which are curried on
+
+GENERIC: rewrite-closures* ( obj -- )
+
+: (rewrite-closures) ( form -- form' )
+ [ [ rewrite-closures* ] each ] [ ] make ;
+
+: rewrite-closures ( form -- form' )
+ expand-macros (rewrite-sugar) (rewrite-closures) point-free ;
+
+GENERIC: defs-vars* ( seq form -- seq' )
+
+: defs-vars ( form -- vars ) { } [ defs-vars* ] reduce prune ;
+
+M: def defs-vars* local>> unquote suffix ;
+
+M: quotation defs-vars* [ defs-vars* ] each ;
+
+M: object defs-vars* drop ;
+
+GENERIC: uses-vars* ( seq form -- seq' )
+
+: uses-vars ( form -- vars ) { } [ uses-vars* ] reduce prune ;
+
+M: local-writer uses-vars* "local-reader" word-prop suffix ;
+
+M: lexical uses-vars* suffix ;
+
+M: quote uses-vars* local>> uses-vars* ;
+
+M: object uses-vars* drop ;
+
+M: quotation uses-vars* [ uses-vars* ] each ;
+
+: free-vars ( form -- seq )
+ [ uses-vars ] [ defs-vars ] bi diff ;
+
+M: callable rewrite-closures*
+ #! Turn free variables into bound variables, curry them
+ #! onto the body
+ dup free-vars [ <quote> ] map
+ [ % ]
+ [ var-defs prepend (rewrite-closures) point-free , ]
+ [ length \ curry <repetition> % ]
+ tri ;
+
+M: object rewrite-closures* , ;
--- /dev/null
+! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays fry kernel math quotations sequences
+words combinators make locals.backend locals.types
+locals.errors ;
+IN: locals.rewrite.point-free
+
+! Step 3: rewrite locals usage within a single quotation into
+! retain stack manipulation
+
+: local-index ( args obj -- n )
+ 2dup '[ unquote _ eq? ] find drop
+ dup [ 2nip ] [ drop bad-local ] if ;
+
+: read-local-quot ( args obj -- quot )
+ local-index neg [ get-local ] curry ;
+
+GENERIC: localize ( args obj -- args quot )
+
+M: local localize dupd read-local-quot ;
+
+M: quote localize dupd local>> read-local-quot ;
+
+M: local-word localize dupd read-local-quot [ call ] append ;
+
+M: local-reader localize dupd read-local-quot [ local-value ] append ;
+
+M: local-writer localize
+ dupd "local-reader" word-prop
+ read-local-quot [ set-local-value ] append ;
+
+M: def localize
+ local>> [ prefix ] [ local-reader? [ 1array >r ] [ >r ] ? ] bi ;
+
+M: object localize 1quotation ;
+
+! We special-case all the :> at the start of a quotation
+: load-locals-quot ( args -- quot )
+ [ [ ] ] [
+ dup [ local-reader? ] contains? [
+ dup [ local-reader? [ 1array ] [ ] ? ] map
+ spread>quot
+ ] [ [ ] ] if swap length [ load-locals ] curry append
+ ] if-empty ;
+
+: load-locals-index ( quot -- n )
+ [ [ dup def? [ local>> local-reader? ] [ drop t ] if ] find drop ]
+ [ length ] bi or ;
+
+: point-free-start ( quot -- args rest )
+ dup load-locals-index
+ cut [ [ local>> ] map dup <reversed> load-locals-quot % ] dip ;
+
+: point-free-body ( args quot -- args )
+ [ localize % ] each ;
+
+: drop-locals-quot ( args -- )
+ [ length , [ drop-locals ] % ] unless-empty ;
+
+: point-free-end ( args obj -- )
+ dup special?
+ [ localize % drop-locals-quot ]
+ [ [ drop-locals-quot ] [ , ] bi* ]
+ if ;
+
+: point-free ( quot -- newquot )
+ [
+ point-free-start
+ [ drop-locals-quot ] [
+ unclip-last
+ [ point-free-body ]
+ [ point-free-end ]
+ bi*
+ ] if-empty
+ ] [ ] make ;
--- /dev/null
+! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays assocs classes classes.tuple fry
+generalizations hashtables kernel locals locals.backend
+locals.errors locals.types make quotations sequences vectors
+words ;
+IN: locals.rewrite.sugar
+
+! Step 1: rewrite [| [let [let* [wlet into :> forms, turn
+! literals with locals in them into code which constructs
+! the literal after pushing locals on the stack
+
+GENERIC: rewrite-sugar* ( obj -- )
+
+: (rewrite-sugar) ( form -- form' )
+ [ rewrite-sugar* ] [ ] make ;
+
+GENERIC: quotation-rewrite ( form -- form' )
+
+M: callable quotation-rewrite [ [ rewrite-sugar* ] each ] [ ] make ;
+
+: var-defs ( vars -- defs ) <reversed> [ <def> ] [ ] map-as ;
+
+M: lambda quotation-rewrite
+ [ body>> ] [ vars>> var-defs ] bi
+ prepend quotation-rewrite ;
+
+M: callable rewrite-sugar* quotation-rewrite , ;
+
+M: lambda rewrite-sugar* quotation-rewrite , ;
+
+GENERIC: rewrite-literal? ( obj -- ? )
+
+M: special rewrite-literal? drop t ;
+
+M: array rewrite-literal? [ rewrite-literal? ] contains? ;
+
+M: quotation rewrite-literal? [ rewrite-literal? ] contains? ;
+
+M: wrapper rewrite-literal? drop t ;
+
+M: hashtable rewrite-literal? drop t ;
+
+M: vector rewrite-literal? drop t ;
+
+M: tuple rewrite-literal? drop t ;
+
+M: object rewrite-literal? drop f ;
+
+GENERIC: rewrite-element ( obj -- )
+
+: rewrite-elements ( seq -- )
+ [ rewrite-element ] each ;
+
+: rewrite-sequence ( seq -- )
+ [ rewrite-elements ] [ length , ] [ 0 head , ] tri \ nsequence , ;
+
+M: array rewrite-element
+ dup rewrite-literal? [ rewrite-sequence ] [ , ] if ;
+
+M: vector rewrite-element rewrite-sequence ;
+
+M: hashtable rewrite-element >alist rewrite-sequence \ >hashtable , ;
+
+M: tuple rewrite-element
+ [ tuple-slots rewrite-elements ] [ class literalize , ] bi \ boa , ;
+
+M: quotation rewrite-element rewrite-sugar* ;
+
+M: lambda rewrite-element rewrite-sugar* ;
+
+M: binding-form rewrite-element binding-form-in-literal-error ;
+
+M: local rewrite-element , ;
+
+M: local-reader rewrite-element , ;
+
+M: local-writer rewrite-element
+ local-writer-in-literal-error ;
+
+M: local-word rewrite-element
+ local-word-in-literal-error ;
+
+M: word rewrite-element literalize , ;
+
+M: wrapper rewrite-element
+ dup rewrite-literal? [ wrapped>> rewrite-element ] [ , ] if ;
+
+M: object rewrite-element , ;
+
+M: array rewrite-sugar* rewrite-element ;
+
+M: vector rewrite-sugar* rewrite-element ;
+
+M: tuple rewrite-sugar* rewrite-element ;
+
+M: def rewrite-sugar* , ;
+
+M: hashtable rewrite-sugar* rewrite-element ;
+
+M: wrapper rewrite-sugar* rewrite-element ;
+
+M: word rewrite-sugar*
+ dup { >r r> load-locals get-local drop-locals } memq?
+ [ >r/r>-in-lambda-error ] [ call-next-method ] if ;
+
+M: object rewrite-sugar* , ;
+
+: let-rewrite ( body bindings -- )
+ [ quotation-rewrite % <def> , ] assoc-each
+ quotation-rewrite % ;
+
+M: let rewrite-sugar*
+ [ body>> ] [ bindings>> ] bi let-rewrite ;
+
+M: let* rewrite-sugar*
+ [ body>> ] [ bindings>> ] bi let-rewrite ;
+
+M: wlet rewrite-sugar*
+ [ body>> ] [ bindings>> ] bi
+ [ '[ _ ] ] assoc-map
+ let-rewrite ;
--- /dev/null
+! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators kernel sequences words ;
+IN: locals.types
+
+TUPLE: lambda vars body ;
+
+C: <lambda> lambda
+
+TUPLE: binding-form bindings body ;
+
+TUPLE: let < binding-form ;
+
+C: <let> let
+
+TUPLE: let* < binding-form ;
+
+C: <let*> let*
+
+TUPLE: wlet < binding-form ;
+
+C: <wlet> wlet
+
+TUPLE: quote local ;
+
+C: <quote> quote
+
+: unquote ( quote -- local ) dup quote? [ local>> ] when ; inline
+
+TUPLE: def local ;
+
+C: <def> def
+
+PREDICATE: local < word "local?" word-prop ;
+
+: <local> ( name -- word )
+ #! Create a local variable identifier
+ f <word>
+ dup t "local?" set-word-prop ;
+
+PREDICATE: local-word < word "local-word?" word-prop ;
+
+: <local-word> ( name -- word )
+ f <word> dup t "local-word?" set-word-prop ;
+
+PREDICATE: local-reader < word "local-reader?" word-prop ;
+
+: <local-reader> ( name -- word )
+ f <word>
+ dup t "local-reader?" set-word-prop ;
+
+PREDICATE: local-writer < word "local-writer?" word-prop ;
+
+: <local-writer> ( reader -- word )
+ dup name>> "!" append f <word> {
+ [ nip t "local-writer?" set-word-prop ]
+ [ swap "local-reader" set-word-prop ]
+ [ "local-writer" set-word-prop ]
+ [ nip ]
+ } 2cleave ;
+
+UNION: lexical local local-reader local-writer local-word ;
+UNION: special lexical quote def ;
\r
: analyze-entry ( entry -- )\r
dup level>> { ERROR CRITICAL } memq? [ dup errors get push ] when\r
- 1 over word-name>> word-histogram get at+\r
+ dup word-name>> word-histogram get inc-at\r
dup word-name>> word-names get member? [\r
- 1 over [ level>> ] [ word-name>> ] [ message>> ] tri 3array\r
- message-histogram get at+\r
+ dup [ level>> ] [ word-name>> ] [ message>> ] tri 3array\r
+ message-histogram get inc-at\r
] when\r
drop ;\r
\r
\r
: histogram. ( assoc quot -- )\r
standard-table-style [\r
- >r >alist sort-values <reversed> r> [\r
- [ >r swap r> with-cell pprint-cell ] with-row\r
+ [ >alist sort-values <reversed> ] dip [\r
+ [ swapd with-cell pprint-cell ] with-row\r
] curry assoc-each\r
] tabular-output ;\r
\r
errors. ;\r
\r
: analyze-log ( lines word-names -- )\r
- >r parse-log r> analyze-entries analysis. ;\r
+ [ parse-log ] dip analyze-entries analysis. ;\r
\r
: analyze-log-file ( service word-names -- )\r
- >r parse-log-file r> analyze-entries analysis. ;\r
+ [ parse-log-file ] dip analyze-entries analysis. ;\r
{ $subsection "logging.rotation" }
{ $subsection "logging.parser" }
{ $subsection "logging.analysis" }
-{ $subsection "logging.insomniac" }
{ $subsection "logging.server" } ;
ABOUT: "logging"
\r
"logging.parser" require\r
"logging.analysis" require\r
-"logging.insomniac" require\r
: log-stream ( service -- stream )\r
log-files get [ open-log-stream ] cache ;\r
\r
-: multiline-header 20 CHAR: - <string> ; foldable\r
+: multiline-header ( -- string ) 20 CHAR: - <string> ; foldable\r
\r
: (write-message) ( msg name>> level multi? -- )\r
[\r
[ '[ _ ndrop _ nnip call ] [ ] like ] 2map , \ dispatch ,
] bi ;
-: expand-macro ( quot -- )
- stack [ swap with-datastack >vector ] change
- stack get pop >quotation end (expand-macros) ;
+: word, ( word -- ) end , ;
+
+: expand-macro ( word quot -- )
+ '[
+ drop
+ stack [ _ with-datastack >vector ] change
+ stack get pop >quotation end (expand-macros)
+ ] [
+ drop
+ word,
+ ] recover ;
: expand-macro? ( word -- quot ? )
dup [ "transform-quot" word-prop ] [ "macro" word-prop ] bi or dup [
stack get length <=
] [ 2drop f f ] if ;
-: word, ( word -- ) end , ;
-
M: word expand-macros*
dup expand-dispatch? [ drop expand-dispatch ] [
- dup expand-macro? [ nip expand-macro ] [
+ dup expand-macro? [ expand-macro ] [
drop word,
] if
] if ;
M: macro reset-word
[ call-next-method ] [ f "macro" set-word-prop ] bi ;
-
-: n*quot ( n seq -- seq' ) <repetition> concat >quotation ;
-
-: saver ( n -- quot ) \ >r <repetition> >quotation ;
-
-: restorer ( n -- quot ) \ r> <repetition> >quotation ;
2dup [ length ] bi@ < [ 2drop f f ]
[
2dup length head over match
- [ nip swap ?1-tail ] [ >r rest r> (match-first) ] if*
+ [ nip swap ?1-tail ] [ [ rest ] dip (match-first) ] if*
] if ;
: match-first ( seq pattern-seq -- bindings )
"64 on-bits .h"
"ffffffffffffffff"
}
+} ;
+
+HELP: toggle-bit
+{ $values
+ { "m" integer }
+ { "n" integer }
+ { "m'" integer }
}
-;
+{ $description "Toggles the nth bit of an integer." }
+{ $examples
+ { $example "USING: math.bitwise kernel prettyprint ;"
+ "0 3 toggle-bit .b"
+ "1000"
+ }
+ { $example "USING: math.bitwise kernel prettyprint ;"
+ "BIN: 1000 3 toggle-bit .b"
+ "0"
+ }
+} ;
HELP: set-bit
{ $values
"Some applications, such as binary communication protocols and assemblers, need to construct integers from elaborate bit field specifications. Hand-coding this using " { $link shift } " and " { $link bitor } " results in repetitive code. A higher-level facility exists to factor out this repetition:"
{ $subsection bitfield } ;
-ARTICLE: "math.bitwise" "Bitwise arithmetic"
-"The " { $vocab-link "math.bitwise" } " vocabulary can implements bitwise arithmetic words that are useful for efficiency, low-level programming, and interfacing with C libraries." $nl
+ARTICLE: "math.bitwise" "Additional bitwise arithmetic"
+"The " { $vocab-link "math.bitwise" } " vocabulary provides bitwise arithmetic words extending " { $link "bitwise-arithmetic" } ". They are useful for efficiency, low-level programming, and interfacing with C libraries."
+$nl
"Setting and clearing bits:"
{ $subsection set-bit }
{ $subsection clear-bit }
\ foo must-infer
[ 1 ] [ { 1 } flags ] unit-test
+
+[ 8 ] [ 0 3 toggle-bit ] unit-test
+[ 0 ] [ 8 3 toggle-bit ] unit-test
! See http://factorcode.org/license.txt for BSD license.
USING: arrays kernel math math.functions sequences
sequences.private words namespaces macros hints
-combinators fry ;
+combinators fry io.binary ;
IN: math.bitwise
! utilities
: bits ( m n -- m' ) 2^ wrap ; inline
: mask-bit ( m n -- m' ) 2^ mask ; inline
: on-bits ( n -- m ) 2^ 1- ; inline
+: toggle-bit ( m n -- m' ) 2^ bitxor ; inline
: shift-mod ( n s w -- n )
[ shift ] dip 2^ wrap ; inline
: bitroll ( x s w -- y )
[ wrap ] keep
- [ shift-mod ]
- [ [ - ] keep shift-mod ] 3bi bitor ; inline
+ [ shift-mod ] [ [ - ] keep shift-mod ] 3bi bitor ; inline
: bitroll-32 ( n s -- n' ) 32 bitroll ; inline
-HINTS: bitroll-32 bignum fixnum ;
-
: bitroll-64 ( n s -- n' ) 64 bitroll ; inline
-HINTS: bitroll-64 bignum fixnum ;
-
! 32-bit arithmetic
: w+ ( int int -- int ) + 32 bits ; inline
: w- ( int int -- int ) - 32 bits ; inline
: bit-count ( x -- n )
dup 0 < [ bitnot ] when (bit-count) ; inline
+
+! Signed byte array to integer conversion
+: signed-le> ( bytes -- x )
+ [ le> ] [ length 8 * 1- on-bits ] bi
+ 2dup > [ bitnot bitor ] [ drop ] if ;
+
+: signed-be> ( bytes -- x )
+ <reversed> signed-le> ;
--- /dev/null
+Slava Pestov
+Doug Coleman
+Aaron Schaefer
--- /dev/null
+USING: help.markup help.syntax kernel math math.order sequences ;
+IN: math.combinatorics
+
+HELP: factorial
+{ $values { "n" "a non-negative integer" } { "n!" integer } }
+{ $description "Outputs the product of all positive integers less than or equal to " { $snippet "n" } "." }
+{ $examples { $example "USING: math.combinatorics prettyprint ;" "4 factorial ." "24" } } ;
+
+HELP: nPk
+{ $values { "n" "a non-negative integer" } { "k" "a non-negative integer" } { "nPk" integer } }
+{ $description "Outputs the total number of unique permutations of size " { $snippet "k" } " (order does matter) that can be taken from a set of size " { $snippet "n" } "." }
+{ $examples { $example "USING: math.combinatorics prettyprint ;" "10 4 nPk ." "5040" } } ;
+
+HELP: nCk
+{ $values { "n" "a non-negative integer" } { "k" "a non-negative integer" } { "nCk" integer } }
+{ $description "Outputs the total number of unique combinations of size " { $snippet "k" } " (order does not matter) that can be taken from a set of size " { $snippet "n" } ". Commonly written as \"n choose k\"." }
+{ $examples { $example "USING: math.combinatorics prettyprint ;" "10 4 nCk ." "210" } } ;
+
+HELP: permutation
+{ $values { "n" "a non-negative integer" } { "seq" sequence } { "seq" sequence } }
+{ $description "Outputs the " { $snippet "nth" } " lexicographical permutation of " { $snippet "seq" } "." }
+{ $notes "Permutations are 0-based and a bounds error will be thrown if " { $snippet "n" } " is larger than " { $snippet "seq length factorial 1-" } "." }
+{ $examples { $example "USING: math.combinatorics prettyprint ;" "1 3 permutation ." "{ 0 2 1 }" } { $example "USING: math.combinatorics prettyprint ;" "5 { \"apple\" \"banana\" \"orange\" } permutation ." "{ \"orange\" \"banana\" \"apple\" }" } } ;
+
+HELP: all-permutations
+{ $values { "seq" sequence } { "seq" sequence } }
+{ $description "Outputs a sequence containing all permutations of " { $snippet "seq" } " in lexicographical order." }
+{ $examples { $example "USING: math.combinatorics prettyprint ;" "3 all-permutations ." "{ { 0 1 2 } { 0 2 1 } { 1 0 2 } { 1 2 0 } { 2 0 1 } { 2 1 0 } }" } } ;
+
+HELP: inverse-permutation
+{ $values { "seq" sequence } { "permutation" sequence } }
+{ $description "Outputs a sequence of indices representing the lexicographical permutation of " { $snippet "seq" } "." }
+{ $notes "All items in " { $snippet "seq" } " must be comparable by " { $link <=> } "." }
+{ $examples { $example "USING: math.combinatorics prettyprint ;" "\"dcba\" inverse-permutation ." "{ 3 2 1 0 }" } { $example "USING: math.combinatorics prettyprint ;" "{ 12 56 34 78 } inverse-permutation ." "{ 0 2 1 3 }" } } ;
+
+
+IN: math.combinatorics.private
+
+HELP: factoradic
+{ $values { "n" integer } { "factoradic" sequence } }
+{ $description "Converts a positive integer " { $snippet "n" } " to factoradic form. The factoradic of an integer is its representation based on a mixed radix numerical system that corresponds to the values of " { $snippet "n" } " factorial." }
+{ $examples { $example "USING: math.combinatorics.private prettyprint ;" "859 factoradic ." "{ 1 1 0 3 0 1 0 }" } } ;
+
+HELP: >permutation
+{ $values { "factoradic" sequence } { "permutation" sequence } }
+{ $description "Converts an integer represented in factoradic form into its corresponding unique permutation (0-based)." }
+{ $notes "For clarification, the following two statements are equivalent:" { $code "10 factoradic >permutation" "{ 1 2 0 0 } >permutation" } }
+{ $examples { $example "USING: math.combinatorics.private prettyprint ;" "{ 0 0 0 0 } >permutation ." "{ 0 1 2 3 }" } } ;
+
--- /dev/null
+USING: math.combinatorics math.combinatorics.private tools.test ;
+IN: math.combinatorics.tests
+
+[ { } ] [ 0 factoradic ] unit-test
+[ { 1 0 } ] [ 1 factoradic ] unit-test
+[ { 1 1 0 3 0 1 0 } ] [ 859 factoradic ] unit-test
+
+[ { 0 1 2 3 } ] [ { 0 0 0 0 } >permutation ] unit-test
+[ { 0 1 3 2 } ] [ { 0 0 1 0 } >permutation ] unit-test
+[ { 1 2 0 6 3 5 4 } ] [ { 1 1 0 3 0 1 0 } >permutation ] unit-test
+
+[ { 0 1 2 3 } ] [ 0 4 permutation-indices ] unit-test
+[ { 0 1 3 2 } ] [ 1 4 permutation-indices ] unit-test
+[ { 1 2 0 6 3 5 4 } ] [ 859 7 permutation-indices ] unit-test
+
+[ 1 ] [ 0 factorial ] unit-test
+[ 1 ] [ 1 factorial ] unit-test
+[ 3628800 ] [ 10 factorial ] unit-test
+
+[ 1 ] [ 3 0 nPk ] unit-test
+[ 6 ] [ 3 2 nPk ] unit-test
+[ 6 ] [ 3 3 nPk ] unit-test
+[ 0 ] [ 3 4 nPk ] unit-test
+[ 311875200 ] [ 52 5 nPk ] unit-test
+[ 672151459757865654763838640470031391460745878674027315200000000000 ] [ 52 47 nPk ] unit-test
+
+[ 1 ] [ 3 0 nCk ] unit-test
+[ 3 ] [ 3 2 nCk ] unit-test
+[ 1 ] [ 3 3 nCk ] unit-test
+[ 0 ] [ 3 4 nCk ] unit-test
+[ 2598960 ] [ 52 5 nCk ] unit-test
+[ 2598960 ] [ 52 47 nCk ] unit-test
+
+[ { "a" "b" "c" "d" } ] [ 0 { "a" "b" "c" "d" } permutation ] unit-test
+[ { "d" "c" "b" "a" } ] [ 23 { "a" "b" "c" "d" } permutation ] unit-test
+[ { "d" "a" "b" "c" } ] [ 18 { "a" "b" "c" "d" } permutation ] unit-test
+
+[ { { "a" "b" "c" } { "a" "c" "b" }
+ { "b" "a" "c" } { "b" "c" "a" }
+ { "c" "a" "b" } { "c" "b" "a" } } ] [ { "a" "b" "c" } all-permutations ] unit-test
+
+[ { 0 1 2 } ] [ { "a" "b" "c" } inverse-permutation ] unit-test
+[ { 2 1 0 } ] [ { "c" "b" "a" } inverse-permutation ] unit-test
+[ { 3 0 2 1 } ] [ { 12 45 34 2 } inverse-permutation ] unit-test
+
--- /dev/null
+! 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 fry ;
+IN: math.combinatorics
+
+<PRIVATE
+
+: possible? ( n m -- ? )
+ 0 rot between? ; inline
+
+: twiddle ( n k -- n k )
+ 2dup - dupd > [ dupd - ] when ; inline
+
+! See this article for explanation of the factoradic-based permutation methodology:
+! http://msdn2.microsoft.com/en-us/library/aa302371.aspx
+
+: factoradic ( n -- factoradic )
+ 0 [ over 0 > ] [ 1+ [ /mod ] keep swap ] [ ] produce reverse 2nip ;
+
+: (>permutation) ( seq n -- seq )
+ [ '[ _ dupd >= [ 1+ ] when ] map ] keep prefix ;
+
+: >permutation ( factoradic -- permutation )
+ reverse 1 cut [ (>permutation) ] each ;
+
+: permutation-indices ( n seq -- permutation )
+ length [ factoradic ] dip 0 pad-left >permutation ;
+
+PRIVATE>
+
+: factorial ( n -- n! )
+ 1 [ 1+ * ] reduce ;
+
+: nPk ( n k -- nPk )
+ 2dup possible? [ dupd - [a,b) product ] [ 2drop 0 ] if ;
+
+: nCk ( n k -- nCk )
+ twiddle [ nPk ] keep factorial / ;
+
+: permutation ( n seq -- seq )
+ [ permutation-indices ] keep nths ;
+
+: all-permutations ( seq -- seq )
+ [ length factorial ] keep '[ _ permutation ] map ;
+
+: each-permutation ( seq quot -- )
+ [ [ length factorial ] keep ] dip
+ '[ _ permutation @ ] each ; inline
+
+: reduce-permutations ( seq initial quot -- result )
+ swapd each-permutation ; inline
+
+: inverse-permutation ( seq -- permutation )
+ <enum> >alist sort-values keys ;
--- /dev/null
+Permutations and combinations
! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel kernel.private math math.private
-math.libm math.functions prettyprint.backend arrays
-math.functions.private sequences parser ;
+math.libm math.functions arrays math.functions.private sequences
+parser ;
IN: math.complex.private
M: real real-part ;
M: complex absq >rect [ sq ] bi@ + ;
: 2>rect ( x y -- xr yr xi yi )
- [ [ real-part ] bi@ ] 2keep
- [ imaginary-part ] bi@ ; inline
+ [ [ real-part ] bi@ ]
+ [ [ imaginary-part ] bi@ ] 2bi ; inline
M: complex hashcode*
nip >rect [ hashcode ] bi@ bitxor ;
M: complex number=
2>rect number= [ number= ] [ 2drop f ] if ;
-: *re ( x y -- xr*yr xi*ri ) 2>rect * >r * r> ; inline
-: *im ( x y -- xi*yr xr*yi ) 2>rect >r * swap r> * ; inline
+: *re ( x y -- xr*yr xi*ri ) 2>rect [ * ] 2bi@ ; inline
+: *im ( x y -- xi*yr xr*yi ) 2>rect [ * swap ] dip * ; inline
-M: complex + 2>rect + >r + r> (rect>) ;
-M: complex - 2>rect - >r - r> (rect>) ;
-M: complex * 2dup *re - -rot *im + (rect>) ;
+M: complex + 2>rect [ + ] 2bi@ (rect>) ;
+M: complex - 2>rect [ - ] 2bi@ (rect>) ;
+M: complex * [ *re - ] [ *im + ] 2bi (rect>) ;
: complex/ ( x y -- r i m )
- dup absq >r 2dup *re + -rot *im - r> ; inline
+ [ [ *re + ] [ *im - ] 2bi ] keep absq ; inline
-M: complex / complex/ tuck / >r / r> (rect>) ;
+M: complex / complex/ tuck [ / ] 2bi@ (rect>) ;
M: complex abs absq >float fsqrt ;
-M: complex sqrt >polar swap fsqrt swap 2.0 / polar> ;
+M: complex sqrt >polar [ fsqrt ] [ 2.0 / ] bi* polar> ;
IN: syntax
: C{ \ } [ first2 rect> ] parse-literal ; parsing
-
-M: complex pprint-delims drop \ C{ \ } ;
-M: complex >pprint-sequence >rect 2array ;
-M: complex pprint* pprint-object ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: math math.functions arrays prettyprint.custom kernel ;
+IN: math.complex.prettyprint
+
+M: complex pprint* pprint-object ;
+M: complex pprint-delims drop \ C{ \ } ;
+M: complex >pprint-sequence >rect 2array ;
PRIVATE>
: rect> ( x y -- z )
- over real? over real? and [
+ 2dup [ real? ] both? [
(rect>)
] [
"Complex number must have real components" throw
>float dup 0.0 < [ neg fsqrt 0.0 swap rect> ] [ fsqrt ] if ;
: each-bit ( n quot: ( ? -- ) -- )
- over 0 = pick -1 = or [
+ over [ 0 = ] [ -1 = ] bi or [
2drop
] [
- 2dup >r >r >r odd? r> call r> 2/ r> each-bit
+ 2dup { [ odd? ] [ call ] [ 2/ ] [ each-bit ] } spread
] if ; inline recursive
: map-bits ( n quot: ( ? -- obj ) -- seq )
>rect [ >float ] bi@ ; inline
: >polar ( z -- abs arg )
- >float-rect [ [ sq ] bi@ + fsqrt ] [ swap fatan2 ] 2bi ;
- inline
+ >float-rect [ [ sq ] bi@ + fsqrt ] [ swap fatan2 ] 2bi ; inline
: cis ( arg -- z ) dup fcos swap fsin rect> ; inline
<PRIVATE
: ^mag ( w abs arg -- magnitude )
- >r >r >float-rect swap r> swap fpow r> rot * fexp /f ;
- inline
+ [ >float-rect swap ] [ swap fpow ] [ rot * fexp /f ] tri* ; inline
: ^theta ( w abs arg -- theta )
- >r >r >float-rect r> flog * swap r> * + ; inline
+ [ >float-rect ] [ flog * swap ] [ * + ] tri* ; inline
: ^complex ( x y -- z )
swap >polar [ ^mag ] [ ^theta ] 3bi polar> ; inline
: 0^ ( x -- z )
dup zero? [ drop 0./0. ] [ 0 < 1./0. 0 ? ] if ; inline
-PRIVATE>
-
-: ^ ( x y -- z )
- {
- { [ over zero? ] [ nip 0^ ] }
- { [ dup integer? ] [ integer^ ] }
- { [ 2dup real^? ] [ fpow ] }
- [ ^complex ]
- } cond ;
-
: (^mod) ( n x y -- z )
1 swap [
- [ dupd * pick mod ] when >r sq over mod r>
+ [ dupd * pick mod ] when [ sq over mod ] dip
] each-bit 2nip ; inline
: (gcd) ( b a x y -- a d )
over zero? [
2nip
] [
- swap [ /mod >r over * swapd - r> ] keep (gcd)
+ swap [ /mod [ over * swapd - ] dip ] keep (gcd)
] if ;
+PRIVATE>
+
+: ^ ( x y -- z )
+ {
+ { [ over zero? ] [ nip 0^ ] }
+ { [ dup integer? ] [ integer^ ] }
+ { [ 2dup real^? ] [ fpow ] }
+ [ ^complex ]
+ } cond ; inline
+
: gcd ( x y -- a d )
- 0 -rot 1 -rot (gcd) dup 0 < [ neg ] when ; foldable
+ [ 0 1 ] 2dip (gcd) dup 0 < [ neg ] when ; foldable
: lcm ( a b -- c )
[ * ] 2keep gcd nip /i ; foldable
: ^mod ( x y n -- z )
over 0 < [
- [ >r neg r> ^mod ] keep mod-inv
+ [ [ neg ] dip ^mod ] keep mod-inv
] [
-rot (^mod)
] if ; foldable
M: real absq sq ;
: ~abs ( x y epsilon -- ? )
- >r - abs r> < ;
+ [ - abs ] dip < ;
: ~rel ( x y epsilon -- ? )
- >r [ - abs ] 2keep [ abs ] bi@ + r> * < ;
+ [ [ - abs ] 2keep [ abs ] bi@ + ] dip * < ;
: ~ ( x y epsilon -- ? )
{
- { [ pick fp-nan? pick fp-nan? or ] [ 3drop f ] }
+ { [ 2over [ fp-nan? ] either? ] [ 3drop f ] }
{ [ dup zero? ] [ drop number= ] }
{ [ dup 0 < ] [ ~rel ] }
[ ~abs ]
M: complex log >polar swap flog swap rect> ;
-: cos ( x -- y )
- dup complex? [
- >float-rect 2dup
- fcosh swap fcos * -rot
- fsinh swap fsin neg * rect>
- ] [ fcos ] if ; foldable
+GENERIC: cos ( x -- y ) foldable
+
+M: complex cos
+ >float-rect
+ [ [ fcos ] [ fcosh ] bi* * ]
+ [ [ fsin neg ] [ fsinh ] bi* * ] 2bi rect> ;
+
+M: real cos fcos ;
: sec ( x -- y ) cos recip ; inline
-: cosh ( x -- y )
- dup complex? [
- >float-rect 2dup
- fcos swap fcosh * -rot
- fsin swap fsinh * rect>
- ] [ fcosh ] if ; foldable
+GENERIC: cosh ( x -- y ) foldable
+
+M: complex cosh
+ >float-rect
+ [ [ fcosh ] [ fcos ] bi* * ]
+ [ [ fsinh ] [ fsin ] bi* * ] 2bi rect> ;
+
+M: real cosh fcosh ;
: sech ( x -- y ) cosh recip ; inline
-: sin ( x -- y )
- dup complex? [
- >float-rect 2dup
- fcosh swap fsin * -rot
- fsinh swap fcos * rect>
- ] [ fsin ] if ; foldable
+GENERIC: sin ( x -- y ) foldable
+
+M: complex sin
+ >float-rect
+ [ [ fsin ] [ fcosh ] bi* * ]
+ [ [ fcos ] [ fsinh ] bi* * ] 2bi rect> ;
+
+M: real sin fsin ;
: cosec ( x -- y ) sin recip ; inline
-: sinh ( x -- y )
- dup complex? [
- >float-rect 2dup
- fcos swap fsinh * -rot
- fsin swap fcosh * rect>
- ] [ fsinh ] if ; foldable
+GENERIC: sinh ( x -- y ) foldable
+
+M: complex sinh
+ >float-rect
+ [ [ fsinh ] [ fcos ] bi* * ]
+ [ [ fcosh ] [ fsin ] bi* * ] 2bi rect> ;
+
+M: real sinh fsinh ;
: cosech ( x -- y ) sinh recip ; inline
-: tan ( x -- y )
- dup complex? [ dup sin swap cos / ] [ ftan ] if ; inline
+GENERIC: tan ( x -- y ) foldable
+
+M: complex tan [ sin ] [ cos ] bi / ;
+
+M: real tan ftan ;
-: tanh ( x -- y )
- dup complex? [ dup sinh swap cosh / ] [ ftanh ] if ; inline
+GENERIC: tanh ( x -- y ) foldable
+
+M: complex tanh [ sinh ] [ cosh ] bi / ;
+
+M: real tanh ftanh ;
: cot ( x -- y ) tan recip ; inline
: acosech ( x -- y ) recip asinh ; inline
: atanh ( x -- y )
- dup 1+ swap 1- neg / log 2 / ; inline
+ [ 1+ ] [ 1- neg ] bi / log 2 / ; inline
: acoth ( x -- y ) recip atanh ; inline
dup [-1,1]? [ facos ] [ asin pi 2 / swap - ] if ;
inline
-: atan ( x -- y )
- dup complex? [ i* atanh i* ] [ fatan ] if ; inline
+GENERIC: atan ( x -- y ) foldable
+
+M: complex atan i* atanh i* ;
+
+M: real atan fatan ;
: asec ( x -- y ) recip acos ; inline
{ $values { "rect" "a new " { $link rect } } }
{ $description "Creates a rectangle located at the origin with zero dimensions." } ;
+ARTICLE: "math.geometry.rect" "Rectangles"
+"The " { $vocab-link "math.geometry.rect" } " vocabulary defines a rectangle data type and operations on them."
+{ $subsection rect }
+"Rectangles can be taken apart:"
+{ $subsection rect-loc }
+{ $subsection rect-dim }
+{ $subsection rect-bounds }
+{ $subsection rect-extent }
+"New rectangles can be created:"
+{ $subsection <zero-rect> }
+{ $subsection <rect> }
+{ $subsection <extent-rect> }
+"More utility words for working with rectangles:"
+{ $subsection offset-rect }
+{ $subsection rect-intersect }
+{ $subsection intersects? } ;
+
+ABOUT: "math.geometry.rect"
over rect-loc v+ swap rect-dim <rect> ;
: (rect-intersect) ( rect rect -- array array )
- 2rect-extent vmin >r vmax r> ;
+ 2rect-extent [ vmax ] [ vmin ] 2bi* ;
: rect-intersect ( rect1 rect2 -- newrect )
(rect-intersect) <extent-rect> ;
(rect-intersect) [v-] { 0 0 } = ;
: (rect-union) ( rect rect -- array array )
- 2rect-extent vmax >r vmin r> ;
+ 2rect-extent [ vmin ] [ vmax ] 2bi* ;
: rect-union ( rect1 rect2 -- newrect )
(rect-union) <extent-rect> ;
{ $subsection interval-bitnot }
{ $subsection interval-recip }
{ $subsection interval-2/ }
-{ $subsection interval-abs } ;
+{ $subsection interval-abs }
+{ $subsection interval-log2 } ;
ARTICLE: "math-intervals-sets" "Set-theoretic operations on intervals"
{ $subsection interval-contains? }
{ $values { "i1" interval } { "i2" interval } }
{ $description "Absolute value of an interval." } ;
+HELP: interval-log2
+{ $values { "i1" interval } { "i2" interval } }
+{ $description "Integer-valued Base-2 logarithm of an interval." } ;
+
HELP: interval-intersect
{ $values { "i1" interval } { "i2" interval } { "i3" "an " { $link interval } " or " { $link f } } }
{ $description "Outputs the set-theoretic intersection of " { $snippet "i1" } " and " { $snippet "i2" } ". If " { $snippet "i1" } " and " { $snippet "i2" } " do not intersect, outputs " { $link f } "." } ;
! See http://factorcode.org/license.txt for BSD license.
! Based on Slate's src/unfinished/interval.slate by Brian Rice.
USING: accessors kernel sequences arrays math math.order
-combinators generic ;
+combinators generic layouts ;
IN: math.intervals
SYMBOL: empty-interval
TUPLE: interval { from read-only } { to read-only } ;
: <interval> ( from to -- int )
- over first over first {
+ 2dup [ first ] bi@ {
{ [ 2dup > ] [ 2drop 2drop empty-interval ] }
{ [ 2dup = ] [
- 2drop over second over second and
+ 2drop 2dup [ second ] both?
[ interval boa ] [ 2drop empty-interval ] if
] }
[ 2drop interval boa ]
: closed-point ( n -- endpoint ) t 2array ;
: [a,b] ( a b -- interval )
- >r closed-point r> closed-point <interval> ; foldable
+ [ closed-point ] dip closed-point <interval> ; foldable
: (a,b) ( a b -- interval )
- >r open-point r> open-point <interval> ; foldable
+ [ open-point ] dip open-point <interval> ; foldable
: [a,b) ( a b -- interval )
- >r closed-point r> open-point <interval> ; foldable
+ [ closed-point ] dip open-point <interval> ; foldable
: (a,b] ( a b -- interval )
- >r open-point r> closed-point <interval> ; foldable
+ [ open-point ] dip closed-point <interval> ; foldable
: [a,a] ( a -- interval )
closed-point dup <interval> ; foldable
: [-inf,inf] ( -- interval ) full-interval ; inline
: compare-endpoints ( p1 p2 quot -- ? )
- >r over first over first r> call [
+ [ 2dup [ first ] bi@ ] dip call [
2drop t
] [
- over first over first = [
- swap second swap second not or
+ 2dup [ first ] bi@ = [
+ [ second ] bi@ not or
] [
2drop f
] if
] if ;
: (interval-op) ( p1 p2 quot -- p3 )
- [ [ first ] [ first ] [ ] tri* call ]
+ [ [ first ] [ first ] [ call ] tri* ]
[ drop [ second ] both? ]
3bi 2array ; inline
drop f
] [
interval>points
- 2dup [ second ] bi@ and
+ 2dup [ second ] both?
[ [ first ] bi@ = ]
[ 2drop f ] if
] if ;
dup [ interval>points [ first ] bi@ [a,b] ] when ;
: interval-integer-op ( i1 i2 quot -- i3 )
- >r 2dup
- [ interval>points [ first integer? ] both? ] both?
- r> [ 2drop [-inf,inf] ] if ; inline
+ [
+ 2dup [ interval>points [ first integer? ] both? ] both?
+ ] dip [ 2drop [-inf,inf] ] if ; inline
: interval-shift ( i1 i2 -- i3 )
#! Inaccurate; could be tighter
2tri and and ;
: (interval<) ( i1 i2 -- i1 i2 ? )
- over from>> over from>> endpoint< ;
+ 2dup [ from>> ] bi@ endpoint< ;
: interval< ( i1 i2 -- ? )
{
} cond 2nip ;
: left-endpoint-<= ( i1 i2 -- ? )
- >r from>> r> to>> = ;
+ [ from>> ] dip to>> = ;
: right-endpoint-<= ( i1 i2 -- ? )
- >r to>> r> from>> = ;
+ [ to>> ] dip from>> = ;
: interval<= ( i1 i2 -- ? )
{
2dup [ interval-nonnegative? ] both?
[
[ interval>points [ first ] bi@ ] bi@
- 4array supremum 0 swap next-power-of-2 [a,b]
+ 4array supremum 0 swap >integer next-power-of-2 [a,b]
] [ 2drop [-inf,inf] ] if
] do-empty-interval ;
#! Inaccurate.
interval-bitor ;
+: interval-log2 ( i1 -- i2 )
+ {
+ { empty-interval [ empty-interval ] }
+ { full-interval [ 0 [a,inf] ] }
+ [
+ to>> first 1 max dup most-positive-fixnum >
+ [ drop full-interval interval-log2 ]
+ [ 1+ >integer log2 0 swap [a,b] ]
+ if
+ ]
+ } case ;
+
: assume< ( i1 i2 -- i3 )
dup special-interval? [ drop ] [
to>> first [-inf,a) interval-intersect
: facos ( x -- y )
"double" "libm" "acos" { "double" } alien-invoke ;
- foldable
+ inline
: fasin ( x -- y )
"double" "libm" "asin" { "double" } alien-invoke ;
- foldable
+ inline
: fatan ( x -- y )
"double" "libm" "atan" { "double" } alien-invoke ;
- foldable
+ inline
: fatan2 ( x y -- z )
"double" "libm" "atan2" { "double" "double" } alien-invoke ;
- foldable
+ inline
: fcos ( x -- y )
"double" "libm" "cos" { "double" } alien-invoke ;
- foldable
+ inline
: fsin ( x -- y )
"double" "libm" "sin" { "double" } alien-invoke ;
- foldable
+ inline
: ftan ( x -- y )
"double" "libm" "tan" { "double" } alien-invoke ;
- foldable
+ inline
: fcosh ( x -- y )
"double" "libm" "cosh" { "double" } alien-invoke ;
- foldable
+ inline
: fsinh ( x -- y )
"double" "libm" "sinh" { "double" } alien-invoke ;
- foldable
+ inline
: ftanh ( x -- y )
"double" "libm" "tanh" { "double" } alien-invoke ;
- foldable
+ inline
: fexp ( x -- y )
"double" "libm" "exp" { "double" } alien-invoke ;
- foldable
+ inline
: flog ( x -- y )
"double" "libm" "log" { "double" } alien-invoke ;
- foldable
+ inline
: fpow ( x y -- z )
"double" "libm" "pow" { "double" "double" } alien-invoke ;
- foldable
+ inline
: fsqrt ( x -- y )
"double" "libm" "sqrt" { "double" } alien-invoke ;
- foldable
+ inline
! Windows doesn't have these...
: facosh ( x -- y )
"double" "libm" "acosh" { "double" } alien-invoke ;
- foldable
+ inline
: fasinh ( x -- y )
"double" "libm" "asinh" { "double" } alien-invoke ;
- foldable
+ inline
: fatanh ( x -- y )
"double" "libm" "atanh" { "double" } alien-invoke ;
- foldable
+ inline
[ f ] [ \ number= fixnum object math-both-known? ] unit-test
[ t ] [ \ number= integer fixnum math-both-known? ] unit-test
[ f ] [ \ >fixnum \ shift derived-ops memq? ] unit-test
+[ f ] [ \ >integer \ /i derived-ops memq? ] unit-test
+[ t ] [ \ fixnum-shift \ shift derived-ops memq? ] unit-test
[ { integer fixnum } ] [ \ +-integer-fixnum integer-op-input-classes ] unit-test
[ { fixnum fixnum } ] [ \ fixnum+ integer-op-input-classes ] unit-test
[ fixnum-bitnot ] [ \ bitnot modular-variant ] unit-test
[ fixnum+fast ] [ \ fixnum+ modular-variant ] unit-test
[ fixnum+fast ] [ \ fixnum+fast modular-variant ] unit-test
-
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel kernel.private math math.private words
-sequences parser namespaces make assocs quotations arrays locals
+sequences parser namespaces make assocs quotations arrays
generic generic.math hashtables effects compiler.units
-classes.algebra ;
+classes.algebra fry combinators ;
IN: math.partial-dispatch
PREDICATE: math-partial < word
{ fixnum- fixnum-fast }
{ fixnum* fixnum*fast }
{ fixnum-shift fixnum-shift-fast }
+ { fixnum/i fixnum/i-fast }
+ { fixnum/mod fixnum/mod-fast }
} at ;
: modular-variant ( op -- fast-op )
{ bitnot fixnum-bitnot }
} at swap or ;
-:: fixnum-integer-op ( a b fix-word big-word -- c )
- b tag 0 eq? [
- a b fix-word execute
- ] [
- a fixnum>bignum b big-word execute
- ] if ; inline
-
-:: integer-fixnum-op ( a b fix-word big-word -- c )
- a tag 0 eq? [
- a b fix-word execute
- ] [
- a b fixnum>bignum big-word execute
- ] if ; inline
+: integer-fixnum-op-quot ( fix-word big-word -- quot )
+ [
+ [ over fixnum? ] %
+ [ '[ _ execute ] , ]
+ [ '[ fixnum>bignum _ execute ] , ] bi*
+ \ if ,
+ ] [ ] make ;
-:: integer-integer-op ( a b fix-word big-word -- c )
- b tag 0 eq? [
- a b fix-word big-word integer-fixnum-op
- ] [
- a dup tag 0 eq? [ fixnum>bignum ] when
- b big-word execute
- ] if ; inline
+: fixnum-integer-op-quot ( fix-word big-word -- quot )
+ [
+ [ dup fixnum? ] %
+ [ '[ _ execute ] , ]
+ [ '[ [ fixnum>bignum ] dip _ execute ] , ] bi*
+ \ if ,
+ ] [ ] make ;
-: integer-op-combinator ( triple -- word )
+: integer-integer-op-quot ( fix-word big-word -- quot )
[
- [ second name>> % "-" % ]
- [ third name>> % "-op" % ]
- bi
- ] "" make "math.partial-dispatch" lookup ;
+ [ dup fixnum? ] %
+ 2dup integer-fixnum-op-quot ,
+ [
+ [ over fixnum? [ [ fixnum>bignum ] dip ] when ] %
+ nip ,
+ ] [ ] make ,
+ \ if ,
+ ] [ ] make ;
: integer-op-word ( triple -- word )
[ name>> ] map "-" join "math.partial-dispatch" create ;
-: integer-op-quot ( triple fix-word big-word -- quot )
- rot integer-op-combinator 1quotation 2curry ;
+: integer-op-quot ( fix-word big-word triple -- quot )
+ [ second ] [ third ] bi 2array {
+ { { fixnum integer } [ fixnum-integer-op-quot ] }
+ { { integer fixnum } [ integer-fixnum-op-quot ] }
+ { { integer integer } [ integer-integer-op-quot ] }
+ } case ;
-: define-integer-op-word ( triple fix-word big-word -- )
+: define-integer-op-word ( fix-word big-word triple -- )
[
- [ 2drop integer-op-word ] [ integer-op-quot ] 3bi
+ [ 2nip integer-op-word ] [ integer-op-quot ] 3bi
(( x y -- z )) define-declared
] [
- 2drop
+ 2nip
[ integer-op-word ] keep
"derived-from" set-word-prop
] 3bi ;
: define-integer-op-words ( triples fix-word big-word -- )
- [ define-integer-op-word ] 2curry each ;
+ '[ [ _ _ ] dip define-integer-op-word ] each ;
: integer-op-triples ( word -- triples )
{
{ fixnum integer }
{ integer fixnum }
{ integer integer }
- } swap [ prefix ] curry map ;
+ } swap '[ _ prefix ] map ;
: define-integer-ops ( word fix-word big-word -- )
[
{ fixnum bignum float }
[ [ dup 3array ] [ swap method ] 2bi ] with { } map>assoc
[ nip ] assoc-filter
- [ def>> peek ] assoc-map % ;
+ [ def>> ] assoc-map
+ [ nip length 1 = ] assoc-filter
+ [ first ] assoc-map % ;
SYMBOL: math-ops
: math-method* ( word left right -- quot )
3dup math-op
- [ >r 3drop r> 1quotation ] [ drop math-method ] if ;
+ [ [ 3drop ] dip 1quotation ] [ drop math-method ] if ;
: math-both-known? ( word left right -- ? )
3dup math-op
[ drop math-class-max swap specific-method >boolean ] if ;
: (derived-ops) ( word assoc -- words )
- swap [ rot first eq? nip ] curry assoc-filter ;
+ swap '[ swap first _ eq? nip ] assoc-filter ;
: derived-ops ( word -- words )
[ 1array ] [ math-ops get (derived-ops) values ] bi append ;
: integer-derived-ops ( word -- words )
[ math-ops get (derived-ops) ] [ fast-math-ops get (derived-ops) ] bi
[
- [
+ [
drop
[ second integer class<= ]
[ third integer class<= ]
] bi@ append ;
: each-derived-op ( word quot -- )
- >r derived-ops r> each ; inline
+ [ derived-ops ] dip each ; inline
: each-fast-derived-op ( word quot -- )
- >r fast-derived-ops r> each ; inline
+ [ fast-derived-ops ] dip each ; inline
: each-integer-derived-op ( word quot -- )
- >r integer-derived-ops r> each ; inline
+ [ integer-derived-ops ] dip each ; inline
[
[
\ + define-math-ops
\ - define-math-ops
\ * define-math-ops
- \ shift define-math-ops
\ mod define-math-ops
\ /i define-math-ops
\ >= define-math-ops
\ number= define-math-ops
+ { { shift bignum bignum } bignum-shift } ,
+ { { shift fixnum fixnum } fixnum-shift } ,
+
\ + \ fixnum+ \ bignum+ define-integer-ops
\ - \ fixnum- \ bignum- define-integer-ops
\ * \ fixnum* \ bignum* define-integer-ops
: rise ( pt2 pt1 -- n ) [ second ] bi@ - ;
: run ( pt2 pt1 -- n ) [ first ] bi@ - ;
: slope ( pt pt -- slope ) [ rise ] [ run ] 2bi / ;
-: distance ( point point -- float ) v- norm ;
: midpoint ( point point -- point ) v+ 2 v/n ;
: linear-solution ( pt pt -- x ) [ drop first2 ] [ slope ] 2bi / - ;
\ No newline at end of file
--- /dev/null
+Doug Coleman
--- /dev/null
+USING: help.markup help.syntax math sequences ;
+IN: math.polynomials
+
+ARTICLE: "polynomials" "Polynomials"
+"A polynomial is a vector with the highest powers on the right:"
+{ $code "{ 1 1 0 1 } -> 1 + x + x^3" "{ } -> 0" }
+"Numerous words are defined to help with polynomial arithmetic:"
+{ $subsection p= }
+{ $subsection p+ }
+{ $subsection p- }
+{ $subsection p* }
+{ $subsection p-sq }
+{ $subsection powers }
+{ $subsection n*p }
+{ $subsection p/mod }
+{ $subsection pgcd }
+{ $subsection polyval }
+{ $subsection pdiff }
+{ $subsection pextend-conv }
+{ $subsection ptrim }
+{ $subsection 2ptrim } ;
+
+ABOUT: "polynomials"
+
+HELP: powers
+{ $values { "n" integer } { "x" number } { "seq" sequence } }
+{ $description "Output a sequence having " { $snippet "n" } " elements in the format: " { $snippet "{ 1 x x^2 x^3 ... }" } "." }
+{ $examples { $example "USING: math.polynomials prettyprint ;" "4 2 powers ." "{ 1 2 4 8 }" } } ;
+
+HELP: p=
+{ $values { "p" "a polynomial" } { "q" "a polynomial" } { "?" "a boolean" } }
+{ $description "Tests if two polynomials are equal." }
+{ $examples { $example "USING: math.polynomials prettyprint ;" "{ 0 1 } { 0 1 0 } p= ." "t" } } ;
+
+HELP: ptrim
+{ $values { "p" "a polynomial" } { "p" "a polynomial" } }
+{ $description "Trims excess zeros from a polynomial." }
+{ $examples { $example "USING: math.polynomials prettyprint ;" "{ 0 1 0 0 } ptrim ." "{ 0 1 }" } } ;
+
+HELP: 2ptrim
+{ $values { "p" "a polynomial" } { "q" "a polynomial" } { "p" "a polynomial" } { "q" "a polynomial" } }
+{ $description "Trims excess zeros from two polynomials." }
+{ $examples { $example "USING: kernel math.polynomials prettyprint ;" "{ 0 1 0 0 } { 1 0 0 } 2ptrim [ . ] bi@" "{ 0 1 }\n{ 1 }" } } ;
+
+HELP: p+
+{ $values { "p" "a polynomial" } { "q" "a polynomial" } { "r" "a polynomial" } }
+{ $description "Adds " { $snippet "p" } " and " { $snippet "q" } " component-wise." }
+{ $examples { $example "USING: math.polynomials prettyprint ;" "{ 1 0 1 } { 0 1 } p+ ." "{ 1 1 1 }" } } ;
+
+HELP: p-
+{ $values { "p" "a polynomial" } { "q" "a polynomial" } { "r" "a polynomial" } }
+{ $description "Subtracts " { $snippet "q" } " from " { $snippet "p" } " component-wise." }
+{ $examples { $example "USING: math.polynomials prettyprint ;" "{ 1 1 1 } { 0 1 } p- ." "{ 1 0 1 }" } } ;
+
+HELP: n*p
+{ $values { "n" number } { "p" "a polynomial" } { "n*p" "a polynomial" } }
+{ $description "Multiplies each element of " { $snippet "p" } " by " { $snippet "n" } "." }
+{ $examples { $example "USING: math.polynomials prettyprint ;" "4 { 3 0 1 } n*p ." "{ 12 0 4 }" } } ;
+
+HELP: pextend-conv
+{ $values { "p" "a polynomial" } { "q" "a polynomial" } { "p" "a polynomial" } { "q" "a polynomial" } }
+{ $description "Convulution, extending to " { $snippet "p_m + q_n - 1" } "." }
+{ $examples { $example "USING: kernel math.polynomials prettyprint ;" "{ 1 0 1 } { 0 1 } pextend-conv [ . ] bi@" "V{ 1 0 1 0 }\nV{ 0 1 0 0 }" } } ;
+
+HELP: p*
+{ $values { "p" "a polynomial" } { "q" "a polynomial" } { "r" "a polynomial" } }
+{ $description "Multiplies two polynomials." }
+{ $examples { $example "USING: math.polynomials prettyprint ;" "{ 1 2 3 0 0 0 } { 1 2 0 0 } p* ." "{ 1 4 7 6 0 0 0 0 0 }" } } ;
+
+HELP: p-sq
+{ $values { "p" "a polynomial" } { "p^2" "a polynomial" } }
+{ $description "Squares a polynomial." }
+{ $examples { $example "USING: math.polynomials prettyprint ;" "{ 1 2 0 } p-sq ." "{ 1 4 4 0 0 }" } } ;
+
+HELP: p/mod
+{ $values { "p" "a polynomial" } { "q" "a polynomial" } { "z" "a polynomial" } { "w" "a polynomial" } }
+{ $description "Computes to quotient " { $snippet "z" } " and remainder " { $snippet "w" } " of dividing " { $snippet "p" } " by " { $snippet "q" } "." }
+{ $examples { $example "USING: kernel math.polynomials prettyprint ;" "{ 1 1 1 1 } { 3 1 } p/mod [ . ] bi@" "V{ 7 -2 1 }\nV{ -20 0 0 }" } } ;
+
+HELP: pgcd
+{ $values { "p" "a polynomial" } { "q" "a polynomial" } { "a" "a polynomial" } { "d" "a polynomial" } }
+{ $description "Computes the greatest common divisor " { $snippet "d" } " of " { $snippet "p" } " and " { $snippet "q" } ", and another value " { $snippet "a" } " satisfying:" { $code "a*q = d mod p" } }
+{ $notes "GCD in the case of polynomials is a monic polynomial of the highest possible degree that divides into both " { $snippet "p" } " and " { $snippet "q" } "." }
+{ $examples
+ { $example "USING: kernel math.polynomials prettyprint ;"
+ "{ 1 1 1 1 } { 1 1 } pgcd [ . ] bi@"
+ "{ 0 0 }\n{ 1 1 }"
+ }
+} ;
+
+HELP: pdiff
+{ $values { "p" "a polynomial" } { "p'" "a polynomial" } }
+{ $description "Finds the derivative of " { $snippet "p" } "." } ;
+
+HELP: polyval
+{ $values { "p" "a polynomial" } { "x" number } { "p[x]" number } }
+{ $description "Evaluate " { $snippet "p" } " with the input " { $snippet "x" } "." }
+{ $examples { $example "USING: math.polynomials prettyprint ;" "{ 1 0 1 } 2 polyval ." "5" } } ;
+
--- /dev/null
+USING: kernel math math.polynomials tools.test ;
+IN: math.polynomials.tests
+
+[ { 0 1 } ] [ { 0 1 0 0 } ptrim ] unit-test
+[ { 1 } ] [ { 1 0 0 } ptrim ] unit-test
+[ { 0 } ] [ { 0 } ptrim ] unit-test
+[ { 3 10 8 } ] [ { 1 2 } { 3 4 } p* ] unit-test
+[ { 3 10 8 } ] [ { 3 4 } { 1 2 } p* ] unit-test
+[ { 0 0 0 0 0 0 0 0 0 0 } ] [ { 0 0 0 } { 0 0 0 0 0 0 0 0 } p* ] unit-test
+[ { 0 1 } ] [ { 0 1 } { 1 } p* ] unit-test
+[ { 0 } ] [ { } { } p* ] unit-test
+[ { 0 } ] [ { 0 } { } p* ] unit-test
+[ { 0 } ] [ { } { 0 } p* ] unit-test
+[ { 0 0 0 } ] [ { 0 0 0 } { 0 0 0 } p+ ] unit-test
+[ { 0 0 0 } ] [ { 0 0 0 } { 0 0 0 } p- ] unit-test
+[ { 0 0 0 } ] [ 4 { 0 0 0 } n*p ] unit-test
+[ { 4 8 0 12 } ] [ 4 { 1 2 0 3 } n*p ] unit-test
+[ { 1 4 7 6 0 0 0 0 0 } ] [ { 1 2 3 0 0 0 } { 1 2 0 0 } p* ] unit-test
+[ V{ 7 -2 1 } V{ -20 0 0 } ] [ { 1 1 1 1 } { 3 1 } p/mod ] unit-test
+[ V{ 0 0 } V{ 1 1 } ] [ { 1 1 } { 1 1 1 1 } p/mod ] unit-test
+[ V{ 1 0 1 } V{ 0 0 0 } ] [ { 1 1 1 1 } { 1 1 } p/mod ] unit-test
+[ V{ 1 0 1 } V{ 0 0 0 } ] [ { 1 1 1 1 } { 1 1 0 0 0 0 0 0 } p/mod ] unit-test
+[ V{ 1 0 1 } V{ 0 0 0 } ] [ { 1 1 1 1 0 0 0 0 } { 1 1 0 0 } p/mod ] unit-test
+[ V{ 5.0 } V{ 0 } ] [ { 10.0 } { 2.0 } p/mod ] unit-test
+[ V{ 15/16 } V{ 0 } ] [ { 3/4 } { 4/5 } p/mod ] unit-test
+[ t ] [ { 0 1 } { 0 1 0 } p= ] unit-test
+[ f ] [ { 0 0 1 } { 0 1 0 } p= ] unit-test
+[ t ] [ { 1 1 1 } { 1 1 1 } p= ] unit-test
+[ { 0 0 } { 1 1 } ] [ { 1 1 1 1 } { 1 1 } pgcd ] unit-test
+
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays kernel make math math.order math.vectors sequences shuffle
+ splitting vectors ;
+IN: math.polynomials
+
+<PRIVATE
+
+: 2pad-left ( p q n -- p q ) [ 0 pad-left ] curry bi@ ;
+: 2pad-right ( p q n -- p q ) [ 0 pad-right ] curry bi@ ;
+: pextend ( p q -- p q ) 2dup [ length ] bi@ max 2pad-right ;
+: pextend-left ( p q -- p q ) 2dup [ length ] bi@ max 2pad-left ;
+: unempty ( seq -- seq ) [ { 0 } ] when-empty ;
+: 2unempty ( seq seq -- seq seq ) [ unempty ] bi@ ;
+
+PRIVATE>
+
+: powers ( n x -- seq )
+ <array> 1 [ * ] accumulate nip ;
+
+: p= ( p q -- ? ) pextend = ;
+
+: ptrim ( p -- p )
+ dup length 1 = [ [ zero? ] trim-right ] unless ;
+
+: 2ptrim ( p q -- p q ) [ ptrim ] bi@ ;
+: p+ ( p q -- r ) pextend v+ ;
+: p- ( p q -- r ) pextend v- ;
+: n*p ( n p -- n*p ) n*v ;
+
+: pextend-conv ( p q -- p q )
+ 2dup [ length ] bi@ + 1- 2pad-right [ >vector ] bi@ ;
+
+: p* ( p q -- r )
+ 2unempty pextend-conv <reversed> dup length
+ [ over length pick <slice> pick [ * ] 2map sum ] map 2nip reverse ;
+
+: p-sq ( p -- p^2 )
+ dup p* ;
+
+<PRIVATE
+
+: p/mod-setup ( p p -- p p n )
+ 2ptrim
+ 2dup [ length ] bi@ -
+ dup 1 < [ drop 1 ] when
+ [ over length + 0 pad-left pextend ] keep 1+ ;
+
+: /-last ( seq seq -- a )
+ #! divide the last two numbers in the sequences
+ [ peek ] bi@ / ;
+
+: (p/mod) ( p p -- p p )
+ 2dup /-last
+ 2dup , n*p swapd
+ p- >vector
+ dup pop* swap rest-slice ;
+
+PRIVATE>
+
+: p/mod ( p q -- z w )
+ p/mod-setup [ [ (p/mod) ] times ] V{ } make
+ reverse nip swap 2ptrim pextend ;
+
+<PRIVATE
+
+: (pgcd) ( b a y x -- a d )
+ dup V{ 0 } clone p= [
+ drop nip
+ ] [
+ tuck p/mod [ pick p* swap [ swapd p- ] dip ] dip (pgcd)
+ ] if ;
+
+PRIVATE>
+
+: pgcd ( p q -- a d )
+ swap V{ 0 } clone V{ 1 } clone 2swap (pgcd) [ >array ] bi@ ;
+
+: pdiff ( p -- p' )
+ dup length v* { 0 } ?head drop ;
+
+: polyval ( p x -- p[x] )
+ [ dup length ] dip powers v. ;
+
--- /dev/null
+Polynomial arithmetic
--- /dev/null
+Slava Pestov
--- /dev/null
+USING: help.markup help.syntax math math.vectors vectors ;
+IN: math.quaternions
+
+HELP: q*
+{ $values { "u" "a quaternion" } { "v" "a quaternion" } { "u*v" "a quaternion" } }
+{ $description "Multiply quaternions." }
+{ $examples { $example "USING: math.quaternions prettyprint ;" "{ C{ 0 1 } 0 } { 0 1 } q* ." "{ 0 C{ 0 1 } }" } } ;
+
+HELP: qconjugate
+{ $values { "u" "a quaternion" } { "u'" "a quaternion" } }
+{ $description "Quaternion conjugate." } ;
+
+HELP: qrecip
+{ $values { "u" "a quaternion" } { "1/u" "a quaternion" } }
+{ $description "Quaternion inverse." } ;
+
+HELP: q/
+{ $values { "u" "a quaternion" } { "v" "a quaternion" } { "u/v" "a quaternion" } }
+{ $description "Divide quaternions." }
+{ $examples { $example "USING: math.quaternions prettyprint ;" "{ 0 C{ 0 1 } } { 0 1 } q/ ." "{ C{ 0 1 } 0 }" } } ;
+
+HELP: q*n
+{ $values { "q" "a quaternion" } { "n" number } { "q" "a quaternion" } }
+{ $description "Multiplies each element of " { $snippet "q" } " by " { $snippet "n" } "." }
+{ $notes "You will get the wrong result if you try to multiply a quaternion by a complex number on the right using " { $link v*n } ". Use this word instead."
+ $nl "Note that " { $link v*n } " with a quaternion and a real is okay." } ;
+
+HELP: c>q
+{ $values { "c" number } { "q" "a quaternion" } }
+{ $description "Turn a complex number into a quaternion." }
+{ $examples { $example "USING: math.quaternions prettyprint ;" "C{ 0 1 } c>q ." "{ C{ 0 1 } 0 }" } } ;
+
+HELP: v>q
+{ $values { "v" vector } { "q" "a quaternion" } }
+{ $description "Turn a 3-vector into a quaternion with real part 0." }
+{ $examples { $example "USING: math.quaternions prettyprint ;" "{ 1 0 0 } v>q ." "{ C{ 0 1 } 0 }" } } ;
+
+HELP: q>v
+{ $values { "q" "a quaternion" } { "v" vector } }
+{ $description "Get the vector part of a quaternion, discarding the real part." }
+{ $examples { $example "USING: math.quaternions prettyprint ;" "{ C{ 0 1 } 0 } q>v ." "{ 1 0 0 }" } } ;
+
+HELP: euler
+{ $values { "phi" number } { "theta" number } { "psi" number } { "q" "a quaternion" } }
+{ $description "Convert a rotation given by Euler angles (phi, theta, and psi) to a quaternion." } ;
+
--- /dev/null
+IN: math.quaternions.tests
+USING: tools.test math.quaternions kernel math.vectors
+math.constants ;
+
+[ 1.0 ] [ qi norm ] unit-test
+[ 1.0 ] [ qj norm ] unit-test
+[ 1.0 ] [ qk norm ] unit-test
+[ 1.0 ] [ q1 norm ] unit-test
+[ 0.0 ] [ q0 norm ] unit-test
+[ t ] [ qi qj q* qk = ] unit-test
+[ t ] [ qj qk q* qi = ] unit-test
+[ t ] [ qk qi q* qj = ] unit-test
+[ t ] [ qi qi q* q1 v+ q0 = ] unit-test
+[ t ] [ qj qj q* q1 v+ q0 = ] unit-test
+[ t ] [ qk qk q* q1 v+ q0 = ] unit-test
+[ t ] [ qi qj qk q* q* q1 v+ q0 = ] unit-test
+[ t ] [ C{ 0 1 } qj n*v qk = ] unit-test
+[ t ] [ qj C{ 0 1 } q*n qk v+ q0 = ] unit-test
+[ t ] [ qk qj q/ qi = ] unit-test
+[ t ] [ qi qk q/ qj = ] unit-test
+[ t ] [ qj qi q/ qk = ] unit-test
+[ t ] [ qi q>v v>q qi = ] unit-test
+[ t ] [ qj q>v v>q qj = ] unit-test
+[ t ] [ qk q>v v>q qk = ] unit-test
+[ t ] [ 1 c>q q1 = ] unit-test
+[ t ] [ C{ 0 1 } c>q qi = ] unit-test
--- /dev/null
+! Copyright (C) 2005, 2007 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays kernel math math.functions math.vectors sequences ;
+IN: math.quaternions
+
+! Everybody's favorite non-commutative skew field, the quaternions!
+
+! Quaternions are represented as pairs of complex numbers, using the
+! identity: (a+bi)+(c+di)j = a+bi+cj+dk.
+
+<PRIVATE
+
+: ** conjugate * ; inline
+
+: 2q ( u v -- u' u'' v' v'' ) [ first2 ] bi@ ; inline
+
+: q*a ( u v -- a ) 2q swapd ** [ * ] dip - ; inline
+
+: q*b ( u v -- b ) 2q [ ** swap ] dip * + ; inline
+
+PRIVATE>
+
+: q* ( u v -- u*v )
+ [ q*a ] [ q*b ] 2bi 2array ;
+
+: qconjugate ( u -- u' )
+ first2 [ conjugate ] [ neg ] bi* 2array ;
+
+: qrecip ( u -- 1/u )
+ qconjugate dup norm-sq v/n ;
+
+: q/ ( u v -- u/v )
+ qrecip q* ;
+
+: q*n ( q n -- q )
+ conjugate v*n ;
+
+: c>q ( c -- q )
+ 0 2array ;
+
+: v>q ( v -- q )
+ first3 rect> [ 0 swap rect> ] dip 2array ;
+
+: q>v ( q -- v )
+ first2 [ imaginary-part ] dip >rect 3array ;
+
+! Zero
+: q0 { 0 0 } ;
+
+! Units
+: q1 { 1 0 } ;
+: qi { C{ 0 1 } 0 } ;
+: qj { 0 1 } ;
+: qk { 0 C{ 0 1 } } ;
+
+! Euler angles
+
+<PRIVATE
+
+: (euler) ( theta unit -- q )
+ [ -0.5 * [ cos c>q ] [ sin ] bi ] dip n*v v- ;
+
+PRIVATE>
+
+: euler ( phi theta psi -- q )
+ [ qi (euler) ] [ qj (euler) ] [ qk (euler) ] tri* q* q* ;
--- /dev/null
+Quaternion arithmetic and Euler angles
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
USING: kernel layouts math math.order namespaces sequences
sequences.private accessors ;
IN: math.ranges
{ step read-only } ;
: <range> ( a b step -- range )
- >r over - r>
- [ / 1+ 0 max >integer ] keep
- range boa ; inline
+ [ over - ] dip [ /i 1+ 0 max ] keep range boa ; inline
M: range length ( seq -- n )
length>> ;
: twiddle 2dup > -1 1 ? ; inline
-: (a, dup roll + -rot ; inline
+: (a, dup [ + ] curry 2dip ; inline
-: ,b) dup neg rot + swap ; inline
+: ,b) dup [ - ] curry dip ; inline
: [a,b] ( a b -- range ) twiddle <range> ; inline
dup 1 number= [ drop ] [ <ratio> ] if ; inline
: scale ( a/b c/d -- a*d b*c )
- 2>fraction >r * swap r> * swap ; inline
+ 2>fraction [ * swap ] dip * swap ; inline
: ratio+d ( a/b c/d -- b*d )
- denominator swap denominator * ; inline
+ [ denominator ] bi@ * ; inline
PRIVATE>
"Division by zero" throw
] [
dup 0 < [ [ neg ] bi@ ] when
- 2dup gcd nip tuck /i >r /i r> fraction>
+ 2dup gcd nip tuck /i [ /i ] dip fraction>
] if ;
M: ratio hashcode*
M: ratio + 2dup scale + -rot ratio+d / ;
M: ratio - 2dup scale - -rot ratio+d / ;
-M: ratio * 2>fraction * >r * r> / ;
+M: ratio * 2>fraction * [ * ] dip / ;
M: ratio / scale / ;
M: ratio /i scale /i ;
M: ratio /f scale /f ;
--- /dev/null
+Doug Coleman
+Michael Judge
--- /dev/null
+USING: help.markup help.syntax debugger ;
+IN: math.statistics
+
+HELP: geometric-mean
+{ $values { "seq" "a sequence of numbers" } { "n" "a non-negative real number"} }
+{ $description "Computes the geometric mean of all elements in " { $snippet "seq" } ". The geometric mean measures the central tendency of a data set that minimizes the effects of extreme values." }
+{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } geometric-mean ." "1.81712059283214" } }
+{ $errors "Throws a " { $link signal-error. } " (square-root of 0) if the sequence is empty." } ;
+
+HELP: harmonic-mean
+{ $values { "seq" "a sequence of numbers" } { "n" "a non-negative real number"} }
+{ $description "Computes the harmonic mean of the elements in " { $snippet "seq" } ". The harmonic mean is appropriate when the average of rates is desired." }
+{ $notes "Positive reals only." }
+{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } harmonic-mean ." "6/11" } }
+{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
+
+HELP: mean
+{ $values { "seq" "a sequence of numbers" } { "n" "a non-negative real number"} }
+{ $description "Computes the arithmetic mean of all elements in " { $snippet "seq" } "." }
+{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } mean ." "2" } }
+{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
+
+HELP: median
+{ $values { "seq" "a sequence of numbers" } { "n" "a non-negative real number"} }
+{ $description "Computes the median of " { $snippet "seq" } " by sorting the sequence from lowest value to highest and outputting the middle one. If there is an even number of elements in the sequence, the median is not unique, so the mean of the two middle values is outputted." }
+{ $examples
+ { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } median ." "2" }
+ { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } median ." "2+1/2" } }
+{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
+
+HELP: range
+{ $values { "seq" "a sequence of numbers" } { "n" "a non-negative real number"} }
+{ $description "Computes the distance of the maximum and minimum values in " { $snippet "seq" } "." }
+{ $examples
+ { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } range ." "2" }
+ { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } range ." "3" } } ;
+
+HELP: std
+{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
+{ $description "Computes the standard deviation of " { $snippet "seq" } ", which is the square root of the variance. It measures how widely spread the values in a sequence are about the mean." }
+{ $examples
+ { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } std ." "1.0" }
+ { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } std ." "1.290994448735806" } } ;
+
+HELP: ste
+ { $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
+ { $description "Computes the standard error of the mean for " { $snippet "seq" } ". It's defined as the standard deviation divided by the square root of the length of the sequence, and measures uncertainty associated with the estimate of the mean." }
+ { $examples
+ { $example "USING: math.statistics prettyprint ;" "{ -2 2 } ste ." "2.0" }
+ { $example "USING: math.statistics prettyprint ;" "{ -2 2 2 } ste ." "1.333333333333333" } } ;
+
+HELP: var
+{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
+{ $description "Computes the variance of " { $snippet "seq" } ". It's a measurement of the spread of values in a sequence. The larger the variance, the larger the distance of values from the mean." }
+{ $notes "If the number of elements in " { $snippet "seq" } " is 1 or less, it outputs 0." }
+{ $examples
+ { $example "USING: math.statistics prettyprint ;" "{ 1 } var ." "0" }
+ { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } var ." "1" }
+ { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } var ." "1+2/3" } } ;
+
--- /dev/null
+USING: kernel math math.functions math.statistics tools.test ;
+IN: math.statistics.tests
+
+[ 1 ] [ { 1 } mean ] unit-test
+[ 3/2 ] [ { 1 2 } mean ] unit-test
+[ 0 ] [ { 0 0 0 } geometric-mean ] unit-test
+[ t ] [ { 2 2 2 2 } geometric-mean 2.0 .0001 ~ ] unit-test
+[ 1.0 ] [ { 1 1 1 } geometric-mean ] unit-test
+[ 1/3 ] [ { 1 1 1 } harmonic-mean ] unit-test
+
+[ 0 ] [ { 1 } range ] unit-test
+[ 89 ] [ { 1 2 30 90 } range ] unit-test
+[ 2 ] [ { 1 2 3 } median ] unit-test
+[ 5/2 ] [ { 1 2 3 4 } median ] unit-test
+
+[ 1 ] [ { 1 2 3 } var ] unit-test
+[ 1.0 ] [ { 1 2 3 } std ] unit-test
+[ t ] [ { 1 2 3 4 } ste 0.6454972243679028 - .0001 < ] unit-test
+
+[ t ] [ { 23.2 33.4 22.5 66.3 44.5 } std 18.1906 - .0001 < ] unit-test
+
+[ 0 ] [ { 1 } var ] unit-test
+[ 0.0 ] [ { 1 } std ] unit-test
+[ 0.0 ] [ { 1 } ste ] unit-test
--- /dev/null
+! Copyright (C) 2008 Doug Coleman, Michael Judge.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays combinators kernel math math.analysis math.functions sequences
+ sequences.lib sorting ;
+IN: math.statistics
+
+: mean ( seq -- n )
+ [ sum ] [ length ] bi / ;
+
+: geometric-mean ( seq -- n )
+ [ length ] [ product ] bi nth-root ;
+
+: harmonic-mean ( seq -- n )
+ [ recip ] sigma recip ;
+
+: median ( seq -- n )
+ natural-sort dup length even? [
+ [ midpoint@ dup 1- 2array ] keep nths mean
+ ] [
+ [ midpoint@ ] keep nth
+ ] if ;
+
+: range ( seq -- n )
+ minmax swap - ;
+
+: var ( seq -- x )
+ #! normalize by N-1
+ dup length 1 <= [
+ drop 0
+ ] [
+ [ [ mean ] keep [ - sq ] with sigma ] keep
+ length 1- /
+ ] if ;
+
+: std ( seq -- x )
+ var sqrt ;
+
+: ste ( seq -- x )
+ [ std ] [ length ] bi sqrt / ;
+
+: ((r)) ( mean(x) mean(y) {x} {y} -- (r) )
+ ! finds sigma((xi-mean(x))(yi-mean(y))
+ 0 [ [ [ pick ] dip swap - ] bi@ * + ] 2reduce 2nip ;
+
+: (r) ( mean(x) mean(y) {x} {y} sx sy -- r )
+ * recip [ [ ((r)) ] keep length 1- / ] dip * ;
+
+: [r] ( {{x,y}...} -- mean(x) mean(y) {x} {y} sx sy )
+ first2 [ [ [ mean ] bi@ ] 2keep ] 2keep [ std ] bi@ ;
+
+: r ( {{x,y}...} -- r )
+ [r] (r) ;
+
+: r^2 ( {{x,y}...} -- r )
+ r sq ;
+
+: least-squares ( {{x,y}...} -- alpha beta )
+ [r] { [ 2dup ] [ ] [ ] [ ] [ ] } spread
+ ! stack is mean(x) mean(y) mean(x) mean(y) {x} {y} sx sy
+ [ (r) ] 2keep ! stack is mean(x) mean(y) r sx sy
+ swap / * ! stack is mean(x) mean(y) beta
+ [ swapd * - ] keep ;
+
--- /dev/null
+Mean, median, standard deviation, and other statistical routines
{ $description "Multiplies each element of " { $snippet "u" } " by " { $snippet "n" } "." } ;
HELP: v*n
-{ $values { "n" "a number" } { "u" "a sequence of numbers" } { "v" "a sequence of numbers" } }
+{ $values { "u" "a sequence of numbers" } { "n" "a number" } { "v" "a sequence of numbers" } }
{ $description "Multiplies each element of " { $snippet "u" } " by " { $snippet "n" } "." } ;
HELP: n/v
: norm ( v -- x ) norm-sq sqrt ;
: normalize ( u -- v ) dup norm v/n ;
+: distance ( u v -- x ) [ - absq ] [ + ] 2map-reduce sqrt ;
+
: set-axis ( u v axis -- w )
- [ >r zero? 2over ? r> swap nth ] map-index 2nip ;
+ [ [ zero? 2over ? ] dip swap nth ] map-index 2nip ;
HINTS: vneg { array } ;
HINTS: norm-sq { array } ;
HINTS: norm { array } ;
HINTS: normalize { array } ;
+HINTS: distance { array array } ;
HINTS: n*v { object array } ;
HINTS: v*n { array object } ;
! Copyright (C) 2007 Slava Pestov, Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
-USING: math kernel memoize tools.test parser
+USING: math kernel memoize tools.test parser generalizations
prettyprint io.streams.string sequences eval ;
IN: memoize.tests
[ 89 ] [ 10 fib ] unit-test
-[ "USING: kernel math memoize ; IN: memoize.tests MEMO: x ( a b c d e -- f g h i j ) >r >r >r >r 1+ r> r> r> r> ;" eval ] must-fail
+[ "USING: kernel math memoize generalizations ; IN: memoize.tests MEMO: x ( a b c d e -- f g h i j ) [ 1+ ] 4 ndip ;" eval ] must-fail
MEMO: see-test ( a -- b ) reverse ;
+++ /dev/null
-Slava Pestov
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: assocs help.markup help.syntax io.streams.string sequences ;
-IN: mime-types
-
-HELP: mime-db
-{ $values
-
- { "seq" sequence } }
-{ $description "Outputs an array where the first element is a MIME type and the rest of the array is file extensions that have that MIME type." } ;
-
-HELP: mime-type
-{ $values
- { "filename" "a filename" }
- { "mime-type" "a MIME type string" } }
-{ $description "Outputs the MIME type associtated with a path by parsing the path's file extension and looking it up in the table returned by " { $link mime-types } "." } ;
-
-HELP: mime-types
-{ $values
-
- { "assoc" assoc } }
-{ $description "Outputs an " { $snippet "assoc" } " made from the data in the " { $link mime-db } " word where the keys are file extensions and the values are the corresponding MIME types." } ;
-
-HELP: nonstandard-mime-types
-{ $values
-
- { "assoc" assoc } }
-{ $description "A list of Factor-specific MIME types that are added to the MIME database loaded from disk." } ;
-
-ARTICLE: "mime-types" "MIME types"
-"The " { $vocab-link "mime-types" } " vocabulary loads a file of MIME types and provides a word to look up the MIME type based on a file extension." $nl
-"Looking up a MIME type:"
-{ $subsection mime-type } ;
-
-ABOUT: "mime-types"
+++ /dev/null
-IN: mime-types.tests
-USING: mime-types tools.test ;
-
-[ "application/postscript" ] [ "foo.ps" mime-type ] unit-test
-[ "application/octet-stream" ] [ "foo.ps.gz" mime-type ] unit-test
-[ "text/plain" ] [ "foo.factor" mime-type ] unit-test
+++ /dev/null
-! Copyright (C) 2004, 2008 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-USING: io.files io.encodings.ascii assocs sequences splitting
-kernel namespaces fry memoize ;
-IN: mime-types
-
-MEMO: mime-db ( -- seq )
- "resource:basis/mime-types/mime.types" ascii file-lines
- [ "#" head? not ] filter [ " \t" split harvest ] map harvest ;
-
-: nonstandard-mime-types ( -- assoc )
- H{
- { "factor" "text/plain" }
- { "cgi" "application/x-cgi-script" }
- { "fhtml" "application/x-factor-server-page" }
- } ;
-
-MEMO: mime-types ( -- assoc )
- [
- mime-db [ unclip '[ [ _ ] dip set ] each ] each
- ] H{ } make-assoc
- nonstandard-mime-types assoc-union ;
-
-: mime-type ( filename -- mime-type )
- file-extension mime-types at "application/octet-stream" or ;
+++ /dev/null
-# This is a comment. I love comments.
-
-# This file controls what Internet media types are sent to the client for
-# given file extension(s). Sending the correct media type to the client
-# is important so they know how to handle the content of the file.
-# Extra types can either be added here or by using an AddType directive
-# in your config files. For more information about Internet media types,
-# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type
-# registry is at <http://www.iana.org/assignments/media-types/>.
-
-# MIME type Extensions
-application/activemessage
-application/andrew-inset ez
-application/applefile
-application/atom+xml atom
-application/atomcat+xml atomcat
-application/atomicmail
-application/atomsvc+xml atomsvc
-application/auth-policy+xml
-application/batch-smtp
-application/beep+xml
-application/cals-1840
-application/ccxml+xml ccxml
-application/cellml+xml
-application/cnrp+xml
-application/commonground
-application/conference-info+xml
-application/cpl+xml
-application/csta+xml
-application/cstadata+xml
-application/cybercash
-application/davmount+xml davmount
-application/dca-rft
-application/dec-dx
-application/dialog-info+xml
-application/dicom
-application/dns
-application/dvcs
-application/ecmascript ecma
-application/edi-consent
-application/edi-x12
-application/edifact
-application/epp+xml
-application/eshop
-application/fastinfoset
-application/fastsoap
-application/fits
-application/font-tdpfr pfr
-application/h224
-application/http
-application/hyperstudio stk
-application/iges
-application/im-iscomposing+xml
-application/index
-application/index.cmd
-application/index.obj
-application/index.response
-application/index.vnd
-application/iotp
-application/ipp
-application/isup
-application/javascript js
-application/json json
-application/kpml-request+xml
-application/kpml-response+xml
-application/mac-binhex40 hqx
-application/mac-compactpro cpt
-application/macwriteii
-application/marc mrc
-application/mathematica ma nb mb
-application/mathml+xml mathml
-application/mbms-associated-procedure-description+xml
-application/mbms-deregister+xml
-application/mbms-envelope+xml
-application/mbms-msk+xml
-application/mbms-msk-response+xml
-application/mbms-protection-description+xml
-application/mbms-reception-report+xml
-application/mbms-register+xml
-application/mbms-register-response+xml
-application/mbms-user-service-description+xml
-application/mbox mbox
-application/mediaservercontrol+xml mscml
-application/mikey
-application/mp4 mp4s
-application/mpeg4-generic
-application/mpeg4-iod
-application/mpeg4-iod-xmt
-application/msword doc dot
-application/mxf mxf
-application/nasdata
-application/news-message-id
-application/news-transmission
-application/nss
-application/ocsp-request
-application/ocsp-response
-application/octet-stream bin dms lha lzh class so iso dmg dist distz pkg bpk dump elc scpt
-application/oda oda
-application/oebps-package+xml
-application/ogg ogg
-application/parityfec
-application/pdf pdf
-application/pgp-encrypted pgp
-application/pgp-keys
-application/pgp-signature asc sig
-application/pics-rules prf
-application/pidf+xml
-application/pkcs10 p10
-application/pkcs7-mime p7m p7c
-application/pkcs7-signature p7s
-application/pkix-cert cer
-application/pkix-crl crl
-application/pkix-pkipath pkipath
-application/pkixcmp pki
-application/pls+xml pls
-application/poc-settings+xml
-application/postscript ai eps ps
-application/prs.alvestrand.titrax-sheet
-application/prs.cww cww
-application/prs.nprend
-application/prs.plucker
-application/qsig
-application/rdf+xml rdf
-application/reginfo+xml rif
-application/relax-ng-compact-syntax rnc
-application/remote-printing
-application/resource-lists+xml rl
-application/riscos
-application/rlmi+xml
-application/rls-services+xml rs
-application/rsd+xml rsd
-application/rss+xml rss
-application/rtf rtf
-application/rtx
-application/samlassertion+xml
-application/samlmetadata+xml
-application/sbml+xml sbml
-application/sdp sdp
-application/set-payment
-application/set-payment-initiation setpay
-application/set-registration
-application/set-registration-initiation setreg
-application/sgml
-application/sgml-open-catalog
-application/shf+xml shf
-application/sieve
-application/simple-filter+xml
-application/simple-message-summary
-application/simplesymbolcontainer
-application/slate
-application/smil
-application/smil+xml smi smil
-application/soap+fastinfoset
-application/soap+xml
-application/spirits-event+xml
-application/srgs gram
-application/srgs+xml grxml
-application/ssml+xml ssml
-application/timestamp-query
-application/timestamp-reply
-application/tve-trigger
-application/vemmi
-application/vividence.scriptfile
-application/vnd.3gpp.bsf+xml
-application/vnd.3gpp.pic-bw-large plb
-application/vnd.3gpp.pic-bw-small psb
-application/vnd.3gpp.pic-bw-var pvb
-application/vnd.3gpp.sms
-application/vnd.3gpp2.bcmcsinfo+xml
-application/vnd.3gpp2.sms
-application/vnd.3m.post-it-notes pwn
-application/vnd.accpac.simply.aso aso
-application/vnd.accpac.simply.imp imp
-application/vnd.acucobol acu
-application/vnd.acucorp atc acutc
-application/vnd.adobe.xdp+xml xdp
-application/vnd.adobe.xfdf xfdf
-application/vnd.aether.imp
-application/vnd.amiga.ami ami
-application/vnd.anser-web-certificate-issue-initiation cii
-application/vnd.anser-web-funds-transfer-initiation fti
-application/vnd.antix.game-component atx
-application/vnd.apple.installer+xml mpkg
-application/vnd.audiograph aep
-application/vnd.autopackage
-application/vnd.avistar+xml
-application/vnd.blueice.multipass mpm
-application/vnd.bmi bmi
-application/vnd.businessobjects rep
-application/vnd.cab-jscript
-application/vnd.canon-cpdl
-application/vnd.canon-lips
-application/vnd.cendio.thinlinc.clientconf
-application/vnd.chemdraw+xml cdxml
-application/vnd.chipnuts.karaoke-mmd mmd
-application/vnd.cinderella cdy
-application/vnd.cirpack.isdn-ext
-application/vnd.claymore cla
-application/vnd.clonk.c4group c4g c4d c4f c4p c4u
-application/vnd.commerce-battelle
-application/vnd.commonspace csp cst
-application/vnd.contact.cmsg cdbcmsg
-application/vnd.cosmocaller cmc
-application/vnd.crick.clicker clkx
-application/vnd.crick.clicker.keyboard clkk
-application/vnd.crick.clicker.palette clkp
-application/vnd.crick.clicker.template clkt
-application/vnd.crick.clicker.wordbank clkw
-application/vnd.criticaltools.wbs+xml wbs
-application/vnd.ctc-posml pml
-application/vnd.cups-pdf
-application/vnd.cups-postscript
-application/vnd.cups-ppd ppd
-application/vnd.cups-raster
-application/vnd.cups-raw
-application/vnd.curl curl
-application/vnd.cybank
-application/vnd.data-vision.rdz rdz
-application/vnd.denovo.fcselayout-link fe_launch
-application/vnd.dna dna
-application/vnd.dolby.mlp mlp
-application/vnd.dpgraph dpg
-application/vnd.dreamfactory dfac
-application/vnd.dvb.esgcontainer
-application/vnd.dvb.ipdcesgaccess
-application/vnd.dxr
-application/vnd.ecdis-update
-application/vnd.ecowin.chart mag
-application/vnd.ecowin.filerequest
-application/vnd.ecowin.fileupdate
-application/vnd.ecowin.series
-application/vnd.ecowin.seriesrequest
-application/vnd.ecowin.seriesupdate
-application/vnd.enliven nml
-application/vnd.epson.esf esf
-application/vnd.epson.msf msf
-application/vnd.epson.quickanime qam
-application/vnd.epson.salt slt
-application/vnd.epson.ssf ssf
-application/vnd.ericsson.quickcall
-application/vnd.eszigno3+xml es3 et3
-application/vnd.eudora.data
-application/vnd.ezpix-album ez2
-application/vnd.ezpix-package ez3
-application/vnd.fdf fdf
-application/vnd.ffsns
-application/vnd.fints
-application/vnd.flographit gph
-application/vnd.fluxtime.clip ftc
-application/vnd.framemaker fm frame maker
-application/vnd.frogans.fnc fnc
-application/vnd.frogans.ltf ltf
-application/vnd.fsc.weblaunch fsc
-application/vnd.fujitsu.oasys oas
-application/vnd.fujitsu.oasys2 oa2
-application/vnd.fujitsu.oasys3 oa3
-application/vnd.fujitsu.oasysgp fg5
-application/vnd.fujitsu.oasysprs bh2
-application/vnd.fujixerox.art-ex
-application/vnd.fujixerox.art4
-application/vnd.fujixerox.hbpl
-application/vnd.fujixerox.ddd ddd
-application/vnd.fujixerox.docuworks xdw
-application/vnd.fujixerox.docuworks.binder xbd
-application/vnd.fut-misnet
-application/vnd.fuzzysheet fzs
-application/vnd.genomatix.tuxedo txd
-application/vnd.google-earth.kml+xml kml
-application/vnd.google-earth.kmz kmz
-application/vnd.grafeq gqf gqs
-application/vnd.gridmp
-application/vnd.groove-account gac
-application/vnd.groove-help ghf
-application/vnd.groove-identity-message gim
-application/vnd.groove-injector grv
-application/vnd.groove-tool-message gtm
-application/vnd.groove-tool-template tpl
-application/vnd.groove-vcard vcg
-application/vnd.handheld-entertainment+xml zmm
-application/vnd.hbci hbci
-application/vnd.hcl-bireports
-application/vnd.hhe.lesson-player les
-application/vnd.hp-hpgl hpgl
-application/vnd.hp-hpid hpid
-application/vnd.hp-hps hps
-application/vnd.hp-jlyt jlt
-application/vnd.hp-pcl pcl
-application/vnd.hp-pclxl pclxl
-application/vnd.httphone
-application/vnd.hzn-3d-crossword x3d
-application/vnd.ibm.afplinedata
-application/vnd.ibm.electronic-media
-application/vnd.ibm.minipay mpy
-application/vnd.ibm.modcap afp listafp list3820
-application/vnd.ibm.rights-management irm
-application/vnd.ibm.secure-container sc
-application/vnd.igloader igl
-application/vnd.immervision-ivp ivp
-application/vnd.immervision-ivu ivu
-application/vnd.informedcontrol.rms+xml
-application/vnd.intercon.formnet xpw xpx
-application/vnd.intertrust.digibox
-application/vnd.intertrust.nncp
-application/vnd.intu.qbo qbo
-application/vnd.intu.qfx qfx
-application/vnd.ipunplugged.rcprofile rcprofile
-application/vnd.irepository.package+xml irp
-application/vnd.is-xpr xpr
-application/vnd.jam jam
-application/vnd.japannet-directory-service
-application/vnd.japannet-jpnstore-wakeup
-application/vnd.japannet-payment-wakeup
-application/vnd.japannet-registration
-application/vnd.japannet-registration-wakeup
-application/vnd.japannet-setstore-wakeup
-application/vnd.japannet-verification
-application/vnd.japannet-verification-wakeup
-application/vnd.jcp.javame.midlet-rms rms
-application/vnd.jisp jisp
-application/vnd.kahootz ktz ktr
-application/vnd.kde.karbon karbon
-application/vnd.kde.kchart chrt
-application/vnd.kde.kformula kfo
-application/vnd.kde.kivio flw
-application/vnd.kde.kontour kon
-application/vnd.kde.kpresenter kpr kpt
-application/vnd.kde.kspread ksp
-application/vnd.kde.kword kwd kwt
-application/vnd.kenameaapp htke
-application/vnd.kidspiration kia
-application/vnd.kinar kne knp
-application/vnd.koan skp skd skt skm
-application/vnd.liberty-request+xml
-application/vnd.llamagraphics.life-balance.desktop lbd
-application/vnd.llamagraphics.life-balance.exchange+xml lbe
-application/vnd.lotus-1-2-3 123
-application/vnd.lotus-approach apr
-application/vnd.lotus-freelance pre
-application/vnd.lotus-notes nsf
-application/vnd.lotus-organizer org
-application/vnd.lotus-screencam scm
-application/vnd.lotus-wordpro lwp
-application/vnd.macports.portpkg portpkg
-application/vnd.marlin.drm.actiontoken+xml
-application/vnd.marlin.drm.conftoken+xml
-application/vnd.marlin.drm.mdcf
-application/vnd.mcd mcd
-application/vnd.medcalcdata mc1
-application/vnd.mediastation.cdkey cdkey
-application/vnd.meridian-slingshot
-application/vnd.mfer mwf
-application/vnd.mfmp mfm
-application/vnd.micrografx.flo flo
-application/vnd.micrografx.igx igx
-application/vnd.mif mif
-application/vnd.minisoft-hp3000-save
-application/vnd.mitsubishi.misty-guard.trustweb
-application/vnd.mobius.daf daf
-application/vnd.mobius.dis dis
-application/vnd.mobius.mbk mbk
-application/vnd.mobius.mqy mqy
-application/vnd.mobius.msl msl
-application/vnd.mobius.plc plc
-application/vnd.mobius.txf txf
-application/vnd.mophun.application mpn
-application/vnd.mophun.certificate mpc
-application/vnd.motorola.flexsuite
-application/vnd.motorola.flexsuite.adsi
-application/vnd.motorola.flexsuite.fis
-application/vnd.motorola.flexsuite.gotap
-application/vnd.motorola.flexsuite.kmr
-application/vnd.motorola.flexsuite.ttc
-application/vnd.motorola.flexsuite.wem
-application/vnd.mozilla.xul+xml xul
-application/vnd.ms-artgalry cil
-application/vnd.ms-asf asf
-application/vnd.ms-cab-compressed cab
-application/vnd.ms-excel xls xlm xla xlc xlt xlw
-application/vnd.ms-fontobject eot
-application/vnd.ms-htmlhelp chm
-application/vnd.ms-ims ims
-application/vnd.ms-lrm lrm
-application/vnd.ms-playready.initiator+xml
-application/vnd.ms-powerpoint ppt pps pot
-application/vnd.ms-project mpp mpt
-application/vnd.ms-tnef
-application/vnd.ms-wmdrm.lic-chlg-req
-application/vnd.ms-wmdrm.lic-resp
-application/vnd.ms-wmdrm.meter-chlg-req
-application/vnd.ms-wmdrm.meter-resp
-application/vnd.ms-works wps wks wcm wdb
-application/vnd.ms-wpl wpl
-application/vnd.ms-xpsdocument xps
-application/vnd.mseq mseq
-application/vnd.msign
-application/vnd.music-niff
-application/vnd.musician mus
-application/vnd.ncd.control
-application/vnd.nervana
-application/vnd.netfpx
-application/vnd.neurolanguage.nlu nlu
-application/vnd.noblenet-directory nnd
-application/vnd.noblenet-sealer nns
-application/vnd.noblenet-web nnw
-application/vnd.nokia.catalogs
-application/vnd.nokia.conml+wbxml
-application/vnd.nokia.conml+xml
-application/vnd.nokia.isds-radio-presets
-application/vnd.nokia.iptv.config+xml
-application/vnd.nokia.landmark+wbxml
-application/vnd.nokia.landmark+xml
-application/vnd.nokia.landmarkcollection+xml
-application/vnd.nokia.n-gage.ac+xml
-application/vnd.nokia.n-gage.data ngdat
-application/vnd.nokia.n-gage.symbian.install n-gage
-application/vnd.nokia.ncd
-application/vnd.nokia.pcd+wbxml
-application/vnd.nokia.pcd+xml
-application/vnd.nokia.radio-preset rpst
-application/vnd.nokia.radio-presets rpss
-application/vnd.novadigm.edm edm
-application/vnd.novadigm.edx edx
-application/vnd.novadigm.ext ext
-application/vnd.oasis.opendocument.chart odc
-application/vnd.oasis.opendocument.chart-template otc
-application/vnd.oasis.opendocument.formula odf
-application/vnd.oasis.opendocument.formula-template otf
-application/vnd.oasis.opendocument.graphics odg
-application/vnd.oasis.opendocument.graphics-template otg
-application/vnd.oasis.opendocument.image odi
-application/vnd.oasis.opendocument.image-template oti
-application/vnd.oasis.opendocument.presentation odp
-application/vnd.oasis.opendocument.presentation-template otp
-application/vnd.oasis.opendocument.spreadsheet ods
-application/vnd.oasis.opendocument.spreadsheet-template ots
-application/vnd.oasis.opendocument.text odt
-application/vnd.oasis.opendocument.text-master otm
-application/vnd.oasis.opendocument.text-template ott
-application/vnd.oasis.opendocument.text-web oth
-application/vnd.obn
-application/vnd.olpc-sugar xo
-application/vnd.oma-scws-config
-application/vnd.oma-scws-http-request
-application/vnd.oma-scws-http-response
-application/vnd.oma.bcast.associated-procedure-parameter+xml
-application/vnd.oma.bcast.drm-trigger+xml
-application/vnd.oma.bcast.imd+xml
-application/vnd.oma.bcast.notification+xml
-application/vnd.oma.bcast.sgboot
-application/vnd.oma.bcast.sgdd+xml
-application/vnd.oma.bcast.sgdu
-application/vnd.oma.bcast.simple-symbol-container
-application/vnd.oma.bcast.smartcard-trigger+xml
-application/vnd.oma.bcast.sprov+xml
-application/vnd.oma.dd2+xml dd2
-application/vnd.oma.drm.risd+xml
-application/vnd.oma.group-usage-list+xml
-application/vnd.oma.poc.groups+xml
-application/vnd.oma.xcap-directory+xml
-application/vnd.omads-email+xml
-application/vnd.omads-file+xml
-application/vnd.omads-folder+xml
-application/vnd.omaloc-supl-init
-application/vnd.openofficeorg.extension oxt
-application/vnd.osa.netdeploy
-application/vnd.osgi.dp dp
-application/vnd.otps.ct-kip+xml
-application/vnd.palm prc pdb pqa oprc
-application/vnd.paos.xml
-application/vnd.pg.format str
-application/vnd.pg.osasli ei6
-application/vnd.piaccess.application-licence
-application/vnd.picsel efif
-application/vnd.poc.group-advertisement+xml
-application/vnd.pocketlearn plf
-application/vnd.powerbuilder6 pbd
-application/vnd.powerbuilder6-s
-application/vnd.powerbuilder7
-application/vnd.powerbuilder7-s
-application/vnd.powerbuilder75
-application/vnd.powerbuilder75-s
-application/vnd.preminet
-application/vnd.previewsystems.box box
-application/vnd.proteus.magazine mgz
-application/vnd.publishare-delta-tree qps
-application/vnd.pvi.ptid1 ptid
-application/vnd.pwg-multiplexed
-application/vnd.pwg-xhtml-print+xml
-application/vnd.qualcomm.brew-app-res
-application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb
-application/vnd.rapid
-application/vnd.recordare.musicxml mxl
-application/vnd.recordare.musicxml+xml
-application/vnd.renlearn.rlprint
-application/vnd.rn-realmedia rm
-application/vnd.ruckus.download
-application/vnd.s3sms
-application/vnd.scribus
-application/vnd.sealed.3df
-application/vnd.sealed.csf
-application/vnd.sealed.doc
-application/vnd.sealed.eml
-application/vnd.sealed.mht
-application/vnd.sealed.net
-application/vnd.sealed.ppt
-application/vnd.sealed.tiff
-application/vnd.sealed.xls
-application/vnd.sealedmedia.softseal.html
-application/vnd.sealedmedia.softseal.pdf
-application/vnd.seemail see
-application/vnd.sema sema
-application/vnd.semd semd
-application/vnd.semf semf
-application/vnd.shana.informed.formdata ifm
-application/vnd.shana.informed.formtemplate itp
-application/vnd.shana.informed.interchange iif
-application/vnd.shana.informed.package ipk
-application/vnd.simtech-mindmapper twd twds
-application/vnd.smaf mmf
-application/vnd.solent.sdkm+xml sdkm sdkd
-application/vnd.spotfire.dxp dxp
-application/vnd.spotfire.sfs sfs
-application/vnd.sss-cod
-application/vnd.sss-dtf
-application/vnd.sss-ntf
-application/vnd.street-stream
-application/vnd.sun.wadl+xml
-application/vnd.sus-calendar sus susp
-application/vnd.svd svd
-application/vnd.swiftview-ics
-application/vnd.syncml+xml xsm
-application/vnd.syncml.dm+wbxml bdm
-application/vnd.syncml.dm+xml xdm
-application/vnd.syncml.ds.notification
-application/vnd.tao.intent-module-archive tao
-application/vnd.tmobile-livetv tmo
-application/vnd.trid.tpt tpt
-application/vnd.triscape.mxs mxs
-application/vnd.trueapp tra
-application/vnd.truedoc
-application/vnd.ufdl ufd ufdl
-application/vnd.uiq.theme utz
-application/vnd.umajin umj
-application/vnd.unity unityweb
-application/vnd.uoml+xml uoml
-application/vnd.uplanet.alert
-application/vnd.uplanet.alert-wbxml
-application/vnd.uplanet.bearer-choice
-application/vnd.uplanet.bearer-choice-wbxml
-application/vnd.uplanet.cacheop
-application/vnd.uplanet.cacheop-wbxml
-application/vnd.uplanet.channel
-application/vnd.uplanet.channel-wbxml
-application/vnd.uplanet.list
-application/vnd.uplanet.list-wbxml
-application/vnd.uplanet.listcmd
-application/vnd.uplanet.listcmd-wbxml
-application/vnd.uplanet.signal
-application/vnd.vcx vcx
-application/vnd.vd-study
-application/vnd.vectorworks
-application/vnd.vidsoft.vidconference
-application/vnd.visio vsd vst vss vsw
-application/vnd.visionary vis
-application/vnd.vividence.scriptfile
-application/vnd.vsf vsf
-application/vnd.wap.sic
-application/vnd.wap.slc
-application/vnd.wap.wbxml wbxml
-application/vnd.wap.wmlc wmlc
-application/vnd.wap.wmlscriptc wmlsc
-application/vnd.webturbo wtb
-application/vnd.wfa.wsc
-application/vnd.wordperfect wpd
-application/vnd.wqd wqd
-application/vnd.wrq-hp3000-labelled
-application/vnd.wt.stf stf
-application/vnd.wv.csp+wbxml
-application/vnd.wv.csp+xml
-application/vnd.wv.ssp+xml
-application/vnd.xara xar
-application/vnd.xfdl xfdl
-application/vnd.xmpie.cpkg
-application/vnd.xmpie.dpkg
-application/vnd.xmpie.plan
-application/vnd.xmpie.ppkg
-application/vnd.xmpie.xlim
-application/vnd.yamaha.hv-dic hvd
-application/vnd.yamaha.hv-script hvs
-application/vnd.yamaha.hv-voice hvp
-application/vnd.yamaha.smaf-audio saf
-application/vnd.yamaha.smaf-phrase spf
-application/vnd.yellowriver-custom-menu cmp
-application/vnd.zzazz.deck+xml zaz
-application/voicexml+xml vxml
-application/watcherinfo+xml
-application/whoispp-query
-application/whoispp-response
-application/winhlp hlp
-application/wita
-application/wordperfect5.1
-application/wsdl+xml wsdl
-application/wspolicy+xml wspolicy
-application/x-ace-compressed ace
-application/x-bcpio bcpio
-application/x-bittorrent torrent
-application/x-bzip bz
-application/x-bzip2 bz2 boz
-application/x-cdlink vcd
-application/x-chat chat
-application/x-chess-pgn pgn
-application/x-compress
-application/x-cpio cpio
-application/x-csh csh
-application/x-director dcr dir dxr fgd
-application/x-dvi dvi
-application/x-futuresplash spl
-application/x-gtar gtar
-application/x-gzip
-application/x-hdf hdf
-application/x-java-jnlp-file jnlp
-application/x-latex latex
-application/x-ms-wmd wmd
-application/x-ms-wmz wmz
-application/x-msaccess mdb
-application/x-msbinder obd
-application/x-mscardfile crd
-application/x-msclip clp
-application/x-msdownload exe dll com bat msi
-application/x-msmediaview mvb m13 m14
-application/x-msmetafile wmf
-application/x-msmoney mny
-application/x-mspublisher pub
-application/x-msschedule scd
-application/x-msterminal trm
-application/x-mswrite wri
-application/x-netcdf nc cdf
-application/x-pkcs12 p12 pfx
-application/x-pkcs7-certificates p7b spc
-application/x-pkcs7-certreqresp p7r
-application/x-rar-compressed rar
-application/x-sh sh
-application/x-shar shar
-application/x-shockwave-flash swf
-application/x-stuffit sit
-application/x-stuffitx sitx
-application/x-sv4cpio sv4cpio
-application/x-sv4crc sv4crc
-application/x-tar tar
-application/x-tcl tcl
-application/x-tex tex
-application/x-texinfo texinfo texi
-application/x-ustar ustar
-application/x-wais-source src
-application/x-x509-ca-cert der crt
-application/x400-bp
-application/xcap-att+xml
-application/xcap-caps+xml
-application/xcap-el+xml
-application/xcap-error+xml
-application/xcap-ns+xml
-application/xenc+xml xenc
-application/xhtml+xml xhtml xht
-application/xml xml xsl
-application/xml-dtd dtd
-application/xml-external-parsed-entity
-application/xmpp+xml
-application/xop+xml xop
-application/xslt+xml xslt
-application/xspf+xml xspf
-application/xv+xml mxml xhvml xvml xvm
-application/zip zip
-audio/32kadpcm
-audio/3gpp
-audio/3gpp2
-audio/ac3
-audio/amr
-audio/amr-wb
-audio/amr-wb+
-audio/asc
-audio/basic au snd
-audio/bv16
-audio/bv32
-audio/clearmode
-audio/cn
-audio/dat12
-audio/dls
-audio/dsr-es201108
-audio/dsr-es202050
-audio/dsr-es202211
-audio/dsr-es202212
-audio/dvi4
-audio/eac3
-audio/evrc
-audio/evrc-qcp
-audio/evrc0
-audio/evrc1
-audio/evrcb
-audio/evrcb0
-audio/evrcb1
-audio/g722
-audio/g7221
-audio/g723
-audio/g726-16
-audio/g726-24
-audio/g726-32
-audio/g726-40
-audio/g728
-audio/g729
-audio/g7291
-audio/g729d
-audio/g729e
-audio/gsm
-audio/gsm-efr
-audio/ilbc
-audio/l16
-audio/l20
-audio/l24
-audio/l8
-audio/lpc
-audio/midi mid midi kar rmi
-audio/mobile-xmf
-audio/mp4 mp4a
-audio/mp4a-latm m4a m4p
-audio/mpa
-audio/mpa-robust
-audio/mpeg mpga mp2 mp2a mp3 m2a m3a
-audio/mpeg4-generic
-audio/parityfec
-audio/pcma
-audio/pcmu
-audio/prs.sid
-audio/qcelp
-audio/red
-audio/rtp-enc-aescm128
-audio/rtp-midi
-audio/rtx
-audio/smv
-audio/smv0
-audio/smv-qcp
-audio/sp-midi
-audio/t140c
-audio/t38
-audio/telephone-event
-audio/tone
-audio/vdvi
-audio/vmr-wb
-audio/vnd.3gpp.iufp
-audio/vnd.4sb
-audio/vnd.audiokoz
-audio/vnd.celp
-audio/vnd.cisco.nse
-audio/vnd.cmles.radio-events
-audio/vnd.cns.anp1
-audio/vnd.cns.inf1
-audio/vnd.digital-winds eol
-audio/vnd.dlna.adts
-audio/vnd.dolby.mlp
-audio/vnd.everad.plj
-audio/vnd.hns.audio
-audio/vnd.lucent.voice lvp
-audio/vnd.nokia.mobile-xmf
-audio/vnd.nortel.vbk
-audio/vnd.nuera.ecelp4800 ecelp4800
-audio/vnd.nuera.ecelp7470 ecelp7470
-audio/vnd.nuera.ecelp9600 ecelp9600
-audio/vnd.octel.sbc
-audio/vnd.qcelp
-audio/vnd.rhetorex.32kadpcm
-audio/vnd.sealedmedia.softseal.mpeg
-audio/vnd.vmx.cvsd
-audio/wav wav
-audio/x-aiff aif aiff aifc
-audio/x-mpegurl m3u
-audio/x-ms-wax wax
-audio/x-ms-wma wma
-audio/x-pn-realaudio ram ra
-audio/x-pn-realaudio-plugin rmp
-audio/x-wav wav
-chemical/x-cdx cdx
-chemical/x-cif cif
-chemical/x-cmdf cmdf
-chemical/x-cml cml
-chemical/x-csml csml
-chemical/x-pdb pdb
-chemical/x-xyz xyz
-image/bmp bmp
-image/cgm cgm
-image/fits
-image/g3fax g3
-image/gif gif
-image/ief ief
-image/jp2 jp2
-image/jpeg jpeg jpg jpe
-image/jpm
-image/jpx
-image/naplps
-image/pict pict pic pct
-image/png png
-image/prs.btif btif
-image/prs.pti
-image/svg+xml svg svgz
-image/t38
-image/tiff tiff tif
-image/tiff-fx
-image/vnd.adobe.photoshop psd
-image/vnd.cns.inf2
-image/vnd.djvu djvu djv
-image/vnd.dwg dwg
-image/vnd.dxf dxf
-image/vnd.fastbidsheet fbs
-image/vnd.fpx fpx
-image/vnd.fst fst
-image/vnd.fujixerox.edmics-mmr mmr
-image/vnd.fujixerox.edmics-rlc rlc
-image/vnd.globalgraphics.pgb
-image/vnd.microsoft.icon ico
-image/vnd.mix
-image/vnd.ms-modi mdi
-image/vnd.net-fpx npx
-image/vnd.sealed.png
-image/vnd.sealedmedia.softseal.gif
-image/vnd.sealedmedia.softseal.jpg
-image/vnd.svf
-image/vnd.wap.wbmp wbmp
-image/vnd.xiff xif
-image/x-cmu-raster ras
-image/x-cmx cmx
-image/x-icon
-image/x-macpaint pntg pnt mac
-image/x-pcx pcx
-image/x-pict pic pct
-image/x-portable-anymap pnm
-image/x-portable-bitmap pbm
-image/x-portable-graymap pgm
-image/x-portable-pixmap ppm
-image/x-quicktime qtif qti
-image/x-rgb rgb
-image/x-xbitmap xbm
-image/x-xpixmap xpm
-image/x-xwindowdump xwd
-message/cpim
-message/delivery-status
-message/disposition-notification
-message/external-body
-message/http
-message/news
-message/partial
-message/rfc822 eml mime
-message/s-http
-message/sip
-message/sipfrag
-message/tracking-status
-model/iges igs iges
-model/mesh msh mesh silo
-model/vnd.dwf dwf
-model/vnd.flatland.3dml
-model/vnd.gdl gdl
-model/vnd.gs.gdl
-model/vnd.gtw gtw
-model/vnd.moml+xml
-model/vnd.mts mts
-model/vnd.parasolid.transmit.binary
-model/vnd.parasolid.transmit.text
-model/vnd.vtu vtu
-model/vrml wrl vrml
-multipart/alternative
-multipart/appledouble
-multipart/byteranges
-multipart/digest
-multipart/encrypted
-multipart/form-data
-multipart/header-set
-multipart/mixed
-multipart/parallel
-multipart/related
-multipart/report
-multipart/signed
-multipart/voice-message
-text/calendar ics ifb
-text/css css
-text/csv csv
-text/directory
-text/dns
-text/enriched
-text/html html htm
-text/parityfec
-text/plain txt text conf def list log in
-text/prs.fallenstein.rst
-text/prs.lines.tag dsc
-text/red
-text/rfc822-headers
-text/richtext rtx
-text/rtf
-text/rtp-enc-aescm128
-text/rtx
-text/sgml sgml sgm
-text/t140
-text/tab-separated-values tsv
-text/troff t tr roff man me ms
-text/uri-list uri uris urls
-text/vnd.abc
-text/vnd.curl
-text/vnd.dmclientscript
-text/vnd.esmertec.theme-descriptor
-text/vnd.fly fly
-text/vnd.fmi.flexstor flx
-text/vnd.in3d.3dml 3dml
-text/vnd.in3d.spot spot
-text/vnd.iptc.newsml
-text/vnd.iptc.nitf
-text/vnd.latex-z
-text/vnd.motorola.reflex
-text/vnd.ms-mediapackage
-text/vnd.net2phone.commcenter.command
-text/vnd.sun.j2me.app-descriptor jad
-text/vnd.trolltech.linguist
-text/vnd.wap.si
-text/vnd.wap.sl
-text/vnd.wap.wml wml
-text/vnd.wap.wmlscript wmls
-text/x-asm s asm
-text/x-c c cc cxx cpp h hh dic
-text/x-fortran f for f77 f90
-text/x-pascal p pas
-text/x-java-source java
-text/x-setext etx
-text/x-uuencode uu
-text/x-vcalendar vcs
-text/x-vcard vcf
-text/xml
-text/xml-external-parsed-entity
-video/3gpp 3gp
-video/3gpp-tt
-video/3gpp2 3g2
-video/bmpeg
-video/bt656
-video/celb
-video/dv
-video/h261 h261
-video/h263 h263
-video/h263-1998
-video/h263-2000
-video/h264 h264
-video/jpeg jpgv
-video/jpm jpm jpgm
-video/mj2 mj2 mjp2
-video/mp1s
-video/mp2p
-video/mp2t
-video/mp4 mp4 mp4v mpg4 m4v
-video/mp4v-es
-video/mpeg mpeg mpg mpe m1v m2v
-video/mpeg4-generic
-video/mpv
-video/nv
-video/parityfec
-video/pointer
-video/quicktime qt mov
-video/raw
-video/rtp-enc-aescm128
-video/rtx
-video/smpte292m
-video/vc1
-video/vnd.dlna.mpeg-tts
-video/vnd.fvt fvt
-video/vnd.hns.video
-video/vnd.motorola.video
-video/vnd.motorola.videop
-video/vnd.mpegurl mxu m4u
-video/vnd.nokia.interleaved-multimedia
-video/vnd.nokia.videovoip
-video/vnd.objectvideo
-video/vnd.sealed.mpeg1
-video/vnd.sealed.mpeg4
-video/vnd.sealed.swf
-video/vnd.sealedmedia.softseal.mov
-video/vnd.vivo viv
-video/x-dv dv dif
-video/x-fli fli
-video/x-ms-asf asf asx
-video/x-ms-wm wm
-video/x-ms-wmv wmv
-video/x-ms-wmx wmx
-video/x-ms-wvx wvx
-video/x-msvideo avi
-video/x-sgi-movie movie
-x-conference/x-cooltalk ice
--- /dev/null
+Doug Coleman
--- /dev/null
+USING: accessors checksums checksums.md5 io io.encodings.ascii
+io.encodings.binary io.files io.streams.byte-array
+io.streams.string kernel make mime.multipart
+mime.multipart.private multiline sequences strings tools.test ;
+IN: mime.multipart.tests
+
+[ { "a" } ] [
+ [
+ "azzbzzczzdzz" <string-reader> "z" <multipart-stream> 1 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "a" } ] [
+ [
+ "azzbzzczzdzz" <string-reader> "z" <multipart-stream> 2 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "a" } ] [
+ [
+ "azzbzzczzdzz" <string-reader> "z" <multipart-stream> 3 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "a" } ] [
+ [
+ "azzbzzczzdzz" <string-reader> "z" <multipart-stream> 4 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "a" } ] [
+ [
+ "azzbzzczzdzz" <string-reader> "z" <multipart-stream> 5 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+
+[ { "a" "a" } ] [
+ [
+ "aazzbzzczzdzz" <string-reader> "z" <multipart-stream> 1 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "aa" } ] [
+ [
+ "aazzbzzczzdzz" <string-reader> "z" <multipart-stream> 2 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "aa" } ] [
+ [
+ "aazzbzzczzdzz" <string-reader> "z" <multipart-stream> 3 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "aa" } ] [
+ [
+ "aazzbzzczzdzz" <string-reader> "z" <multipart-stream> 4 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "aa" } ] [
+ [
+ "aazzbzzczzdzz" <string-reader> "z" <multipart-stream> 5 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+
+
+[ { "a" } ] [
+ [
+ "azzbzzczzdzz" <string-reader> "zz" <multipart-stream> 1 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "a" "z" "z" "b" "z" "z" "c" "z" "z" "d" "zz" } ] [
+ [
+ "azzbzzczzdzz" <string-reader> "zzz" <multipart-stream> 1 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "a" "z" "z" "b" "z" "z" "c" "z" "z" "d" } ] [
+ [
+ "azzbzzczzdzzz" <string-reader> "zzz" <multipart-stream> 1 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "az" "zb" "zz" "cz" "zd" } ] [
+ [
+ "azzbzzczzdzzz" <string-reader> "zzz" <multipart-stream> 2 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "a" "zzb" "zzc" "zzd" } ] [
+ [
+ "azzbzzczzdzzz" <string-reader> "zzz" <multipart-stream> 3 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "az" "zbzz" "czzd" } ] [
+ [
+ "azzbzzczzdzzz" <string-reader> "zzz" <multipart-stream> 4 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+[ { "azz" "bzzcz" "zd" } ] [
+ [
+ "azzbzzczzdzzz" <string-reader> "zzz" <multipart-stream> 5 >>n
+ [ , ] multipart-step-loop drop
+ ] { } make
+] unit-test
+
+
+
+: dog-test-empty-bytes-safari ( -- bytes )
+ B{
+ 45 45 45 45 45 45 87 101 98 75 105 116 70 111 114 109 66
+ 111 117 110 100 97 114 121 74 57 98 119 65 87 115 51 121
+ 110 112 113 115 72 53 75 13 10 67 111 110 116 101 110 116
+ 45 68 105 115 112 111 115 105 116 105 111 110 58 32 102 111
+ 114 109 45 100 97 116 97 59 32 110 97 109 101 61 34 102 105
+ 108 101 49 34 59 32 102 105 108 101 110 97 109 101 61 34
+ 100 111 103 46 106 112 103 34 13 10 67 111 110 116 101 110
+ 116 45 84 121 112 101 58 32 105 109 97 103 101 47 106 112
+ 101 103 13 10 13 10 255 216 255 224 0 16 74 70 73 70 0 1 1
+ 0 0 1 0 1 0 0 255 219 0 67 0 5 3 4 4 4 3 5 4 4 4 5 5 5 6 7
+ 12 8 7 7 7 7 15 11 11 9 12 17 15 18 18 17 15 17 17 19 22 28
+ 23 19 20 26 21 17 17 24 33 24 26 29 29 31 31 31 19 23 34 36
+ 34 30 36 28 30 31 30 255 219 0 67 1 5 5 5 7 6 7 14 8 8 14
+ 30 20 17 20 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
+ 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
+ 30 30 30 30 30 30 30 30 30 30 30 30 30 30 255 192 0 17 8 1
+ 49 1 64 3 1 34 0 2 17 1 3 17 1 255 196 0 29 0 0 2 2 3 1 1 1
+ 0 0 0 0 0 0 0 0 0 4 5 6 7 2 3 8 0 1 9 255 196 0 74 16 0 2 1
+ 3 3 2 4 4 3 4 5 10 5 3 5 1 1 2 3 0 4 17 5 18 33 6 49 19 34
+ 65 81 7 50 97 113 20 35 129 21 51 66 82 36 52 145 161 177 8
+ 53 83 98 114 115 147 178 193 209 22 37 67 116 241 99 130
+ 240 23 68 84 100 146 225 255 196 0 25 1 0 3 1 1 1 0 0 0 0 0
+ 0 0 0 0 0 0 1 2 3 0 4 5 255 196 0 39 17 0 2 2 2 2 3 0 2 1 5
+ 1 0 0 0 0 0 0 1 2 17 3 33 18 49 34 50 65 19 81 4 5 20 35 66
+ 97 82 255 218 0 12 3 1 0 2 17 3 17 0 63 0 228 200 149 136
+ 219 131 200 207 233 68 196 145 112 60 21 45 234 91 181 57
+ 177 178 138 75 56 95 111 152 196 51 250 209 11 167 198 14
+ 118 138 22 138 153 104 150 118 82 46 217 45 161 98 79 242
+ 102 157 38 151 98 174 64 211 237 72 247 49 46 104 11 8 140
+ 111 229 247 166 194 70 137 12 146 112 61 235 57 36 172 31
+ 82 7 154 199 78 244 176 178 255 0 132 41 100 195 76 15 183
+ 240 118 60 31 244 85 237 126 241 237 237 157 213 176 113
+ 197 66 158 254 234 82 74 49 45 187 144 42 49 155 158 217
+ 108 152 99 21 68 214 88 116 217 83 17 218 218 171 250 109
+ 138 180 254 6 221 83 205 109 1 199 115 225 10 141 90 106 23
+ 106 187 95 59 73 239 237 77 44 111 89 79 136 24 186 250 131
+ 235 86 199 166 71 143 20 52 181 211 237 24 143 232 150 236
+ 61 140 66 155 65 167 233 251 64 252 5 158 127 221 45 3 99
+ 42 220 42 186 240 79 247 83 139 38 86 92 21 57 20 76 246
+ 140 78 155 98 88 31 217 246 125 191 209 45 108 253 159 97
+ 255 0 240 44 255 0 225 45 22 216 200 199 181 99 88 74 98 77
+ 99 78 178 69 111 14 194 213 23 28 226 48 15 246 212 30 242
+ 21 252 105 8 145 170 103 178 213 137 172 121 162 127 181 87
+ 151 141 182 247 31 235 210 180 216 209 28 88 217 219 120 99
+ 250 52 100 255 0 172 155 168 248 108 109 11 103 240 208 127
+ 194 173 118 82 71 225 47 148 246 163 11 169 30 74 81 140
+ 102 182 178 35 203 97 104 62 162 46 104 41 45 109 119 127
+ 86 131 254 21 48 144 225 9 198 104 105 198 24 118 53 76 77
+ 81 141 73 105 109 143 234 176 127 193 21 146 89 219 110 63
+ 209 97 255 0 131 69 65 183 110 15 39 218 182 144 160 159 41
+ 6 169 102 5 22 54 138 114 109 45 216 123 24 184 53 177 45
+ 44 137 231 79 179 237 254 138 179 118 101 112 167 159 181
+ 102 131 140 212 35 236 99 95 224 172 119 143 252 190 207
+ 254 21 18 186 125 129 92 254 2 207 254 16 172 15 148 230
+ 182 71 46 225 198 106 178 78 204 40 213 237 109 83 33 45
+ 224 237 223 195 199 247 214 189 30 222 222 69 45 37 165 187
+ 156 227 12 161 177 245 230 143 214 212 8 75 123 138 15 69
+ 96 7 220 214 159 169 135 31 129 177 192 198 159 102 120 255
+ 0 68 181 240 216 217 12 15 217 214 156 246 252 165 230 137
+ 139 205 235 128 7 204 123 80 183 154 148 118 202 66 225 156
+ 118 62 148 169 174 38 91 55 193 167 233 191 60 214 22 96 14
+ 249 137 107 84 199 69 137 246 174 157 100 255 0 65 18 210
+ 43 237 82 105 148 188 108 64 254 31 102 164 243 223 204 146
+ 249 155 39 233 73 38 50 84 137 156 112 233 19 200 4 118 54
+ 201 238 22 33 68 54 153 166 52 96 173 149 163 15 115 16 205
+ 66 244 189 77 141 226 40 115 143 90 155 91 73 192 116 245
+ 29 141 77 233 140 177 169 46 64 109 167 88 45 203 31 217
+ 246 92 127 244 171 19 97 99 226 16 218 125 152 227 63 186
+ 20 100 204 56 247 245 175 66 84 145 191 147 235 246 174 140
+ 125 18 180 125 183 211 108 72 7 246 125 158 63 221 45 109
+ 151 77 177 219 254 111 179 255 0 132 180 68 76 163 133 206
+ 51 197 103 43 0 184 166 158 144 72 133 244 54 113 220 5 91
+ 120 50 59 254 77 7 120 109 188 48 22 8 1 207 242 98 152 106
+ 170 191 137 45 239 218 149 93 41 97 129 239 73 97 143 96 19
+ 172 103 204 161 23 232 181 164 71 152 93 143 173 110 117
+ 101 67 90 142 239 195 55 165 97 229 251 37 122 124 138 182
+ 48 118 253 210 81 66 116 250 82 123 2 205 103 108 55 30 99
+ 31 221 218 140 134 63 56 221 200 169 147 26 90 229 159 56
+ 20 109 242 171 89 16 217 251 80 214 190 80 49 197 110 212
+ 63 168 147 234 107 74 62 44 166 36 156 209 17 234 235 140
+ 193 26 170 182 230 227 21 40 248 113 208 240 234 214 169 53
+ 194 224 63 166 57 168 167 85 55 136 34 5 87 126 124 170 123
+ 26 233 15 129 214 42 221 59 108 123 112 51 27 14 223 90 142
+ 61 68 233 206 227 249 58 35 7 224 252 57 252 133 141 91 25
+ 82 71 24 255 0 189 44 212 254 21 222 99 16 171 120 139 234
+ 160 97 171 165 99 81 143 5 145 74 142 199 29 171 239 225 99
+ 121 138 149 80 127 133 241 205 22 229 96 121 19 84 145 199
+ 250 231 77 106 61 62 210 25 35 114 189 212 1 198 43 237 133
+ 210 72 71 24 56 228 125 107 167 186 179 163 236 245 93 61
+ 149 35 76 148 42 43 154 186 195 167 175 58 123 85 149 9 37
+ 67 103 63 74 117 39 123 37 151 26 110 226 20 14 64 53 246
+ 132 211 174 22 234 21 216 217 111 83 69 22 80 72 197 89 245
+ 103 61 238 128 117 60 155 121 15 174 218 174 239 8 23 141
+ 158 251 170 192 213 36 219 11 175 169 28 85 123 169 237 93
+ 64 240 57 52 99 32 142 45 89 191 15 229 231 154 46 201 155
+ 60 214 141 48 43 69 141 163 24 162 109 227 61 199 21 57 118
+ 96 244 57 92 227 52 43 198 219 143 126 244 68 18 3 88 202
+ 172 141 134 108 147 205 8 107 64 62 65 223 145 131 239 91
+ 25 188 199 39 38 181 163 99 191 122 250 112 199 118 59 213
+ 83 160 114 54 59 46 211 239 89 39 203 90 93 89 88 115 197
+ 110 64 74 113 83 138 169 5 59 62 183 35 214 189 16 193 197
+ 124 109 202 123 154 251 19 13 199 35 38 170 242 69 62 194
+ 105 214 255 0 171 138 85 166 169 82 204 164 237 60 103 235
+ 77 181 129 226 66 184 98 163 220 82 155 73 24 202 45 34 81
+ 201 239 75 44 138 141 7 114 72 110 146 203 36 73 12 42 207
+ 150 193 197 73 52 191 135 215 186 168 241 220 180 113 177
+ 206 49 200 90 153 124 40 248 122 110 151 241 183 65 66 12
+ 48 207 191 189 94 54 186 61 165 156 94 28 123 10 149 10 78
+ 59 138 231 109 252 58 163 8 163 159 236 254 19 73 53 176 86
+ 80 176 175 171 1 197 107 185 248 77 101 105 103 51 204 187
+ 36 199 24 25 39 255 0 249 93 18 176 195 18 157 177 168 30
+ 212 191 85 132 201 109 39 134 138 204 227 110 8 160 175 232
+ 210 227 196 226 14 170 210 27 66 215 60 46 54 110 5 72 31
+ 227 82 141 57 214 72 145 137 198 64 237 70 127 148 13 146
+ 219 107 208 145 150 5 240 91 211 245 165 58 75 237 130 48
+ 72 36 47 117 237 71 39 113 4 23 248 216 202 224 96 100 114
+ 107 24 148 183 126 62 213 182 101 57 231 145 89 70 6 7 2
+ 174 221 35 133 71 102 248 84 40 245 172 110 57 38 182 175 3
+ 140 86 19 1 142 194 145 182 199 34 250 129 197 226 100 241
+ 154 211 52 121 77 194 182 234 67 117 238 223 236 162 150 17
+ 248 81 218 138 116 52 72 228 225 183 246 21 241 148 126 30
+ 79 76 46 234 62 234 16 27 181 7 34 55 135 55 63 250 116 232
+ 210 118 168 117 167 172 127 132 183 220 224 15 13 127 187
+ 189 16 10 135 194 144 69 43 176 144 155 88 23 212 71 70 32
+ 110 251 129 165 170 25 99 99 139 78 127 182 179 213 220 199
+ 167 141 190 86 35 191 189 42 241 228 132 174 50 65 246 162
+ 53 9 89 172 227 221 158 212 178 151 139 54 61 100 68 118
+ 241 86 227 89 182 132 121 247 72 1 2 186 187 225 157 184
+ 131 70 182 143 28 162 128 203 234 167 235 92 181 211 246 87
+ 23 221 92 145 198 173 133 144 121 192 249 107 170 250 103
+ 242 236 35 241 147 194 157 84 6 99 252 85 36 169 34 249 98
+ 229 34 100 89 89 139 43 6 97 192 35 211 233 95 94 86 17 2
+ 199 56 238 105 119 226 188 171 223 183 39 222 190 27 172 16
+ 95 113 79 95 173 16 199 30 134 246 242 11 133 60 242 59 212
+ 75 226 103 77 91 235 58 101 204 138 159 154 145 147 145 235
+ 78 97 152 171 248 145 200 10 31 65 222 138 155 100 200 21
+ 178 222 167 29 171 5 87 211 144 110 214 109 31 80 240 36
+ 111 32 39 57 244 57 237 77 224 152 92 69 226 174 49 142 126
+ 149 105 124 86 232 27 125 70 22 187 178 132 9 2 229 177 247
+ 53 76 66 38 209 181 65 109 48 111 8 156 18 123 81 229 20
+ 170 201 101 196 253 163 208 94 161 14 251 105 27 217 106
+ 189 213 20 11 226 125 51 138 177 181 70 205 153 104 249 87
+ 28 85 117 117 253 117 247 251 241 84 87 240 231 26 233 108
+ 192 5 3 131 77 145 78 243 74 180 213 193 7 138 115 18 229
+ 137 172 227 33 27 48 183 64 24 26 202 126 13 108 140 169
+ 242 142 9 236 79 106 26 92 150 228 250 209 140 93 140 124
+ 254 48 107 34 195 39 154 215 255 0 231 122 247 191 253 234
+ 188 65 196 223 27 151 24 144 101 253 40 152 179 130 49 233
+ 90 109 85 29 124 217 163 226 218 19 28 98 163 123 176 165
+ 64 46 219 13 122 22 223 39 28 147 216 86 219 133 4 19 90 1
+ 240 161 50 28 131 252 52 91 131 219 55 144 62 189 56 91 68
+ 133 88 110 245 30 213 37 248 49 210 178 106 58 188 51 73
+ 144 138 119 19 233 140 208 189 61 210 211 245 12 232 193 79
+ 204 57 32 226 186 51 161 250 90 195 65 211 161 138 8 255 0
+ 51 104 46 125 106 115 146 78 145 124 17 113 143 146 37 26
+ 85 188 122 109 132 113 68 184 96 49 159 165 125 185 185 85
+ 59 90 64 119 124 198 180 205 43 5 43 156 31 79 181 10 178
+ 36 44 26 70 222 205 223 30 148 165 210 177 139 150 149 10
+ 227 98 142 192 250 214 155 147 253 28 199 177 88 122 238
+ 244 250 208 171 52 155 134 88 98 133 150 237 164 36 46 112
+ 15 53 129 56 190 145 65 255 0 148 77 158 235 69 153 118 182
+ 199 218 54 118 239 154 175 116 73 72 181 129 135 204 203
+ 218 174 31 142 22 18 234 26 36 203 2 72 21 60 229 64 253
+ 225 207 106 165 244 67 38 194 37 36 178 240 51 90 91 175
+ 248 104 234 13 18 169 228 221 230 127 46 43 5 151 196 228
+ 214 55 127 186 221 238 43 85 187 100 227 158 213 94 71 20
+ 180 232 103 23 43 197 125 145 84 168 201 230 176 135 182 43
+ 100 156 40 165 9 22 212 144 45 249 247 163 161 254 174 40
+ 93 79 157 67 62 153 166 22 234 166 1 197 96 53 98 235 149
+ 12 167 222 147 234 3 242 102 81 220 71 82 41 99 12 59 129
+ 74 117 91 114 45 167 117 31 250 103 251 169 148 140 129 45
+ 55 44 17 99 253 29 23 12 204 28 6 3 20 20 19 127 71 139 159
+ 253 42 223 28 129 136 7 156 154 103 208 255 0 153 177 205
+ 170 120 204 3 12 12 240 69 111 213 199 134 145 66 163 36
+ 143 90 246 154 141 148 231 143 74 203 89 138 67 123 11 6 57
+ 199 21 63 134 139 243 68 211 224 110 159 102 218 140 243
+ 189 188 178 60 152 249 192 192 171 213 173 128 140 176 141
+ 15 25 193 244 168 39 193 43 63 15 79 19 76 7 140 199 206
+ 184 171 30 250 50 146 43 42 228 48 193 168 219 163 177 55
+ 200 71 226 254 97 228 140 28 99 210 183 69 117 30 226 31
+ 105 30 222 148 46 161 152 75 141 229 148 156 226 149 60 140
+ 70 248 137 80 189 241 75 143 34 186 101 158 54 201 25 102
+ 241 55 70 35 3 216 118 162 108 39 87 144 66 242 108 61 243
+ 239 244 168 180 119 82 49 253 233 136 123 10 206 207 82 89
+ 36 88 174 150 38 195 121 37 76 247 250 213 123 36 224 214
+ 201 204 169 20 145 60 61 148 240 72 245 170 127 227 23 70
+ 172 150 134 226 214 223 107 103 141 130 173 155 70 86 183
+ 66 28 179 3 250 26 58 242 194 43 232 66 92 66 187 79 189
+ 115 201 108 56 230 163 105 156 115 105 60 208 196 214 23 80
+ 148 145 71 5 135 122 132 235 145 201 29 249 42 188 22 245
+ 174 164 248 151 240 207 198 70 212 45 21 81 145 142 204 10
+ 160 186 163 71 154 222 77 183 49 8 157 84 246 254 35 239 93
+ 112 206 180 145 203 60 93 201 116 37 211 39 10 0 126 41 220
+ 119 81 1 144 213 22 120 174 35 92 237 226 135 146 250 234
+ 33 235 143 65 87 228 217 13 50 87 226 199 254 144 126 149
+ 245 166 141 200 243 10 133 46 162 232 115 146 72 172 206
+ 175 41 238 191 223 67 147 9 51 12 132 227 114 214 82 120
+ 106 56 113 80 209 170 72 88 5 76 31 189 20 215 178 152 212
+ 149 201 197 50 102 37 118 211 195 242 150 227 222 140 18 71
+ 129 181 137 168 84 119 151 1 73 197 49 180 191 153 148 110
+ 200 199 106 231 250 104 246 74 29 148 174 230 227 29 177 89
+ 232 58 77 246 183 172 195 20 112 177 141 125 135 6 153 244
+ 151 75 234 157 65 36 113 136 241 9 0 230 186 15 162 250 19
+ 79 208 225 79 42 25 145 130 183 31 74 76 146 138 71 84 49
+ 211 183 209 143 68 244 245 174 149 167 6 252 56 86 28 246
+ 169 45 207 130 182 134 66 222 30 61 187 214 251 192 182 235
+ 26 15 40 39 210 144 107 247 22 176 249 46 37 36 124 193 127
+ 155 233 83 91 118 86 172 214 151 14 236 220 228 103 130 222
+ 213 147 204 138 164 48 86 39 185 168 228 218 149 196 206 56
+ 17 91 129 133 81 243 17 88 53 227 180 137 28 114 56 92 122
+ 247 170 27 241 177 225 187 24 231 251 171 43 85 241 50 170
+ 14 15 36 154 87 109 34 151 27 134 121 167 54 108 225 129 12
+ 118 251 82 185 168 151 112 226 129 250 130 194 222 77 30
+ 118 120 247 237 140 250 122 215 48 107 54 169 103 169 201
+ 224 163 129 188 240 195 138 235 187 203 101 109 50 82 205
+ 130 227 143 181 115 71 197 11 55 183 214 228 88 219 17 239
+ 224 1 244 162 157 171 57 102 252 68 107 48 54 234 27 24 175
+ 68 15 114 49 158 213 166 218 19 37 160 207 38 140 137 120
+ 10 220 145 86 198 173 108 227 123 9 130 182 203 218 181 195
+ 216 240 59 214 215 70 49 131 73 244 196 91 80 99 248 197 62
+ 230 152 193 145 111 145 75 245 24 207 226 147 159 90 109
+ 103 31 244 97 158 115 84 140 28 140 40 184 185 117 148 100
+ 12 118 173 183 172 143 165 92 48 193 34 39 175 186 149 168
+ 14 24 142 49 64 220 201 183 78 157 87 129 225 61 43 84 232
+ 196 94 55 155 195 207 134 216 61 168 155 89 101 241 16 108
+ 61 232 168 236 220 219 161 11 198 208 223 219 91 173 172
+ 157 100 86 32 119 166 109 80 30 201 95 79 166 228 30 245
+ 150 187 129 127 18 255 0 101 110 209 23 195 43 246 175 107
+ 136 5 253 171 30 119 29 181 54 44 125 209 127 252 28 119
+ 147 73 72 230 142 40 215 60 31 122 156 223 199 182 38 200
+ 192 3 32 212 119 225 21 138 174 131 12 155 67 115 220 84
+ 183 91 141 148 97 89 64 199 32 251 84 228 244 119 67 216
+ 175 53 163 38 215 30 25 199 112 213 29 69 63 48 152 73 159
+ 65 233 83 13 65 48 37 1 124 167 249 170 55 61 169 40 20 109
+ 200 254 90 129 218 4 247 78 190 70 24 83 220 214 80 238 154
+ 69 16 176 14 14 87 234 104 11 230 104 238 90 118 5 84 252
+ 202 125 190 148 126 152 158 21 202 220 69 135 4 103 13 217
+ 215 233 250 215 70 55 226 38 88 187 39 154 13 208 252 34
+ 163 33 141 193 243 231 212 251 211 251 121 149 85 1 97 130
+ 112 191 90 135 90 206 197 188 64 27 45 201 207 127 214 134
+ 215 181 195 98 143 189 138 237 77 203 207 99 70 147 236 131
+ 99 174 169 234 43 123 77 62 84 37 70 88 247 53 203 223 20
+ 122 138 214 234 127 203 100 102 12 71 7 177 230 180 252 80
+ 248 131 123 168 93 92 217 90 92 48 143 126 11 3 85 179 199
+ 52 132 72 237 36 140 199 144 125 105 163 26 232 132 230 210
+ 164 48 75 217 26 50 178 31 175 216 86 192 177 179 120 114
+ 70 67 241 199 223 181 123 78 176 141 158 25 60 57 29 36 94
+ 123 112 125 170 77 160 116 237 205 192 152 92 70 3 69 180
+ 142 14 72 30 149 94 150 201 70 42 93 246 70 127 3 111 32 5
+ 156 28 246 30 245 190 13 46 213 184 24 7 252 106 204 181
+ 232 39 188 134 25 214 2 158 110 1 167 211 252 45 149 128
+ 217 22 112 6 10 158 230 167 249 25 79 192 83 113 90 218 43
+ 149 217 141 188 156 214 187 150 139 38 69 97 207 165 90 154
+ 223 195 91 168 237 85 150 18 178 103 7 158 226 163 250 159
+ 68 74 152 183 104 138 133 245 230 154 51 108 73 97 165 178
+ 2 110 35 93 185 140 228 246 250 214 22 218 145 75 144 79 49
+ 169 237 237 76 239 180 139 136 30 225 167 183 116 136 113
+ 19 250 19 244 164 87 118 130 221 66 140 239 113 150 255 0
+ 84 123 26 210 236 17 199 79 146 58 87 225 47 85 90 20 133
+ 99 120 217 252 48 184 7 154 188 44 181 72 110 33 115 28 138
+ 189 178 107 243 247 73 212 245 13 34 238 43 139 91 150 86
+ 86 224 103 130 43 161 190 21 117 252 218 133 187 199 52 195
+ 196 199 42 79 57 169 101 130 173 150 89 37 47 133 243 123
+ 62 27 184 205 66 250 153 228 158 87 72 219 242 128 203 31
+ 230 250 83 11 125 67 241 86 98 67 184 239 92 140 119 20 179
+ 85 146 97 108 214 246 225 124 118 236 237 217 7 169 53 139
+ 136 77 210 199 8 240 215 106 142 5 122 9 94 225 177 34 149
+ 251 208 119 94 29 164 113 164 108 89 229 206 11 127 16 254
+ 111 181 21 167 69 35 196 145 178 183 3 230 247 165 148 171
+ 163 166 41 164 130 109 86 72 238 147 99 239 32 246 21 50
+ 208 67 51 13 202 70 225 138 143 217 91 1 54 246 198 79 106
+ 149 105 49 31 46 210 1 250 210 91 125 141 149 166 135 114
+ 167 244 87 221 194 162 96 31 173 115 103 199 23 118 190 241
+ 36 82 160 55 148 159 90 234 47 194 238 179 39 25 59 121 246
+ 174 109 255 0 40 116 120 110 193 194 99 119 97 84 199 217
+ 231 101 232 129 88 15 19 77 12 127 74 223 28 124 80 182 50
+ 40 176 133 70 70 70 236 125 40 181 124 40 198 106 216 211
+ 226 206 89 109 155 34 93 166 136 112 118 10 12 51 23 28 26
+ 222 242 16 170 190 227 251 40 168 180 18 63 170 115 121 30
+ 61 233 149 159 238 69 44 213 124 179 41 200 224 209 54 210
+ 55 130 49 197 27 163 25 220 166 238 105 102 167 24 91 9 200
+ 239 225 63 20 222 94 35 207 189 5 169 47 244 9 255 0 221 61
+ 43 70 54 233 208 175 236 235 101 33 79 228 35 103 244 175
+ 52 113 171 249 177 244 197 37 178 189 151 240 22 235 26 231
+ 108 64 22 250 14 212 76 115 74 236 190 76 156 214 148 120
+ 148 135 25 116 137 30 154 114 195 142 115 199 181 103 212 2
+ 69 22 211 42 134 41 38 15 181 97 165 135 104 187 109 230
+ 137 213 70 52 183 247 83 145 247 160 73 170 154 103 65 124
+ 33 150 245 186 106 18 99 120 198 121 199 106 156 223 50 181
+ 177 103 80 95 24 21 0 248 17 121 29 215 79 197 27 206 216 7
+ 154 178 245 45 63 242 188 72 206 83 28 87 61 118 206 200 63
+ 34 5 170 47 149 155 113 35 212 123 82 11 169 21 163 11 24
+ 218 71 114 106 73 171 90 72 204 237 27 21 199 124 122 212
+ 102 246 53 149 138 188 133 0 61 197 37 89 217 29 136 53 75
+ 171 111 21 13 192 196 108 112 91 218 137 211 97 109 58 34
+ 151 18 135 183 97 186 25 129 206 207 245 126 212 171 82 145
+ 33 117 180 155 5 91 129 159 74 81 38 165 119 166 23 181 185
+ 13 36 64 111 140 154 120 107 68 242 77 217 59 186 215 99
+ 183 178 109 201 135 81 232 121 199 215 235 84 183 196 238
+ 182 55 119 18 90 219 202 225 135 145 142 107 221 79 213 32
+ 192 235 24 33 241 140 3 233 239 85 212 183 17 202 254 44
+ 222 116 39 42 87 230 253 106 177 77 156 83 157 61 31 45 237
+ 237 239 1 102 27 100 118 207 29 137 246 21 186 210 206 226
+ 234 117 88 99 32 227 102 0 229 79 210 134 131 114 220 179
+ 91 169 147 235 31 106 184 62 29 116 188 215 205 14 160 145
+ 168 115 141 216 236 79 184 250 85 23 138 217 40 183 116 197
+ 93 13 210 179 94 74 18 230 213 114 14 72 92 240 106 230 233
+ 14 149 201 182 205 143 49 182 210 72 249 254 245 48 233 30
+ 132 176 210 209 47 24 174 233 57 97 252 167 218 167 186 85
+ 149 188 100 34 145 133 57 28 122 212 102 220 186 58 97 20
+ 182 200 190 129 210 227 194 72 103 183 201 140 229 192 28
+ 17 78 83 165 195 162 4 143 96 7 111 126 245 58 210 108 148
+ 90 143 40 231 191 214 137 154 200 237 77 168 54 171 110 34
+ 137 185 113 123 101 115 115 210 176 184 101 150 223 113 81
+ 198 106 35 212 61 46 204 146 44 118 104 3 38 204 227 176
+ 247 251 213 241 45 180 101 119 0 9 35 251 41 14 173 104 170
+ 73 101 10 153 224 208 119 240 50 148 89 202 157 87 210 48
+ 77 60 202 214 110 145 193 229 140 1 199 222 169 174 161 208
+ 175 22 242 86 75 117 218 95 31 252 215 114 106 218 69 181
+ 227 52 71 111 57 46 113 223 138 169 250 227 225 231 131 110
+ 90 216 198 94 224 22 231 209 126 149 162 223 45 154 81 168
+ 156 164 246 105 35 152 164 140 41 67 203 122 15 160 172 244
+ 205 66 77 47 82 51 89 54 17 78 55 19 203 125 233 247 94 105
+ 223 178 174 22 205 16 237 44 124 64 125 90 162 182 234 136
+ 155 102 138 70 62 137 31 173 94 124 90 57 84 156 54 116 39
+ 195 190 179 134 247 78 137 124 92 52 99 12 24 250 84 190
+ 125 74 222 228 22 13 148 35 12 7 241 125 15 210 185 131 65
+ 214 164 211 239 247 12 162 231 205 138 181 180 30 166 140
+ 66 173 183 114 133 221 180 251 251 212 163 217 104 57 61
+ 217 45 187 183 48 52 154 150 161 34 137 37 242 67 26 246 81
+ 232 61 233 182 153 49 100 85 229 112 63 90 138 45 212 147
+ 203 251 79 82 37 80 183 229 102 164 26 9 252 67 120 146 72
+ 85 91 145 72 227 114 59 160 237 18 88 219 116 161 128 194
+ 250 98 164 218 66 175 145 152 176 31 74 141 233 144 188 234
+ 35 221 177 148 246 247 169 118 137 110 210 97 23 142 49 73
+ 246 131 54 146 29 92 206 230 219 109 190 115 183 140 251 87
+ 51 255 0 148 20 183 13 170 120 78 170 124 221 249 174 164
+ 185 130 27 123 23 50 76 82 69 143 129 239 92 167 241 178
+ 239 241 93 84 144 43 29 170 196 55 214 169 141 83 103 14 94
+ 136 60 113 50 75 18 174 79 229 246 52 94 226 2 231 223 154
+ 250 84 199 50 150 228 142 7 218 177 118 12 221 171 162 18
+ 75 71 56 79 139 25 101 81 243 99 244 172 165 198 194 27 185
+ 239 143 74 24 174 210 24 112 43 207 32 216 41 219 179 8 181
+ 86 62 48 237 222 143 178 93 208 45 3 170 168 241 215 143 90
+ 105 166 46 97 24 246 169 72 198 115 174 16 41 251 208 58
+ 145 99 167 93 28 124 176 57 31 217 76 167 70 35 147 64 234
+ 8 223 179 47 121 255 0 246 207 255 0 45 82 49 209 133 58
+ 116 91 236 237 155 215 195 163 214 53 35 105 60 208 186 71
+ 245 59 111 247 99 251 232 167 39 120 199 189 115 61 187 58
+ 49 244 62 211 27 106 40 244 11 138 206 245 131 90 52 110
+ 112 15 124 250 80 182 59 150 60 230 183 93 131 52 5 27 128
+ 123 98 175 195 198 206 121 123 23 111 194 141 25 19 165 163
+ 146 25 150 25 163 228 146 123 213 139 166 235 6 72 132 55
+ 16 182 244 227 196 61 136 170 231 225 154 76 186 12 22 208
+ 179 49 99 134 250 138 156 221 168 180 182 82 216 81 234 125
+ 123 87 36 175 164 117 198 187 96 58 228 214 203 59 186 202
+ 20 145 242 147 193 53 1 215 181 21 183 159 204 200 184 60
+ 224 240 43 87 94 245 125 134 157 20 166 73 17 216 118 25
+ 230 168 174 178 235 171 237 81 90 222 215 114 199 158 72
+ 239 250 86 132 91 208 207 34 142 209 51 235 190 160 181 86
+ 120 81 64 43 192 57 245 168 68 189 85 123 61 177 130 95 57
+ 67 149 63 78 212 133 26 107 169 12 183 147 177 200 245 61
+ 205 1 113 118 200 204 145 224 15 173 118 67 29 171 100 178
+ 229 182 25 125 127 150 37 188 197 251 168 238 15 189 39 185
+ 59 88 239 96 227 233 90 204 153 36 243 156 250 214 80 71 44
+ 242 42 170 239 102 56 81 158 230 153 164 142 87 119 100 211
+ 225 206 159 38 163 172 70 24 180 11 24 192 157 144 149 39
+ 254 181 215 159 13 186 114 107 91 40 63 18 33 155 114 143
+ 204 72 246 156 125 126 149 76 255 0 147 198 143 171 90 193
+ 29 212 150 211 92 187 159 201 137 149 118 238 29 192 231 57
+ 31 95 210 186 179 67 253 204 19 79 111 28 23 17 128 94 51
+ 243 21 255 0 10 231 148 172 183 14 42 205 194 198 51 182 56
+ 212 246 239 76 244 141 60 52 109 25 57 246 62 245 140 23
+ 182 18 93 21 158 101 66 237 144 163 184 167 169 60 62 42
+ 219 197 177 155 211 111 183 189 78 154 232 101 145 208 77
+ 140 91 97 53 181 215 56 86 224 19 201 175 182 255 0 153 207
+ 99 244 237 88 207 34 169 11 131 222 155 95 72 74 219 179 99
+ 70 54 96 118 28 10 87 127 110 100 144 112 118 47 115 77 147
+ 204 156 80 119 141 180 129 42 159 15 233 220 208 119 240
+ 104 57 39 178 37 117 96 85 213 147 200 51 198 125 105 102
+ 187 166 69 54 157 34 149 46 249 193 30 255 0 74 152 93 203
+ 101 248 35 47 136 164 33 198 65 165 111 61 188 182 243 165
+ 187 70 230 70 249 143 96 43 36 238 217 105 100 109 81 202
+ 255 0 26 122 94 231 240 119 19 36 177 69 30 60 177 32 36
+ 177 255 0 189 115 30 160 38 130 83 13 194 52 108 59 6 24 56
+ 175 208 63 136 208 223 92 105 207 21 134 158 207 19 103 243
+ 21 87 43 199 98 73 239 92 75 241 71 69 212 236 122 138 225
+ 174 109 229 104 249 35 198 24 32 125 72 227 251 234 139 100
+ 114 69 209 22 180 152 162 121 78 1 245 167 218 70 173 115
+ 107 34 186 254 98 142 224 122 138 138 6 100 227 248 79 106
+ 221 5 228 177 159 47 98 49 85 171 22 46 145 97 69 213 51 92
+ 95 197 248 179 182 5 249 99 61 254 245 105 116 222 187 111
+ 113 98 30 50 170 84 236 7 61 207 181 115 221 153 241 206
+ 226 88 47 185 244 52 108 26 166 163 165 220 175 225 238 11
+ 170 182 229 0 240 77 35 196 213 179 170 57 18 143 103 91
+ 244 253 212 110 23 116 170 167 102 50 125 13 77 116 75 168
+ 109 109 131 33 103 25 229 147 214 185 131 161 190 34 36 211
+ 8 175 36 104 229 7 140 227 7 251 234 246 233 77 90 222 254
+ 213 26 9 55 2 61 235 145 220 101 208 202 74 107 178 77 121
+ 113 115 170 188 145 70 36 181 135 30 99 47 241 253 171 159
+ 62 46 90 90 218 245 34 77 104 193 54 183 0 213 253 169 91
+ 200 150 203 113 19 96 168 36 227 218 185 235 226 187 51 106
+ 194 86 112 70 227 192 239 84 199 53 100 178 105 82 35 18 57
+ 99 90 7 239 43 4 155 33 91 156 123 86 107 203 110 174 142
+ 36 101 166 19 130 0 200 199 21 237 170 121 39 154 248 155
+ 177 230 32 214 71 129 156 142 105 210 179 8 245 140 248 163
+ 138 109 163 200 162 223 130 51 138 85 173 224 74 87 190 61
+ 69 29 163 254 235 244 161 40 152 57 183 51 103 6 131 213 8
+ 93 58 247 60 127 71 127 249 104 238 62 180 22 177 183 246
+ 101 239 127 234 239 255 0 45 20 233 24 85 167 73 26 216 65
+ 158 254 18 86 70 100 50 129 159 90 89 104 199 240 86 236
+ 199 63 150 63 186 178 133 100 146 225 112 199 147 197 69 37
+ 101 99 145 116 137 133 143 154 42 223 50 31 8 149 228 138
+ 209 167 127 87 0 247 94 9 162 157 136 78 14 51 222 171 242
+ 136 228 246 39 127 8 122 155 193 211 165 220 219 222 54 192
+ 218 113 254 52 71 92 124 78 134 206 23 182 242 187 28 252
+ 196 228 113 244 170 88 223 220 219 207 44 80 206 241 239
+ 239 180 227 38 144 234 211 205 121 49 73 228 101 63 206 79
+ 45 244 169 180 145 73 78 162 107 234 29 90 235 92 212 101
+ 113 39 229 150 254 34 104 102 133 173 146 56 230 104 163 6
+ 61 202 249 206 107 11 155 118 183 143 115 52 123 72 227 117
+ 42 184 144 147 183 57 35 142 15 24 167 142 136 115 114 14
+ 212 175 140 155 18 48 170 23 212 122 208 18 51 72 219 155
+ 143 181 124 141 89 188 217 237 82 45 15 165 239 239 228 64
+ 35 220 172 50 60 164 211 60 180 168 122 182 34 182 181 150
+ 105 22 52 83 150 56 21 119 124 40 232 61 22 11 120 117 14
+ 162 91 71 193 223 137 156 141 163 244 168 207 76 244 169
+ 183 63 136 212 18 225 18 57 54 168 100 219 185 135 63 225
+ 91 58 183 90 125 107 82 255 0 195 61 62 206 225 188 133 223
+ 130 120 244 164 82 82 209 69 162 234 185 248 149 211 250 36
+ 150 134 27 173 53 90 60 43 62 205 196 168 237 185 135 124
+ 122 30 226 143 31 29 52 104 209 202 95 254 32 5 27 100 36
+ 236 45 159 148 10 175 236 62 14 116 119 78 233 49 106 29
+ 125 173 188 6 78 209 228 140 254 148 143 173 126 25 244 255
+ 0 254 31 184 234 111 135 186 191 237 75 11 33 253 58 212
+ 252 240 131 193 111 211 138 203 18 248 105 41 203 127 11 55
+ 77 248 167 13 230 169 52 150 247 62 32 50 141 165 57 219
+ 192 206 71 176 171 175 165 122 166 5 180 105 218 238 57 174
+ 14 11 190 120 198 63 135 233 92 19 209 178 53 191 80 219
+ 134 145 158 37 96 36 8 112 28 122 30 61 49 87 123 245 75
+ 105 182 99 207 52 183 69 118 195 26 0 16 169 237 74 213 104
+ 10 171 71 82 105 125 92 178 27 168 173 231 133 252 12 41 37
+ 143 45 235 68 75 172 79 115 181 162 5 128 229 177 233 84
+ 103 195 200 167 142 199 241 23 49 151 121 21 93 163 36 242
+ 199 230 63 165 90 218 115 72 203 28 109 148 86 95 48 30 130
+ 163 46 131 68 134 62 164 146 22 88 78 21 152 231 46 120 197
+ 44 126 179 134 226 226 72 124 104 153 146 79 13 129 39 0
+ 251 253 170 55 212 64 44 102 54 86 40 36 33 28 158 7 21 76
+ 245 62 169 115 211 218 200 159 30 37 165 208 49 206 224 240
+ 62 181 88 250 152 177 62 34 245 140 58 102 239 2 121 12 14
+ 222 120 80 249 147 237 244 168 54 141 241 163 78 211 141
+ 197 165 197 196 110 210 203 184 16 199 40 158 223 78 113
+ 222 160 191 17 53 127 196 104 134 75 123 167 145 74 17 20
+ 217 230 63 175 255 0 62 245 82 116 190 137 169 117 70 175
+ 107 165 233 240 120 183 183 79 225 199 158 199 156 150 111
+ 160 28 213 97 20 214 197 201 168 218 58 99 87 248 221 161
+ 73 107 36 48 234 16 164 172 70 232 230 77 202 62 162 133
+ 213 239 186 63 173 172 13 173 252 186 108 175 26 9 160 13
+ 46 213 115 245 3 147 81 85 248 123 240 135 79 184 58 54 177
+ 212 210 207 171 96 36 146 110 10 187 253 64 250 103 181 70
+ 126 35 124 48 190 232 99 6 191 161 221 181 213 145 243 70
+ 249 7 2 179 138 55 41 69 121 116 68 62 34 244 106 232 154
+ 139 73 100 209 61 179 246 17 146 66 253 179 80 146 152 39
+ 131 199 28 213 195 105 171 105 157 87 161 143 26 59 165 188
+ 183 127 13 178 23 185 254 44 14 194 162 250 143 68 106 158
+ 61 204 107 110 234 144 30 119 14 228 250 214 186 216 120
+ 166 66 226 186 146 33 181 64 42 79 57 166 150 183 81 221 67
+ 28 108 18 34 131 27 135 115 75 245 13 58 230 209 218 57 151
+ 105 30 148 26 50 169 243 12 143 106 111 201 100 165 221 14
+ 110 45 100 30 29 202 108 93 231 201 176 249 179 245 169 239
+ 195 46 190 155 65 116 134 233 140 202 14 56 39 138 173 172
+ 165 241 167 102 114 65 246 205 29 45 139 162 248 204 228
+ 123 82 154 13 217 214 154 111 94 193 127 103 35 13 219 89
+ 59 103 214 170 30 176 184 55 250 195 158 200 28 241 237 81
+ 14 158 212 46 196 42 137 52 136 163 140 3 222 158 137 55
+ 121 155 204 199 185 62 181 62 153 119 177 106 33 86 39 146
+ 15 247 81 80 227 28 214 137 102 84 57 35 143 81 91 33 60 96
+ 250 242 42 184 246 182 77 236 45 72 53 242 65 229 28 154
+ 249 12 110 20 229 189 107 50 141 142 244 244 97 14 171 216
+ 100 246 245 166 26 88 99 0 35 218 130 215 35 41 149 62 180
+ 126 145 34 139 101 76 115 75 35 4 237 124 253 43 70 167 206
+ 153 122 63 254 179 255 0 203 71 73 185 87 191 122 7 80 255
+ 0 54 94 255 0 237 223 254 90 41 42 48 158 198 216 61 132 13
+ 234 34 76 10 223 4 91 101 25 226 129 180 188 95 192 192 168
+ 74 159 13 123 253 40 136 174 55 56 243 115 92 231 71 24 168
+ 162 77 103 194 133 29 143 173 23 183 3 142 104 29 53 183 69
+ 159 173 28 161 137 32 48 31 122 183 250 156 242 236 132 107
+ 158 77 85 199 161 245 165 154 157 228 75 20 143 224 147 38
+ 208 160 254 180 95 83 57 138 255 0 123 28 143 97 222 163 23
+ 119 6 86 113 187 3 28 3 64 73 118 105 188 158 75 137 188 71
+ 96 196 142 62 149 164 43 30 194 155 233 90 68 247 146 69 24
+ 134 76 56 200 101 82 71 247 84 150 223 225 254 169 117 125
+ 13 172 54 206 217 30 128 228 208 177 150 50 61 211 246 17
+ 93 221 197 19 50 151 102 24 78 228 254 149 210 29 55 105 99
+ 164 244 220 104 153 154 237 211 1 35 143 5 190 134 190 116
+ 95 193 91 125 52 67 53 238 212 144 12 22 9 206 126 149 105
+ 216 232 54 58 126 158 27 240 202 229 60 161 207 115 250 84
+ 178 100 101 225 138 145 205 127 16 35 235 141 54 194 107
+ 169 173 82 194 202 102 43 28 64 121 177 238 126 181 183 252
+ 152 180 184 110 186 206 59 139 153 55 120 114 255 0 23 124
+ 138 184 254 36 90 166 177 166 141 46 104 35 142 4 39 108
+ 140 60 196 227 176 199 115 84 102 142 215 157 3 174 165 245
+ 152 155 98 49 145 210 65 182 66 185 239 131 86 197 41 73 81
+ 57 175 22 75 126 54 92 222 106 189 105 168 45 206 80 193 62
+ 200 131 127 20 127 74 19 225 245 222 151 210 147 38 181 113
+ 169 69 121 103 125 101 56 212 44 99 102 221 6 60 168 178
+ 103 131 158 249 20 247 171 250 255 0 225 55 87 218 197 168
+ 106 38 238 29 67 24 153 33 139 7 31 169 239 80 253 42 199
+ 77 234 9 221 244 173 34 120 116 93 223 60 242 238 146 225
+ 135 191 176 197 36 63 140 227 147 155 122 59 223 245 28 95
+ 218 44 42 62 68 123 167 116 185 33 117 214 20 71 109 12 210
+ 51 36 95 197 180 158 0 171 51 165 244 73 181 27 215 191 191
+ 183 154 71 150 61 177 2 56 219 239 254 213 35 135 77 93 99
+ 94 75 88 99 72 173 161 199 135 10 231 9 138 187 122 35 69
+ 184 136 199 113 225 112 23 204 91 181 105 61 158 122 116
+ 182 109 183 177 142 215 72 137 99 152 44 139 202 169 238
+ 135 220 211 173 10 247 84 145 37 105 49 49 72 240 127 183
+ 230 20 195 195 180 216 86 107 115 34 158 225 69 108 183 146
+ 21 220 177 126 90 40 200 92 115 82 158 217 76 73 209 23 188
+ 188 186 187 184 17 77 43 73 110 173 231 66 57 205 36 235 93
+ 26 222 248 180 239 3 92 196 188 182 206 202 49 86 11 61 188
+ 190 105 20 200 254 158 80 48 43 69 253 168 184 183 219 28
+ 107 27 24 246 133 127 95 236 162 131 61 28 197 173 216 222
+ 88 217 13 44 226 43 73 31 242 89 255 0 139 239 65 124 52
+ 190 183 232 190 169 212 34 186 137 37 188 186 211 165 252
+ 20 241 182 10 183 7 106 159 114 1 171 31 226 39 74 188 150
+ 165 68 82 126 72 47 156 241 159 165 66 44 180 219 125 107
+ 79 75 123 168 137 187 181 36 199 112 14 10 48 237 131 86
+ 134 153 9 78 169 175 217 28 191 211 109 173 111 109 205 190
+ 165 6 167 45 196 98 226 89 34 13 152 157 143 40 229 191 136
+ 122 213 219 240 252 182 169 240 123 92 211 245 15 204 134
+ 221 191 163 153 62 94 59 129 85 78 147 168 244 85 173 233
+ 139 172 44 181 29 51 80 138 76 59 194 229 163 155 253 110
+ 121 201 246 169 111 88 252 86 233 143 252 53 7 76 244 23
+ 143 35 72 140 37 121 34 218 50 125 205 8 97 148 95 43 61 95
+ 231 255 0 59 22 124 80 140 35 180 82 80 254 51 75 234 219
+ 152 244 185 25 31 199 17 162 17 228 111 191 210 174 222 139
+ 139 169 109 103 71 234 59 16 208 73 134 91 132 28 99 218
+ 162 191 15 58 89 110 181 4 213 181 39 113 32 199 134 93 114
+ 142 255 0 82 43 162 180 147 22 161 107 2 222 219 198 147
+ 162 132 64 7 148 175 189 35 200 250 103 18 132 111 179 158
+ 126 54 232 182 47 178 234 216 143 12 182 230 34 169 75 216
+ 226 86 62 11 7 25 238 43 184 58 167 161 44 181 120 36 73 6
+ 204 140 99 195 4 19 238 42 138 248 143 240 98 250 192 126
+ 51 78 18 73 30 114 219 87 3 251 40 197 162 83 195 78 202 44
+ 103 52 211 78 187 145 54 164 135 122 127 47 168 167 119 125
+ 31 117 14 158 39 146 60 72 6 74 169 228 212 106 230 9 109
+ 91 44 172 185 28 110 20 233 139 199 137 59 211 30 223 194 6
+ 21 216 9 228 123 154 117 19 21 183 101 35 181 68 58 114 224
+ 52 41 184 147 232 64 247 169 58 179 120 108 164 130 77 35
+ 236 22 8 208 254 98 209 16 202 21 112 8 197 15 63 136 172 6
+ 112 125 43 234 35 110 238 0 255 0 173 87 23 65 24 66 236
+ 121 193 197 109 144 238 21 170 15 42 121 151 28 214 213 59
+ 184 170 24 79 174 144 84 145 216 246 173 250 79 238 135 218
+ 133 214 206 213 17 144 115 69 105 35 49 45 99 12 223 228
+ 160 245 15 243 101 239 254 217 255 0 229 163 101 24 10 191
+ 74 11 81 227 77 189 255 0 219 191 252 181 140 66 237 225
+ 152 136 216 103 105 143 138 42 222 57 150 117 57 39 154 107
+ 103 110 162 194 219 10 63 171 171 126 167 189 98 177 159 20
+ 10 230 67 56 162 65 166 16 176 15 122 57 202 178 141 172
+ 115 64 88 198 124 49 205 27 28 101 92 179 114 41 211 177 27
+ 43 190 181 38 61 66 76 115 159 127 74 142 91 196 102 157 87
+ 146 88 212 151 174 163 111 198 6 254 126 212 171 167 182
+ 166 169 24 144 2 50 57 62 156 208 151 236 120 165 106 206
+ 132 248 59 209 94 38 135 22 165 116 100 87 219 133 80 70 49
+ 138 180 58 43 73 68 189 154 226 52 220 241 182 23 35 56 160
+ 58 34 72 173 250 58 47 54 209 225 129 24 247 207 173 79 186
+ 31 77 16 218 248 219 67 25 6 226 42 13 203 224 242 236 123
+ 167 216 226 13 203 26 128 188 231 57 255 0 26 95 212 86 203
+ 14 38 0 224 17 188 125 42 75 20 6 20 41 26 240 252 40 164
+ 186 234 187 174 24 60 133 78 89 87 218 149 187 209 148 221
+ 236 138 245 22 157 60 140 183 218 74 1 34 249 247 204 160
+ 162 241 142 213 79 245 47 72 111 89 117 61 99 84 182 187
+ 158 103 33 174 166 206 10 255 0 42 133 245 251 213 175 213
+ 218 164 50 217 172 77 44 214 192 54 8 65 153 36 250 40 165
+ 235 164 216 95 233 145 223 73 17 140 91 201 143 195 177 220
+ 227 244 236 198 173 6 250 55 37 118 206 124 181 232 213 212
+ 181 136 196 118 238 246 80 74 54 160 1 90 97 239 159 229
+ 171 3 81 179 134 222 91 125 63 77 88 108 247 70 21 97 132
+ 238 43 245 53 45 120 119 180 159 135 218 145 202 124 24 230
+ 10 1 96 59 138 144 116 239 76 219 104 202 250 174 165 4 101
+ 194 238 201 94 91 218 157 201 213 11 26 91 162 47 209 221
+ 26 52 117 23 55 18 44 146 183 32 241 146 126 181 97 105 233
+ 20 118 239 243 120 107 243 2 121 52 161 18 107 251 179 117
+ 35 164 17 70 249 66 107 125 213 247 138 230 59 119 1 148
+ 224 149 236 106 118 51 105 187 99 27 235 207 20 237 133 85
+ 51 237 90 163 140 144 27 36 55 175 214 176 176 141 3 171 57
+ 220 128 242 222 212 213 32 181 101 44 179 99 53 59 41 141
+ 241 20 200 230 41 119 134 56 245 197 31 105 121 29 194 42
+ 177 193 3 134 254 42 198 107 120 2 16 178 100 251 210 153
+ 213 161 184 13 20 228 145 243 173 50 86 9 53 123 50 234 11
+ 11 107 132 41 134 60 99 35 4 255 0 125 85 157 71 210 82 232
+ 87 15 123 4 237 225 49 203 32 28 15 92 241 86 153 120 245
+ 40 4 33 140 12 220 54 239 152 214 173 37 225 148 75 165 223
+ 70 178 197 38 80 59 12 213 185 19 139 75 225 77 117 119 76
+ 218 117 23 78 199 47 225 99 146 248 121 146 242 54 243 3
+ 252 172 191 245 164 29 51 210 246 205 122 209 95 27 104 110
+ 162 249 76 132 248 83 143 117 43 87 61 247 76 54 135 118
+ 243 89 248 81 68 91 43 159 95 113 205 124 211 116 235 59
+ 199 54 23 81 195 110 249 202 133 64 54 122 231 39 248 104
+ 114 98 73 236 91 209 125 35 169 105 98 107 75 29 66 7 178
+ 150 60 155 57 0 59 121 244 39 154 176 161 130 56 45 161 131
+ 240 242 36 164 237 44 221 179 244 168 206 172 145 216 106
+ 169 111 43 77 19 68 121 184 135 229 199 250 223 79 168 169
+ 93 165 218 234 150 209 172 106 222 64 48 87 215 30 166 167
+ 40 219 177 137 5 164 77 225 36 102 48 236 7 36 210 254 160
+ 178 221 27 70 208 171 41 249 151 210 159 105 140 205 10 22
+ 12 209 109 192 217 232 126 191 90 251 119 110 165 6 236 183
+ 213 187 209 72 45 183 217 69 183 75 195 125 121 61 155 100
+ 5 30 184 205 115 207 198 174 155 151 68 213 222 32 25 161
+ 83 228 98 7 34 186 207 88 181 139 79 234 23 149 155 247 220
+ 10 163 255 0 202 41 80 99 115 120 135 178 3 252 67 6 155 28
+ 147 208 117 84 202 79 164 121 159 185 198 123 26 153 3 129
+ 233 81 14 155 253 250 152 252 188 224 129 233 82 233 50 23
+ 235 76 227 178 79 197 31 83 243 62 113 147 239 69 69 10 17
+ 207 56 237 66 70 234 20 224 115 68 71 56 0 125 120 167 197
+ 209 141 160 49 250 250 86 74 25 125 43 234 28 14 56 205 101
+ 147 239 84 48 155 89 82 249 46 54 159 165 109 209 219 49
+ 125 171 29 96 150 206 121 226 190 232 192 180 71 21 140 53
+ 145 153 136 192 29 168 109 70 54 253 151 120 205 192 54 207
+ 255 0 45 18 119 46 57 244 172 117 94 116 59 175 253 179 255
+ 0 202 107 24 142 89 51 27 24 6 15 238 146 183 163 13 224
+ 100 103 53 170 197 15 224 160 237 251 164 175 174 140 178
+ 175 110 245 199 99 146 109 59 247 127 173 22 85 73 60 208
+ 90 110 68 32 159 122 34 114 206 190 203 233 142 245 117 29
+ 89 39 221 16 158 179 54 177 220 6 150 54 101 29 212 54 9
+ 253 107 111 65 52 119 55 208 199 14 159 167 164 123 191 120
+ 209 111 147 191 189 1 214 76 222 33 221 130 113 71 252 41
+ 88 255 0 104 199 36 165 130 171 100 227 214 150 79 84 58
+ 126 71 78 217 170 67 162 91 71 31 38 76 42 17 235 86 191 71
+ 218 226 40 183 157 227 104 3 30 245 85 116 252 107 47 224
+ 147 147 26 121 176 106 212 209 200 68 130 221 153 131 103
+ 118 229 237 138 136 242 236 147 52 74 210 101 92 7 94 113
+ 81 206 163 180 146 65 45 212 115 0 66 224 212 170 13 172 85
+ 149 148 48 60 230 163 157 92 118 146 241 130 177 200 118 96
+ 251 227 63 244 167 125 0 170 250 146 107 143 26 41 174 154
+ 105 32 81 183 100 67 37 142 104 141 62 226 225 44 37 156
+ 192 167 127 149 93 184 194 251 154 34 85 150 107 205 145
+ 176 9 27 121 178 56 175 107 55 45 34 236 114 145 219 47 4
+ 142 9 164 10 179 239 79 89 193 97 27 94 77 34 162 47 152 51
+ 30 13 9 170 235 147 234 243 24 80 18 177 156 130 61 69 71
+ 239 239 159 88 188 88 85 21 45 226 60 5 39 154 51 80 158
+ 223 65 182 73 37 184 54 225 70 230 4 14 70 59 81 76 106 190
+ 198 23 55 145 91 233 127 141 105 132 48 198 48 238 199 3
+ 255 0 154 174 58 155 227 6 147 167 135 139 69 183 123 233
+ 84 238 241 230 249 11 85 101 241 47 174 53 30 162 190 154
+ 40 100 123 125 56 54 216 237 225 111 46 51 220 253 106 53
+ 162 195 249 223 155 143 15 235 70 43 147 7 137 100 15 139
+ 93 115 122 210 203 111 115 4 1 223 248 98 193 3 233 91 224
+ 235 142 190 159 44 117 201 23 112 254 17 66 244 246 143 9
+ 132 58 170 159 165 53 93 29 113 226 5 35 43 144 0 167 81
+ 127 161 185 68 15 255 0 212 47 136 86 174 118 234 178 76 23
+ 130 28 113 138 249 167 124 105 234 91 59 198 143 87 180 181
+ 188 182 99 229 35 190 62 148 116 154 76 126 31 238 219 44
+ 57 200 168 119 85 233 118 246 170 74 40 12 79 4 246 20 90
+ 111 224 27 139 46 222 152 235 237 19 169 151 109 140 198
+ 218 240 156 61 180 237 134 79 246 126 181 34 212 21 229 41
+ 26 161 241 147 204 8 244 250 215 29 239 158 206 100 158 41
+ 36 142 88 206 229 120 216 130 167 220 123 213 223 240 171
+ 175 165 212 172 19 76 214 36 205 194 174 216 238 9 229 135
+ 177 164 118 129 73 244 93 58 63 80 195 169 35 105 23 135
+ 108 177 46 6 238 198 129 182 183 146 199 89 146 65 27 74
+ 210 38 207 15 196 194 129 244 164 122 189 171 181 132 55 80
+ 183 134 20 238 18 47 175 222 138 210 117 111 218 67 240 247
+ 18 5 184 78 3 10 91 12 83 110 168 207 85 150 225 110 90 222
+ 68 144 6 95 202 42 60 195 234 79 173 72 186 125 111 38 252
+ 53 180 146 166 118 124 222 189 251 26 213 115 190 234 201 0
+ 88 214 88 142 85 241 233 68 116 235 184 34 119 145 222 69
+ 109 187 113 253 244 108 220 75 31 72 181 120 160 48 25 4
+ 128 12 144 43 116 176 199 248 15 13 99 98 8 230 182 105 222
+ 91 96 164 129 43 97 183 30 216 199 106 209 172 188 98 216
+ 198 172 195 234 180 91 36 221 58 43 158 186 142 72 46 32
+ 154 67 149 13 159 189 85 31 25 237 148 233 226 85 240 156
+ 21 220 168 235 184 30 61 69 91 221 94 127 21 104 95 4 140
+ 121 126 149 89 245 117 172 87 90 116 126 59 200 27 105 92
+ 142 64 21 37 26 118 91 134 172 230 221 62 226 221 53 16 143
+ 103 28 110 78 73 133 246 47 255 0 230 164 55 238 134 37 218
+ 70 61 57 165 29 89 165 92 104 218 195 188 136 230 34 124
+ 178 122 99 222 178 134 224 188 74 172 114 64 239 86 82 100
+ 166 188 67 34 108 46 115 69 71 38 229 238 41 100 47 199 122
+ 54 221 129 166 140 184 137 45 58 24 219 252 167 62 245 183
+ 156 103 210 180 68 234 171 94 150 96 20 14 106 139 34 97 0
+ 213 121 25 29 141 124 210 37 111 8 166 59 26 245 243 6 77
+ 163 248 123 159 122 195 70 238 212 121 196 195 144 196 247
+ 21 163 84 35 246 77 208 245 17 57 63 109 180 65 27 87 60 80
+ 154 145 255 0 203 111 127 246 207 254 24 173 206 38 21 233
+ 188 216 219 159 254 146 127 133 110 4 9 121 25 161 108 37
+ 85 177 183 95 85 140 110 250 226 136 143 243 36 7 208 26
+ 228 41 30 199 214 25 240 78 71 173 109 150 64 16 143 95 65
+ 239 88 90 16 109 248 227 28 86 139 146 119 231 60 142 213
+ 107 124 73 201 121 16 206 172 95 26 80 23 191 175 210 166
+ 191 9 186 121 141 170 220 180 51 57 39 129 129 239 222 144
+ 217 105 82 234 218 199 131 179 11 184 110 53 209 157 23 211
+ 214 182 122 44 81 201 48 241 182 0 61 49 74 24 251 14 122
+ 66 214 229 94 48 208 133 80 63 139 189 88 90 72 96 192 54
+ 56 236 105 7 78 88 164 31 52 129 163 94 88 231 204 79 181
+ 74 32 134 75 123 116 196 68 156 118 110 226 145 143 46 198
+ 179 58 65 18 179 74 219 207 112 59 84 115 170 46 217 180
+ 249 95 121 44 62 81 237 245 251 209 183 119 81 180 108 184
+ 238 42 25 212 90 162 174 228 102 93 157 155 119 96 41 152
+ 42 207 186 29 184 107 71 154 87 35 185 99 238 106 35 214 90
+ 132 78 5 157 187 22 99 232 41 157 222 169 44 26 83 52 101
+ 76 44 48 54 118 53 26 208 109 228 190 214 33 145 162 12 12
+ 152 25 246 164 47 12 111 76 155 124 53 233 149 16 45 197
+ 218 110 64 114 115 235 84 239 199 221 101 78 177 123 102
+ 140 26 56 188 160 102 186 123 67 179 75 123 51 101 8 13 193
+ 12 127 147 235 92 107 241 198 27 139 126 176 212 98 152 146
+ 230 124 159 246 105 148 28 132 134 68 242 52 200 12 48 44
+ 118 198 237 149 195 183 37 15 202 62 213 165 53 63 1 131 60
+ 39 195 251 84 155 168 46 180 217 180 109 62 218 212 51 92
+ 54 12 161 7 205 247 165 87 82 89 54 159 36 87 22 142 140 62
+ 94 59 85 34 168 156 161 110 209 97 124 56 215 45 245 8 28
+ 170 12 227 145 237 86 5 215 225 226 75 113 12 108 254 77
+ 217 110 56 170 35 225 13 243 91 235 38 53 243 161 111 238
+ 171 123 169 245 84 91 139 104 17 137 65 24 17 253 15 181
+ 116 66 105 160 113 67 109 70 91 88 173 214 118 0 239 5 72
+ 81 218 169 78 186 234 56 127 27 45 154 167 136 55 144 49
+ 222 173 110 160 212 29 58 101 228 42 5 202 198 66 12 122
+ 123 215 62 233 243 164 250 255 0 141 116 60 92 49 242 142
+ 237 247 161 55 72 220 80 93 188 222 50 8 230 132 164 141
+ 199 110 5 49 209 255 0 242 221 97 24 23 216 28 40 223 199
+ 127 181 107 189 186 73 119 50 219 202 189 176 224 114 121
+ 166 125 93 62 159 113 248 25 172 29 213 196 65 164 200 238
+ 213 12 177 114 141 153 73 69 209 212 95 8 26 223 168 186 54
+ 104 166 219 35 68 72 81 246 21 27 234 77 54 125 23 88 18
+ 236 216 132 242 69 51 255 0 37 139 27 166 208 175 174 74
+ 150 141 66 149 95 114 123 212 179 226 94 151 227 217 181
+ 196 42 36 98 114 19 249 126 149 25 174 40 188 50 46 64 61
+ 45 117 107 170 89 51 69 38 14 57 7 189 109 179 111 194 245
+ 10 13 196 46 60 195 211 25 168 15 76 222 92 88 234 70 5 5
+ 73 60 113 145 82 150 213 51 126 143 112 34 19 99 128 135
+ 119 30 249 255 0 165 104 116 52 210 79 69 167 109 119 185
+ 17 22 66 87 119 13 235 138 35 83 11 140 198 229 199 166 106
+ 45 162 220 120 138 36 207 25 230 164 81 75 226 40 88 227
+ 223 143 74 214 115 53 228 70 181 136 157 225 117 141 64 227
+ 133 53 93 235 150 179 52 130 23 132 62 14 0 95 191 173 90
+ 250 196 56 152 49 219 150 249 75 118 6 161 215 246 48 139
+ 215 146 105 24 130 48 71 240 211 36 55 39 209 207 127 20 33
+ 179 180 212 101 79 6 102 89 24 46 201 62 82 113 220 84 6 88
+ 22 44 52 44 206 159 94 226 174 175 140 58 47 137 104 38 179
+ 101 148 71 150 81 184 6 83 244 205 83 54 30 42 72 232 246
+ 243 3 159 48 200 110 126 244 64 246 104 220 241 131 186 137
+ 182 184 64 57 110 107 102 161 110 172 9 141 65 30 254 212
+ 166 104 218 35 156 253 42 148 128 210 100 129 46 99 63 197
+ 95 39 148 99 200 115 72 34 149 193 201 99 138 221 248 229
+ 67 207 106 87 20 128 208 222 233 129 143 30 222 190 245 142
+ 151 235 247 165 175 125 226 2 84 226 143 210 100 5 194 255
+ 0 53 40 7 133 191 44 80 90 144 206 153 122 114 127 171 61
+ 109 150 224 46 87 219 138 26 250 101 109 34 233 189 225 112
+ 126 213 168 70 221 137 52 247 111 194 91 140 28 136 249 166
+ 118 114 121 192 160 116 224 166 24 71 111 203 163 173 194
+ 248 234 5 98 204 146 89 170 152 115 187 239 66 223 99 5 148
+ 225 63 157 62 106 105 99 25 48 42 199 183 39 190 104 203
+ 189 29 230 179 1 21 83 112 249 143 111 238 172 37 48 14 133
+ 210 188 109 107 241 144 164 50 46 209 151 99 130 13 116 78
+ 131 56 158 218 20 150 81 189 80 13 158 131 235 85 223 195
+ 94 156 59 143 226 99 12 217 225 135 21 108 90 233 166 36 79
+ 10 30 0 239 88 172 152 218 198 23 133 149 225 96 185 238
+ 126 148 254 207 12 187 34 137 143 243 63 165 35 182 146 88
+ 80 35 67 128 79 239 15 240 253 41 148 55 50 71 3 198 155
+ 223 63 59 227 185 250 86 20 246 175 9 49 238 137 75 194 7
+ 14 59 26 171 122 185 101 146 252 170 221 70 138 79 57 171
+ 19 90 190 184 150 223 207 136 198 60 160 85 91 173 91 79
+ 121 123 35 126 42 20 85 57 229 143 253 169 39 236 52 59 21
+ 95 71 52 120 85 189 141 19 24 193 61 254 181 38 232 109 62
+ 56 84 95 120 139 52 177 12 70 23 208 251 210 8 45 33 102 62
+ 35 69 113 183 143 43 28 138 150 244 28 129 53 1 12 177 109
+ 133 56 69 30 223 90 89 71 145 87 58 90 44 222 153 135 108
+ 45 112 24 137 64 59 200 35 39 138 160 63 202 143 164 236
+ 110 35 77 90 16 177 220 71 31 157 207 118 63 203 255 0 95
+ 210 186 59 76 240 101 45 113 224 67 10 200 219 34 218 152
+ 57 168 199 95 116 226 234 154 109 212 19 66 158 32 207 206
+ 14 8 193 237 93 81 141 66 145 199 109 202 217 193 218 38
+ 143 125 172 92 206 182 82 120 115 194 3 167 250 199 216 81
+ 186 229 182 179 114 195 76 184 142 52 153 64 252 208 57 63
+ 83 79 238 108 238 58 51 172 102 142 72 93 32 119 36 100 119
+ 25 197 72 174 109 109 245 43 132 213 172 128 119 83 202 159
+ 81 83 166 116 173 171 43 142 148 209 167 210 53 87 186 109
+ 225 20 130 8 29 254 212 255 0 168 117 88 99 189 18 151 121
+ 75 184 112 15 163 10 115 169 205 104 214 160 109 219 47 168
+ 3 24 168 70 191 34 35 161 50 198 74 190 79 218 171 23 76 95
+ 199 68 203 87 214 37 213 236 26 53 97 28 146 199 220 255 0
+ 102 42 186 135 166 111 237 101 123 191 50 170 19 133 35 150
+ 251 84 183 68 104 4 177 177 98 112 6 125 170 84 82 27 248
+ 197 189 188 97 156 253 56 169 202 77 176 113 118 65 83 78
+ 215 58 130 206 36 216 150 214 208 121 188 131 131 250 210
+ 254 157 210 219 80 215 226 210 252 97 8 241 48 197 189 106
+ 194 214 117 11 77 19 76 125 54 215 30 57 82 9 28 3 79 255 0
+ 201 219 162 228 212 181 51 171 222 70 35 241 27 10 204 14
+ 59 131 237 70 9 216 217 101 20 182 116 135 194 61 10 223 71
+ 233 107 107 59 21 100 11 15 159 61 137 250 208 157 71 12 97
+ 154 215 143 1 137 222 171 83 13 26 218 43 88 139 75 108 35
+ 139 110 197 57 225 143 189 38 234 185 161 181 211 101 183
+ 48 140 177 224 142 226 182 98 56 211 178 137 234 75 3 103
+ 126 235 13 210 69 179 144 73 173 130 222 67 20 99 241 145
+ 191 102 220 13 27 168 199 28 215 18 77 53 184 93 195 130 79
+ 106 16 88 52 155 213 111 32 12 167 182 227 255 0 106 132
+ 186 59 155 209 97 116 84 108 85 3 72 36 56 192 34 167 80 70
+ 200 128 172 81 179 175 24 61 234 176 232 167 154 223 242
+ 154 101 45 191 131 159 165 88 208 95 93 44 106 165 81 128
+ 31 50 250 211 199 212 228 105 169 108 211 171 31 16 177 142
+ 51 27 145 202 159 74 142 94 195 25 140 200 192 22 94 114 87
+ 52 250 250 105 35 117 104 83 45 234 27 185 165 119 214 183
+ 19 184 62 25 85 110 227 183 52 76 85 255 0 17 132 154 166
+ 147 37 186 248 46 20 21 7 110 222 125 170 129 155 79 252 60
+ 230 39 32 182 79 145 107 171 122 135 68 142 75 86 221 25 92
+ 100 146 59 26 162 186 143 167 38 135 88 220 138 165 119 28
+ 30 107 24 133 203 14 207 44 159 150 79 240 175 99 75 110 45
+ 85 216 243 83 62 164 210 229 135 108 166 18 138 125 248 34
+ 163 110 129 92 228 86 17 232 71 37 152 0 226 130 158 215
+ 239 82 48 136 202 124 190 180 37 197 190 92 129 142 244 105
+ 152 143 205 19 33 242 127 109 63 233 213 252 149 242 146
+ 217 228 214 155 139 85 10 78 40 189 15 8 59 113 154 120 166
+ 96 249 147 50 29 220 26 211 168 68 19 72 186 62 190 11 147
+ 246 162 174 15 230 134 247 21 167 84 255 0 50 221 55 24 107
+ 119 24 162 97 14 159 36 102 218 32 205 180 248 116 198 213
+ 226 87 83 188 147 154 81 107 167 220 53 140 18 7 35 242 249
+ 163 44 237 37 105 17 119 28 131 147 82 28 156 233 82 143 18
+ 49 232 69 79 180 187 75 121 32 92 220 73 28 184 249 68 69
+ 133 65 186 106 197 231 158 36 49 201 38 61 87 210 174 190
+ 145 211 94 68 137 95 195 66 171 140 177 231 245 172 97 191
+ 72 233 106 109 6 103 93 195 186 142 230 167 58 110 155 149
+ 2 36 4 1 146 204 199 138 15 167 44 108 128 241 124 25 230
+ 127 226 240 71 203 82 107 123 49 34 172 113 248 241 71 156
+ 226 65 131 88 87 42 6 22 110 1 241 219 196 92 121 84 129
+ 138 211 5 149 227 238 88 149 84 19 252 93 170 65 111 103
+ 146 84 149 104 151 251 65 172 166 82 241 42 66 205 41 31
+ 194 220 17 253 148 44 28 209 92 245 109 181 212 113 110 220
+ 74 129 192 30 181 84 206 151 127 141 151 198 194 3 192 4
+ 213 229 213 154 108 146 218 14 114 49 230 95 229 174 127
+ 235 72 166 211 53 41 87 12 242 147 223 39 129 83 156 188
+ 139 225 142 218 26 233 208 201 11 157 171 16 82 114 78 78
+ 106 95 211 141 17 148 180 69 153 211 137 31 248 84 253 106
+ 187 210 229 27 98 154 234 102 10 87 29 253 106 99 211 247
+ 50 71 229 137 138 237 243 73 143 226 31 90 220 138 100 73
+ 45 23 31 79 177 184 177 104 84 141 225 195 120 141 198 71
+ 208 83 253 66 55 75 114 242 175 137 43 240 0 25 207 21 16
+ 233 137 18 107 104 217 110 11 55 0 15 166 123 84 230 250
+ 120 225 136 200 204 200 137 128 8 25 197 118 65 218 60 188
+ 146 119 163 156 190 49 244 36 186 173 171 92 181 143 225
+ 228 44 85 153 187 143 94 42 128 158 223 90 233 105 158 56
+ 219 198 133 143 215 143 181 117 247 196 9 154 123 217 165
+ 105 34 104 200 206 194 249 195 127 241 84 31 89 91 238 184
+ 157 99 133 30 82 55 40 29 143 214 169 197 23 199 41 112 162
+ 186 185 214 103 186 102 123 219 95 57 239 33 24 3 251 42 61
+ 172 120 51 36 69 109 119 3 47 206 61 78 15 21 33 184 142
+ 230 221 222 9 70 84 15 54 125 169 116 176 205 24 93 141 132
+ 241 6 6 59 26 159 17 249 72 198 214 241 98 108 27 117 4 224
+ 149 92 211 111 252 65 168 64 98 75 43 87 17 129 229 44 56
+ 199 233 205 3 107 110 99 99 52 152 50 150 56 99 237 154 123
+ 211 176 77 38 160 37 101 223 31 177 237 70 43 246 110 82 10
+ 232 190 141 212 53 205 71 241 87 143 28 140 88 121 125 43
+ 171 254 26 232 50 233 22 137 111 248 16 144 42 133 223 142
+ 9 170 163 225 212 126 10 143 13 109 192 115 128 31 230 253
+ 42 249 232 235 223 11 77 134 25 36 73 90 110 236 15 57 166
+ 215 194 25 174 84 55 189 178 97 21 188 74 235 225 15 54 210
+ 121 53 5 235 9 86 234 105 118 131 187 119 150 33 243 84 243
+ 168 21 134 153 148 145 35 216 255 0 49 238 56 170 163 172
+ 110 246 221 148 183 185 203 147 193 90 134 99 163 9 14 213
+ 90 57 49 224 176 111 230 87 226 144 79 4 139 52 147 43 196
+ 140 253 129 124 12 209 122 205 212 6 227 198 110 1 242 103
+ 63 197 239 81 141 94 238 226 25 194 40 87 70 244 127 81 244
+ 174 103 45 29 138 28 145 48 233 15 198 27 192 146 18 27 119
+ 163 2 63 76 85 189 164 89 221 73 26 42 185 200 28 131 85
+ 191 195 29 42 75 141 146 194 172 24 159 144 255 0 15 30 149
+ 113 233 150 55 16 170 135 252 206 60 210 123 85 99 234 114
+ 229 146 230 1 29 155 9 135 226 87 9 252 254 162 190 157 54
+ 73 150 76 206 179 156 121 119 112 64 253 42 68 34 23 10 4
+ 109 226 159 76 208 151 54 110 238 87 196 43 32 237 232 7
+ 222 137 62 104 132 107 26 118 99 219 226 136 152 14 121 205
+ 86 125 99 167 175 237 5 105 110 23 96 62 102 65 87 101 229
+ 188 101 30 59 139 121 159 159 51 70 50 13 67 181 253 46 209
+ 204 177 194 198 53 217 156 74 7 6 176 201 217 68 117 172 48
+ 8 222 72 228 50 38 223 33 116 108 230 160 19 129 180 62 59
+ 174 113 87 71 94 233 47 38 158 234 139 184 43 97 86 169 187
+ 184 158 34 241 200 48 85 138 129 236 43 2 74 221 128 250
+ 103 222 176 101 39 229 25 53 159 210 179 135 230 170 115 85
+ 64 52 201 22 80 150 24 56 161 172 78 217 8 0 119 166 23 142
+ 190 27 113 233 75 237 10 155 130 2 253 105 224 237 24 105
+ 58 110 10 223 74 18 255 0 63 178 110 193 244 129 218 143
+ 149 149 99 11 142 72 160 117 31 243 85 217 61 204 78 15 218
+ 131 236 193 186 90 198 116 139 76 50 159 232 201 254 21 240
+ 8 214 109 220 18 57 24 165 154 124 231 246 109 170 238 218
+ 22 221 20 215 212 185 118 155 195 29 189 234 35 147 62 151
+ 185 63 180 227 85 109 196 243 145 232 125 170 240 233 87
+ 154 98 130 117 42 224 113 159 90 231 254 159 141 77 220 110
+ 210 109 243 14 213 208 95 13 174 45 209 81 90 100 44 23 203
+ 187 146 127 178 177 139 91 167 68 45 106 163 233 147 24 238
+ 194 164 246 194 223 193 93 177 201 193 236 190 159 122 65
+ 161 25 226 95 204 138 16 51 198 79 27 105 254 159 226 186
+ 121 152 39 60 39 253 105 146 178 13 219 8 84 102 112 4 112
+ 237 246 207 52 108 80 71 23 155 240 209 243 245 175 145 32
+ 81 150 82 62 181 181 229 80 128 114 126 212 234 128 38 234
+ 59 17 121 1 113 181 118 131 149 240 176 107 157 254 36 105
+ 145 172 225 132 94 57 82 119 47 168 174 150 190 241 164 6
+ 72 31 195 35 212 142 106 176 235 237 5 174 124 86 101 12
+ 216 221 187 24 57 164 156 20 138 96 157 62 69 19 13 184 134
+ 214 71 243 120 132 102 52 147 248 105 222 141 61 221 194
+ 172 215 18 131 50 12 125 90 134 154 19 103 168 120 18 237
+ 96 217 0 125 104 103 241 173 101 252 106 134 27 79 111 74
+ 229 105 166 119 57 114 90 45 126 140 184 86 180 102 55 40 8
+ 237 205 78 191 31 60 86 95 135 107 229 220 190 111 47 36
+ 241 242 213 27 163 234 202 176 41 241 140 81 191 112 123
+ 211 185 186 180 219 217 198 209 221 168 144 143 56 99 206
+ 43 167 30 95 140 228 201 141 223 67 62 185 190 0 22 88 89
+ 78 194 89 166 24 85 62 245 68 234 173 20 200 146 120 151 15
+ 39 140 216 192 249 177 223 21 100 234 93 81 167 222 233 242
+ 121 135 138 27 206 9 24 97 75 172 109 244 123 201 222 118
+ 186 72 146 21 59 6 6 11 55 106 235 82 137 57 41 69 21 69
+ 244 107 60 211 93 169 222 178 249 75 55 4 26 2 230 55 93
+ 145 140 130 91 129 142 245 120 75 240 222 29 147 220 75 118
+ 30 222 100 81 28 157 134 226 70 72 166 215 191 0 76 154 124
+ 23 81 107 2 210 70 149 7 157 187 131 233 218 133 196 73 100
+ 226 172 231 200 35 12 21 130 144 9 218 51 234 105 173 147
+ 53 180 47 106 237 55 154 81 38 213 29 143 181 92 250 183
+ 193 155 93 2 226 207 241 55 27 217 230 97 184 158 15 181 0
+ 157 15 107 160 194 127 107 93 71 0 157 155 135 97 207 177
+ 173 113 30 18 114 86 36 232 155 166 181 212 229 142 20 15
+ 143 149 27 248 143 181 95 61 33 125 178 213 99 141 94 2 163
+ 115 73 32 242 131 237 84 149 189 254 147 167 202 177 171
+ 167 138 174 4 135 0 227 235 82 24 186 206 56 238 36 138 210
+ 113 176 227 37 143 31 165 36 164 146 26 172 183 53 139 233
+ 37 145 47 13 228 65 72 33 147 61 170 172 234 89 213 239 76
+ 97 195 43 49 243 10 217 127 212 139 61 152 48 202 93 149
+ 124 192 17 222 162 154 181 244 173 190 4 254 177 41 201 39
+ 176 251 87 62 73 166 138 98 139 176 77 70 226 105 110 227
+ 128 248 50 89 41 255 0 238 31 106 9 108 115 118 169 36 98
+ 88 216 249 95 209 13 31 102 134 210 220 137 35 60 142 239
+ 220 83 222 137 209 164 212 174 195 188 108 235 158 0 251
+ 215 53 72 232 121 20 116 139 19 225 174 154 190 12 107 17
+ 119 219 130 199 244 255 0 10 182 236 213 161 183 40 171 147
+ 237 81 142 150 210 174 172 237 217 18 40 227 82 0 5 187 212
+ 174 22 216 118 158 113 234 59 26 234 132 93 108 243 231 92
+ 172 209 53 180 127 188 240 78 87 156 30 213 161 217 164 25
+ 154 48 24 118 49 242 113 76 193 89 99 56 237 67 205 20 120
+ 199 202 125 13 55 16 8 111 196 76 140 161 37 39 25 203 14
+ 213 1 234 117 1 164 101 229 74 96 55 189 88 23 183 19 70
+ 204 138 137 142 217 62 181 21 215 72 134 54 150 70 183 84
+ 245 221 158 63 186 183 18 176 119 162 142 235 107 139 179
+ 101 112 48 74 131 149 250 213 55 169 21 153 101 109 195 118
+ 226 49 87 143 197 11 59 89 172 228 240 238 163 86 11 193 86
+ 242 213 7 168 41 183 153 227 13 189 119 119 20 133 31 26 4
+ 138 53 225 183 114 56 162 35 249 141 99 16 93 166 190 134
+ 10 199 218 177 51 11 207 221 183 218 128 179 230 224 227
+ 154 97 117 242 31 181 45 179 202 206 87 215 189 82 14 145
+ 135 197 65 136 103 142 40 13 74 48 116 219 220 28 255 0 70
+ 122 48 73 249 67 52 22 160 196 88 93 242 60 240 56 20 89
+ 132 246 173 33 176 131 211 242 147 181 25 98 164 202 55 122
+ 241 90 172 99 38 202 223 63 232 146 141 137 10 48 53 33 195
+ 237 36 17 76 55 59 140 28 241 86 191 194 221 82 71 187 85
+ 134 86 137 241 229 144 138 169 145 73 66 203 220 28 154 150
+ 252 57 214 154 199 83 71 134 72 163 97 235 39 106 198 58
+ 223 67 121 30 205 68 246 178 34 103 201 57 60 49 250 84 166
+ 202 250 59 114 171 42 153 28 140 2 7 97 80 110 157 214 5
+ 238 147 18 27 150 57 60 113 156 126 149 55 208 161 152 66
+ 38 143 136 200 198 120 57 63 173 89 164 186 57 199 169 35
+ 72 23 119 0 142 213 189 35 81 233 199 181 13 8 118 33 179
+ 192 224 209 101 148 32 227 154 6 62 50 174 119 99 129 233
+ 74 122 130 205 110 173 152 236 11 246 29 233 163 72 161 114
+ 71 21 131 48 145 10 178 239 83 233 237 65 179 45 20 167 88
+ 244 52 211 91 27 203 104 80 178 18 119 122 231 218 171 11
+ 187 123 200 110 31 78 189 93 162 67 243 123 87 79 107 176
+ 53 157 147 186 43 75 17 238 139 232 125 234 136 248 146 177
+ 73 114 100 84 96 155 185 13 195 126 181 25 70 203 225 156
+ 147 164 35 210 116 152 166 184 16 52 171 42 149 202 236 247
+ 170 207 226 54 139 175 105 90 204 242 61 196 190 11 28 198
+ 83 149 219 237 83 222 151 214 197 133 218 194 100 240 225
+ 249 67 96 114 61 170 196 212 52 152 117 189 17 90 56 209
+ 212 12 238 35 56 21 60 77 73 157 83 132 226 185 72 228 251
+ 45 112 139 146 26 86 59 20 134 4 156 22 162 52 205 98 226
+ 222 203 242 166 62 57 186 18 54 227 193 3 211 237 83 78 185
+ 248 112 99 190 184 149 45 13 188 32 231 116 125 152 213 121
+ 169 104 183 182 101 130 238 0 252 153 238 5 116 62 206 120
+ 228 82 123 39 58 151 88 245 117 197 134 159 165 75 124 86
+ 218 24 205 202 70 184 218 7 177 53 60 215 254 43 117 237
+ 199 75 232 182 247 182 18 89 199 225 44 214 243 173 187 21
+ 184 10 123 130 51 199 189 115 249 107 184 36 221 151 221
+ 141 188 156 241 237 82 109 7 226 31 89 104 177 71 109 109
+ 172 94 4 130 217 160 129 50 8 138 54 238 160 17 218 154 133
+ 88 87 254 139 31 226 175 196 126 181 234 43 13 48 94 88 61
+ 132 70 63 26 222 88 247 33 125 191 196 51 233 144 106 29
+ 212 157 103 212 58 189 165 140 186 165 244 83 35 32 88 176
+ 131 32 47 114 126 181 19 213 186 147 168 117 153 33 159 81
+ 212 174 238 154 217 12 80 120 178 110 240 211 249 71 211
+ 147 66 44 55 19 90 71 181 75 159 155 25 236 115 90 135 73
+ 46 221 140 238 53 67 251 78 238 95 20 178 77 146 50 121 205
+ 104 210 245 75 139 217 34 181 134 232 137 3 16 192 3 154 47
+ 67 232 251 173 64 201 227 187 71 35 225 148 14 248 207 106
+ 185 62 27 244 16 178 195 61 132 105 48 148 18 242 96 22 95
+ 214 132 163 171 4 230 170 162 7 208 29 47 125 30 141 53 238
+ 172 242 178 203 251 188 30 64 199 253 232 177 103 28 123
+ 100 241 137 149 120 84 110 199 239 83 126 177 191 182 208
+ 237 37 183 143 116 44 56 85 36 55 24 244 170 238 202 83 123
+ 118 94 66 67 19 148 106 228 116 203 168 73 18 94 153 233
+ 253 83 95 144 76 202 76 46 112 163 31 227 87 31 73 116 153
+ 210 204 49 204 170 14 1 194 210 111 135 23 11 20 34 8 35
+ 145 159 56 201 3 21 104 90 90 27 93 175 36 126 35 176 206
+ 242 79 31 74 233 199 7 86 206 60 143 97 118 241 133 77 187
+ 118 129 233 239 91 90 53 199 28 125 171 21 155 60 50 225
+ 171 238 252 119 170 217 42 53 58 136 187 51 42 250 129 65
+ 234 23 94 12 69 100 143 35 221 123 138 60 149 151 229 20 27
+ 169 71 219 252 62 223 90 1 35 215 115 43 40 113 32 251 55
+ 124 84 47 171 100 186 49 179 184 154 201 65 231 124 91 149
+ 170 85 173 98 202 233 252 103 42 224 121 152 199 145 223
+ 251 170 186 248 147 214 183 90 125 177 91 107 171 105 7 250
+ 223 246 53 138 68 162 190 47 107 186 95 138 214 49 248 190
+ 48 28 73 25 198 223 211 181 87 209 0 214 161 139 51 100 247
+ 110 244 87 94 106 67 88 234 55 186 240 194 31 92 113 154 14
+ 73 213 85 87 233 82 4 244 244 124 133 130 190 211 235 68 52
+ 89 229 73 52 2 183 155 121 163 109 174 50 160 131 233 88 17
+ 102 171 131 149 35 233 75 163 27 110 179 76 238 20 96 210
+ 213 254 179 85 198 149 14 54 149 179 26 231 142 61 41 102
+ 163 41 252 21 194 142 194 39 166 50 168 48 131 244 165 151
+ 202 63 5 63 251 167 162 251 17 183 102 122 48 63 179 160
+ 224 254 233 43 126 71 137 143 90 203 72 79 252 174 220 129
+ 222 36 197 18 45 198 75 17 81 101 227 217 227 251 146 61 77
+ 15 111 122 246 87 65 149 118 227 187 30 213 235 171 133 141
+ 128 57 237 90 226 219 121 34 110 71 40 7 56 28 154 186 143
+ 40 137 47 99 167 126 4 117 157 174 161 167 172 63 153 44
+ 136 120 24 171 231 78 212 65 81 225 218 249 118 231 115 28
+ 0 107 144 190 28 89 173 188 130 77 54 89 34 32 231 105 56
+ 39 237 138 178 180 238 161 234 84 87 102 17 76 136 48 6 9
+ 199 215 154 14 60 65 197 51 163 45 102 103 1 100 216 170
+ 121 5 78 69 99 169 220 54 192 163 201 236 199 214 170 77 11
+ 171 245 39 17 71 112 168 23 28 248 35 183 223 62 181 53 209
+ 175 226 185 45 33 153 131 255 0 44 188 98 164 251 19 36 117
+ 72 147 192 159 42 72 164 38 120 62 244 112 27 80 5 35 111
+ 160 165 118 19 120 142 1 96 223 202 1 230 152 44 168 80 110
+ 202 243 142 105 211 64 173 30 154 21 153 25 100 25 82 48 69
+ 84 255 0 18 122 82 19 35 155 101 32 179 100 10 183 3 46 56
+ 96 104 109 66 202 27 200 240 200 140 222 153 173 40 218 27
+ 28 169 232 228 91 238 152 186 91 147 43 63 135 20 71 60 142
+ 255 0 74 125 211 93 69 117 98 88 93 200 22 221 92 4 207 160
+ 171 91 173 250 76 108 150 72 227 80 51 187 143 106 165 250
+ 146 41 68 141 111 29 187 8 213 253 185 205 113 188 124 37
+ 103 124 36 178 42 147 44 121 46 108 53 205 177 220 69 249
+ 108 155 65 247 250 212 119 170 190 23 217 155 104 37 134
+ 225 10 63 203 143 240 164 218 37 252 214 58 188 112 204 228
+ 64 202 48 79 189 89 90 93 253 188 177 237 89 214 103 253
+ 214 210 123 15 113 245 170 71 43 229 103 52 177 46 52 138
+ 27 93 248 99 116 151 210 44 86 251 160 69 196 44 163 211
+ 220 84 30 247 64 107 107 182 140 171 56 31 46 7 173 118 133
+ 237 180 90 149 144 93 194 54 141 118 57 42 57 250 138 137
+ 106 125 33 167 197 120 100 88 86 104 216 96 101 107 174 50
+ 199 37 105 28 235 179 155 116 14 140 186 212 193 240 55 51
+ 49 206 208 188 226 167 125 55 240 195 54 203 45 210 186 72
+ 143 198 70 55 15 122 186 52 46 153 179 177 138 55 182 217
+ 20 217 228 99 140 83 173 90 104 225 84 141 97 141 86 49 134
+ 36 96 181 53 165 234 138 37 201 144 171 110 135 210 116 79
+ 10 226 121 20 205 225 229 4 124 130 107 238 173 212 150 246
+ 54 203 105 24 72 156 55 151 216 241 254 53 171 169 181 136
+ 109 237 36 219 112 30 68 114 145 166 114 77 87 147 73 121
+ 168 91 139 182 87 46 210 121 71 176 174 73 101 116 209 214
+ 176 213 51 45 96 106 26 245 227 195 122 216 99 204 45 232 5
+ 54 233 30 147 152 202 177 205 147 199 3 20 227 163 244 134
+ 213 30 40 228 140 164 138 70 25 187 26 185 250 111 167 99
+ 183 132 60 209 70 37 3 154 92 80 79 108 76 217 56 233 25
+ 116 63 79 219 217 233 161 221 79 138 125 79 165 74 23 229
+ 25 227 28 115 88 194 137 12 33 19 140 119 175 179 58 38 55
+ 56 31 90 233 163 142 105 182 99 58 163 46 230 96 160 118
+ 165 215 146 52 67 197 102 150 48 222 168 51 69 207 44 126
+ 25 60 176 250 14 212 174 246 96 84 171 178 178 5 200 32 240
+ 69 103 163 40 114 26 137 15 135 230 81 199 203 187 179 80
+ 83 95 73 202 136 33 56 255 0 91 154 134 235 29 68 108 99 48
+ 219 9 166 0 124 199 24 63 110 106 11 172 117 110 189 53 203
+ 197 225 196 233 140 169 112 114 181 135 88 210 44 46 168
+ 215 33 143 79 157 228 73 85 84 16 222 249 250 87 37 124 96
+ 235 11 91 205 78 75 11 75 153 21 131 19 137 70 56 171 39 86
+ 212 53 237 70 57 32 188 185 82 161 14 28 13 187 87 254 188
+ 213 69 213 58 29 188 241 201 42 67 113 123 118 92 225 136 0
+ 99 251 107 112 79 232 106 136 45 172 37 228 105 14 112 123
+ 31 122 33 161 221 231 60 55 108 125 40 217 99 104 81 97 112
+ 145 183 177 239 65 22 96 73 244 237 74 218 163 27 60 53 9
+ 206 43 43 104 195 112 57 172 21 183 33 251 215 212 98 157
+ 142 13 32 12 175 65 7 145 74 155 137 197 57 148 111 83 187
+ 154 73 38 127 24 71 165 60 69 147 25 187 226 49 142 120 165
+ 247 103 117 189 217 247 183 113 250 209 172 165 163 31 106
+ 22 244 40 211 231 199 205 225 62 105 133 25 233 30 109 42
+ 213 113 140 198 159 225 154 57 216 44 44 48 59 119 160 52
+ 103 85 211 44 148 142 76 8 127 93 180 85 196 171 225 242 42
+ 71 74 116 70 181 2 242 94 14 113 199 97 247 169 87 65 219
+ 36 215 177 195 40 220 8 228 47 113 253 180 141 109 252 107
+ 213 37 60 184 239 237 83 174 143 211 149 39 87 0 110 35 200
+ 195 131 138 180 102 170 137 190 236 187 58 103 166 236 35
+ 48 52 114 32 24 221 133 249 170 91 107 165 194 210 5 148 4
+ 24 192 56 168 247 77 204 176 89 68 222 55 138 83 229 76 14
+ 126 149 52 209 238 55 145 226 76 129 217 126 87 3 129 90 82
+ 85 70 74 194 44 116 24 227 153 78 119 103 182 208 48 71 214
+ 155 92 104 236 214 174 17 76 111 252 203 220 211 109 38 72
+ 100 140 6 240 164 218 118 249 123 230 152 203 11 109 9 28
+ 140 152 244 32 100 84 69 110 136 158 149 251 66 218 111 194
+ 218 184 47 158 78 114 5 72 45 159 86 128 156 172 114 40 93
+ 204 199 57 253 41 93 196 81 199 127 137 15 131 38 120 34
+ 155 219 106 64 58 195 28 121 80 57 111 115 72 60 23 137 178
+ 29 74 89 38 86 154 45 171 252 195 176 251 209 173 121 8 5
+ 150 64 9 249 72 245 173 55 48 174 4 182 234 178 49 30 104
+ 207 111 191 222 180 189 188 19 219 238 145 124 39 95 238
+ 166 78 76 87 75 160 203 219 113 121 98 20 190 254 57 35 214
+ 161 183 93 11 13 220 146 220 54 84 224 236 80 7 38 165 58
+ 35 53 189 185 93 199 104 244 166 73 134 1 135 108 230 179
+ 175 160 230 215 69 41 170 244 5 221 179 37 204 176 248 171
+ 17 59 84 14 231 235 81 248 244 109 67 78 159 196 11 34 144
+ 251 184 245 174 141 101 220 140 49 201 239 154 73 168 104
+ 208 238 105 240 173 207 153 113 72 240 193 236 172 103 162
+ 162 147 168 46 237 252 56 132 78 217 143 156 131 205 101
+ 107 212 23 37 89 165 134 70 77 222 78 15 53 53 189 211 108
+ 154 225 166 107 120 194 42 144 191 65 65 219 221 104 214 54
+ 107 248 235 88 252 36 82 219 206 125 234 111 148 53 101 249
+ 127 194 40 122 138 227 204 86 41 3 231 142 15 106 211 125
+ 123 169 234 176 162 109 146 54 3 146 163 189 74 236 166 211
+ 53 75 176 109 97 70 129 135 151 138 145 105 90 109 177 111
+ 195 248 9 145 242 253 41 146 151 105 153 78 190 21 78 149
+ 210 55 151 72 200 33 98 31 141 199 146 15 189 75 116 79 135
+ 114 8 209 111 35 196 123 118 140 119 31 90 179 52 205 54 27
+ 24 246 140 125 168 227 207 113 84 73 62 200 203 249 18 122
+ 100 95 167 186 102 29 46 97 225 64 133 23 213 187 231 222
+ 164 83 203 28 108 25 164 31 111 122 251 43 108 224 71 147
+ 239 154 80 109 218 109 77 228 152 17 30 121 25 239 77 72
+ 156 83 126 193 247 23 107 26 144 60 205 232 40 24 111 174
+ 166 111 14 8 145 142 78 75 103 138 222 87 50 5 130 208 2 59
+ 190 79 21 153 11 103 110 207 18 6 62 173 236 105 28 218 10
+ 236 85 123 38 178 45 252 88 165 81 144 67 32 30 148 134 222
+ 198 235 80 184 114 210 22 10 249 108 30 62 195 233 79 46 46
+ 86 123 98 100 102 137 7 30 94 228 214 26 28 69 220 52 56 95
+ 109 180 109 181 108 51 175 245 23 221 104 208 203 25 13 31
+ 229 129 194 251 210 27 221 6 56 84 182 239 46 120 12 163 2
+ 172 115 20 110 160 110 19 183 169 110 21 62 216 168 230 179
+ 52 101 156 43 64 138 157 234 170 104 69 127 74 251 80 209
+ 225 184 180 144 51 194 168 14 15 166 106 191 234 221 39 75
+ 179 211 165 184 146 21 154 112 126 84 98 23 245 171 39 87
+ 185 202 186 49 71 82 114 25 71 106 174 122 230 37 156 40 50
+ 77 55 180 64 0 15 246 86 228 53 20 87 81 74 130 251 153 35
+ 67 39 101 143 36 99 238 104 9 50 234 54 142 213 35 235 13
+ 19 195 45 36 96 65 27 252 170 57 231 245 168 229 186 201 20
+ 4 73 195 103 24 247 20 128 122 116 122 47 148 253 235 9 178
+ 172 72 247 172 226 32 3 159 122 215 63 53 128 213 133 195
+ 34 136 200 60 253 233 61 209 254 151 156 12 102 155 69 26
+ 176 198 222 244 166 249 130 92 5 250 211 196 70 168 105 11
+ 47 131 230 224 80 87 255 0 212 238 63 221 191 248 86 208
+ 219 160 3 210 133 190 99 248 41 249 255 0 210 122 167 17 92
+ 141 118 127 137 253 159 1 207 30 18 86 196 51 186 156 182
+ 87 212 211 13 50 12 216 64 27 31 186 76 140 246 162 217 225
+ 136 120 123 80 41 224 115 206 106 40 232 98 43 123 241 111
+ 55 242 128 113 147 235 86 7 70 235 76 246 230 31 197 68 140
+ 195 200 164 237 96 62 135 214 163 182 90 28 218 158 99 130
+ 221 164 59 178 0 198 15 235 239 83 110 151 232 9 102 141 45
+ 238 237 102 138 39 28 156 252 191 98 41 210 160 39 68 255 0
+ 165 250 138 212 58 193 170 73 178 233 134 228 73 134 1 30
+ 245 97 104 186 198 154 206 169 103 118 214 236 71 158 25
+ 198 232 228 63 70 244 168 62 133 208 169 21 164 118 179 70
+ 211 148 27 99 71 200 199 234 65 53 34 178 233 77 74 194 47
+ 232 114 58 143 68 151 133 31 99 89 171 11 157 178 203 176
+ 99 185 30 56 210 54 198 74 171 102 50 61 193 247 166 203
+ 120 56 63 32 61 188 78 23 244 53 94 105 26 213 214 151 34
+ 65 172 88 220 66 190 147 198 165 215 63 92 122 84 202 206
+ 234 75 168 188 68 219 34 158 79 151 1 190 191 74 70 19 118
+ 187 11 222 67 44 177 177 18 6 220 184 239 75 186 90 250 71
+ 102 183 153 124 225 176 64 244 250 211 153 97 142 226 50
+ 193 164 82 7 96 188 138 91 106 39 134 247 250 138 202 231
+ 141 231 130 71 181 35 84 131 21 240 154 167 49 34 238 13
+ 199 24 160 103 45 29 214 214 82 84 247 241 56 81 69 217 110
+ 49 40 48 52 89 28 140 19 254 21 246 250 214 73 151 104 141
+ 217 125 8 28 212 219 108 77 38 107 71 120 216 109 66 69 16
+ 38 82 128 134 28 156 80 86 73 58 66 99 117 124 158 57 70
+ 255 0 181 100 201 60 78 89 81 153 49 200 8 114 63 186 130
+ 116 48 99 44 138 63 45 178 123 226 132 186 185 120 226 220
+ 97 102 63 196 69 97 52 178 170 171 68 178 242 57 204 109
+ 255 0 106 85 169 92 92 179 21 69 112 185 231 32 138 22 195
+ 24 41 50 63 213 151 154 140 182 87 118 246 208 73 27 225
+ 138 101 126 149 203 122 183 93 117 30 165 38 161 167 94 204
+ 208 248 19 164 109 30 48 78 61 8 174 179 185 188 189 92 25
+ 97 105 87 248 252 157 197 85 223 17 250 3 72 234 125 66 13
+ 98 214 217 180 157 71 112 23 37 99 32 78 61 73 24 239 79 39
+ 25 157 120 230 177 233 171 1 248 55 105 213 17 233 144 222
+ 220 248 50 217 52 132 194 7 204 23 255 0 154 187 244 141 66
+ 229 131 52 208 177 193 218 131 28 154 143 104 115 197 97
+ 103 13 142 159 96 237 28 40 168 143 225 156 240 63 252 52
+ 217 46 47 152 134 48 50 182 253 196 178 145 71 81 68 114 91
+ 118 137 97 184 157 190 85 49 159 102 172 252 67 180 110 96
+ 88 154 77 109 119 50 219 170 24 228 45 252 71 109 24 101
+ 102 64 162 57 11 247 225 73 197 73 79 147 209 37 141 160
+ 167 186 40 14 197 220 115 130 7 165 7 113 54 223 48 243 159
+ 85 126 194 182 71 11 42 110 109 229 255 0 216 108 127 133
+ 105 72 101 150 243 196 145 88 133 236 2 54 15 247 83 59 176
+ 85 5 105 241 55 134 93 243 188 118 52 46 171 34 67 3 185
+ 145 93 199 101 3 36 83 68 142 84 92 172 100 125 233 38 189
+ 36 203 4 135 240 108 231 30 163 138 165 94 128 145 12 135
+ 241 90 158 160 99 86 111 12 54 91 105 201 21 39 134 85 183
+ 137 98 82 177 198 6 60 79 251 82 189 46 217 152 134 104 12
+ 1 142 78 208 114 104 235 213 217 228 142 57 60 188 6 101
+ 237 246 166 173 81 154 62 94 77 44 150 225 83 42 23 213 199
+ 155 244 21 29 213 174 34 181 133 247 220 69 1 3 45 52 190
+ 103 31 65 255 0 106 47 91 215 45 44 81 252 95 21 220 29 171
+ 26 33 44 199 219 21 16 190 126 161 214 8 240 109 13 165 190
+ 237 202 146 99 113 250 241 154 41 1 161 62 179 175 104 240
+ 69 36 239 49 42 23 205 52 173 134 99 238 61 170 187 215 53
+ 233 37 34 230 214 241 150 215 186 60 131 195 76 125 9 239
+ 86 14 163 209 114 73 40 146 238 54 109 195 45 189 72 254
+ 193 138 135 117 47 195 150 190 148 93 78 178 76 35 253 216
+ 201 217 143 246 79 21 130 138 135 172 58 169 217 198 39 142
+ 64 252 43 3 197 34 211 238 191 16 134 70 238 220 131 232 69
+ 75 117 206 133 188 138 228 205 37 140 174 15 206 242 112
+ 168 61 197 71 36 129 44 93 193 85 69 221 181 85 152 3 143
+ 240 166 143 96 146 189 131 187 237 63 74 196 29 195 53 186
+ 102 73 6 236 167 232 192 255 0 133 106 85 227 140 99 239 79
+ 45 128 38 30 212 162 251 139 174 120 230 156 64 8 250 15
+ 189 1 168 70 11 124 188 147 223 35 20 189 9 35 116 37 90
+ 223 5 128 29 243 65 234 18 255 0 67 184 255 0 116 244 90 41
+ 16 1 142 195 222 151 106 24 252 61 194 110 27 188 54 227 61
+ 179 78 165 162 110 34 139 47 220 55 251 165 160 238 251 175
+ 251 85 234 245 73 118 116 190 131 109 63 174 219 83 53 253
+ 234 126 181 234 245 80 80 139 143 222 15 189 122 95 221 143
+ 189 122 189 88 198 235 207 234 95 253 163 252 107 86 155
+ 251 179 246 175 87 169 31 209 144 77 191 121 255 0 217 173
+ 49 127 90 95 246 133 122 189 74 198 143 99 214 236 104 22
+ 253 243 125 235 213 234 148 69 126 198 211 251 197 175 79
+ 251 179 94 175 80 8 60 191 187 95 181 100 191 184 74 245
+ 122 153 244 62 46 204 26 180 183 239 79 218 189 94 166 47
+ 30 205 144 126 248 81 147 250 215 171 213 136 100 236 244
+ 63 45 125 184 253 239 255 0 109 122 189 80 143 177 51 91
+ 252 181 157 167 205 94 175 85 95 208 154 161 175 147 126
+ 234 111 246 63 235 94 175 83 46 204 129 173 191 131 237 91
+ 117 15 221 138 245 122 156 192 58 215 249 246 111 247 149
+ 242 127 221 39 251 85 234 245 17 88 116 223 212 135 218 148
+ 220 254 224 87 171 212 16 77 109 253 105 105 76 159 214 222
+ 189 94 162 140 205 87 255 0 50 255 0 179 88 71 242 10 245
+ 122 156 64 133 253 217 161 174 254 85 255 0 106 189 94 165
+ 125 139 35 47 253 58 105 99 253 68 255 0 186 175 87 168 174
+ 133 63 255 217 13 10 45 45 45 45 45 45 87 101 98 75 105 116
+ 70 111 114 109 66 111 117 110 100 97 114 121 74 57 98 119
+ 65 87 115 51 121 110 112 113 115 72 53 75 13 10 67 111 110
+ 116 101 110 116 45 68 105 115 112 111 115 105 116 105 111
+ 110 58 32 102 111 114 109 45 100 97 116 97 59 32 110 97 109
+ 101 61 34 102 105 108 101 50 34 59 32 102 105 108 101 110
+ 97 109 101 61 34 116 101 115 116 46 116 120 116 34 13 10 67
+ 111 110 116 101 110 116 45 84 121 112 101 58 32 116 101 120
+ 116 47 112 108 97 105 110 13 10 13 10 116 101 115 116 10 13
+ 10 45 45 45 45 45 45 87 101 98 75 105 116 70 111 114 109 66
+ 111 117 110 100 97 114 121 74 57 98 119 65 87 115 51 121
+ 110 112 113 115 72 53 75 13 10 67 111 110 116 101 110 116
+ 45 68 105 115 112 111 115 105 116 105 111 110 58 32 102 111
+ 114 109 45 100 97 116 97 59 32 110 97 109 101 61 34 102 105
+ 108 101 51 34 59 32 102 105 108 101 110 97 109 101 61 34 34
+ 13 10 13 10 13 10 45 45 45 45 45 45 87 101 98 75 105 116 70
+ 111 114 109 66 111 117 110 100 97 114 121 74 57 98 119 65
+ 87 115 51 121 110 112 113 115 72 53 75 45 45 13 10
+ } ;
+
+: dog-test-empty-bytes-firefox ( -- bytes )
+ B{
+ 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45
+ 45 45 45 45 45 45 45 45 45 49 49 51 55 53 50 50 53 48 51 49
+ 52 52 49 50 56 50 51 50 55 49 54 53 51 49 55 50 57 13 10 67
+ 111 110 116 101 110 116 45 68 105 115 112 111 115 105 116
+ 105 111 110 58 32 102 111 114 109 45 100 97 116 97 59 32
+ 110 97 109 101 61 34 102 105 108 101 49 34 59 32 102 105
+ 108 101 110 97 109 101 61 34 100 111 103 46 106 112 103 34
+ 13 10 67 111 110 116 101 110 116 45 84 121 112 101 58 32
+ 105 109 97 103 101 47 106 112 101 103 13 10 13 10 255 216
+ 255 224 0 16 74 70 73 70 0 1 1 0 0 1 0 1 0 0 255 219 0 67 0
+ 5 3 4 4 4 3 5 4 4 4 5 5 5 6 7 12 8 7 7 7 7 15 11 11 9 12 17
+ 15 18 18 17 15 17 17 19 22 28 23 19 20 26 21 17 17 24 33 24
+ 26 29 29 31 31 31 19 23 34 36 34 30 36 28 30 31 30 255 219
+ 0 67 1 5 5 5 7 6 7 14 8 8 14 30 20 17 20 30 30 30 30 30 30
+ 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
+ 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30
+ 30 30 30 30 255 192 0 17 8 1 49 1 64 3 1 34 0 2 17 1 3 17 1
+ 255 196 0 29 0 0 2 2 3 1 1 1 0 0 0 0 0 0 0 0 0 4 5 6 7 2 3
+ 8 0 1 9 255 196 0 74 16 0 2 1 3 3 2 4 4 3 4 5 10 5 3 5 1 1
+ 2 3 0 4 17 5 18 33 6 49 19 34 65 81 7 50 97 113 20 35 129
+ 21 51 66 82 36 52 145 161 177 8 53 83 98 114 115 147 178
+ 193 209 22 37 67 116 241 99 130 240 23 68 84 100 146 225
+ 255 196 0 25 1 0 3 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 2 3 0 4 5
+ 255 196 0 39 17 0 2 2 2 2 3 0 2 1 5 1 0 0 0 0 0 0 1 2 17 3
+ 33 18 49 34 50 65 19 81 4 5 20 35 66 97 82 255 218 0 12 3 1
+ 0 2 17 3 17 0 63 0 228 200 149 136 219 131 200 207 233 68
+ 196 145 112 60 21 45 234 91 181 57 177 178 138 75 56 95 111
+ 152 196 51 250 209 11 167 198 14 118 138 22 138 153 104 150
+ 118 82 46 217 45 161 98 79 242 102 157 38 151 98 174 64 211
+ 237 72 247 49 46 104 11 8 140 111 229 247 166 194 70 137 12
+ 146 112 61 235 57 36 172 31 82 7 154 199 78 244 176 178 255
+ 0 132 41 100 195 76 15 183 240 118 60 31 244 85 237 126 241
+ 237 237 157 213 176 113 197 66 158 254 234 82 74 49 45 187
+ 144 42 49 155 158 217 108 152 99 21 68 214 88 116 217 83 17
+ 218 218 171 250 109 138 180 254 6 221 83 205 109 1 199 115
+ 225 10 141 90 106 23 106 187 95 59 73 239 237 77 44 111 89
+ 79 136 24 186 250 131 235 86 199 166 71 143 20 52 181 211
+ 237 24 143 232 150 236 61 140 66 155 65 167 233 251 64 252
+ 5 158 127 221 45 3 99 42 220 42 186 240 79 247 83 139 38 86
+ 92 21 57 20 76 246 140 78 155 98 88 31 217 246 125 191 209
+ 45 108 253 159 97 255 0 240 44 255 0 225 45 22 216 200 199
+ 181 99 88 74 98 77 99 78 178 69 111 14 194 213 23 28 226 48
+ 15 246 212 30 242 21 252 105 8 145 170 103 178 213 137 172
+ 121 162 127 181 87 151 141 182 247 31 235 210 180 216 209
+ 28 88 217 219 120 99 250 52 100 255 0 172 155 168 248 108
+ 109 11 103 240 208 127 194 173 118 82 71 225 47 148 246 163
+ 11 169 30 74 81 140 102 182 178 35 203 97 104 62 162 46 104
+ 41 45 109 119 127 86 131 254 21 48 144 225 9 198 104 105
+ 198 24 118 53 76 77 81 141 73 105 109 143 234 176 127 193
+ 21 146 89 219 110 63 209 97 255 0 131 69 65 183 110 15 39
+ 218 182 144 160 159 41 6 169 102 5 22 54 138 114 109 45 216
+ 123 24 184 53 177 45 44 137 231 79 179 237 254 138 179 118
+ 101 112 167 159 181 102 131 140 212 35 236 99 95 224 172
+ 119 143 252 190 207 254 21 18 186 125 129 92 254 2 207 254
+ 16 172 15 148 230 182 71 46 225 198 106 178 78 204 40 213
+ 237 109 83 33 45 224 237 223 195 199 247 214 189 30 222 222
+ 69 45 37 165 187 156 227 12 161 177 245 230 143 214 212 8
+ 75 123 138 15 69 96 7 220 214 159 169 135 31 129 177 192
+ 198 159 102 120 255 0 68 181 240 216 217 12 15 217 214 156
+ 246 252 165 230 137 139 205 235 128 7 204 123 80 183 154
+ 148 118 202 66 225 156 118 62 148 169 174 38 91 55 193 167
+ 233 191 60 214 22 96 14 249 137 107 84 199 69 137 246 174
+ 157 100 255 0 65 18 210 43 237 82 105 148 188 108 64 254 31
+ 102 164 243 223 204 146 249 155 39 233 73 38 50 84 137 156
+ 112 233 19 200 4 118 54 201 238 22 33 68 54 153 166 52 96
+ 173 149 163 15 115 16 205 66 244 189 77 141 226 40 115 143
+ 90 155 91 73 192 116 245 29 141 77 233 140 177 169 46 64
+ 109 167 88 45 203 31 217 246 92 127 244 171 19 97 99 226 16
+ 218 125 152 227 63 186 20 100 204 56 247 245 175 66 84 145
+ 191 147 235 246 174 140 125 18 180 125 183 211 108 72 7 246
+ 125 158 63 221 45 109 151 77 177 219 254 111 179 255 0 132
+ 180 68 76 163 133 206 51 197 103 43 0 184 166 158 144 72
+ 133 244 54 113 220 5 91 120 50 59 254 77 7 120 109 188 48
+ 22 8 1 207 242 98 152 106 170 191 137 45 239 218 149 93 41
+ 97 129 239 73 97 143 96 19 172 103 204 161 23 232 181 164
+ 71 152 93 143 173 110 117 101 67 90 142 239 195 55 165 97
+ 229 251 37 122 124 138 182 48 118 253 210 81 66 116 250 82
+ 123 2 205 103 108 55 30 99 31 221 218 140 134 63 56 221 200
+ 169 147 26 90 229 159 56 20 109 242 171 89 16 217 251 80
+ 214 190 80 49 197 110 212 63 168 147 234 107 74 62 44 166
+ 36 156 209 17 234 235 140 193 26 170 182 230 227 21 40 248
+ 113 208 240 234 214 169 53 194 224 63 166 57 168 167 85 55
+ 136 34 5 87 126 124 170 123 26 233 15 129 214 42 221 59 108
+ 123 112 51 27 14 223 90 142 61 68 233 206 227 249 58 35 7
+ 224 252 57 252 133 141 91 25 82 71 24 255 0 189 44 212 254
+ 21 222 99 16 171 120 139 234 160 97 171 165 99 81 143 5 145
+ 74 142 199 29 171 239 225 99 121 138 149 80 127 133 241 205
+ 22 229 96 121 19 84 145 199 250 231 77 106 61 62 210 25 35
+ 114 189 212 1 198 43 237 133 210 72 71 24 56 228 125 107
+ 167 186 179 163 236 245 93 61 149 35 76 148 42 43 154 186
+ 195 167 175 58 123 85 149 9 37 67 103 63 74 117 39 123 37
+ 151 26 110 226 20 14 64 53 246 132 211 174 22 234 21 216
+ 217 111 83 69 22 80 72 197 89 245 103 61 238 128 117 60 155
+ 121 15 174 218 174 239 8 23 141 158 251 170 192 213 36 219
+ 11 175 169 28 85 123 169 237 93 64 240 57 52 99 32 142 45
+ 89 191 15 229 231 154 46 201 155 60 214 141 48 43 69 141
+ 163 24 162 109 227 61 199 21 57 118 96 244 57 92 227 52 43
+ 198 219 143 126 244 68 18 3 88 202 172 141 134 108 147 205
+ 8 107 64 62 65 223 145 131 239 91 25 188 199 39 38 181 163
+ 99 191 122 250 112 199 118 59 213 83 160 114 54 59 46 211
+ 239 89 39 203 90 93 89 88 115 197 110 64 74 113 83 138 169
+ 5 59 62 183 35 214 189 16 193 197 124 109 202 123 154 251
+ 19 13 199 35 38 170 242 69 62 194 105 214 255 0 171 138 85
+ 166 169 82 204 164 237 60 103 235 77 181 129 226 66 184 98
+ 163 220 82 155 73 24 202 45 34 81 201 239 75 44 138 141 7
+ 114 72 110 146 203 36 73 12 42 207 150 193 197 73 52 191
+ 135 215 186 168 241 220 180 113 177 206 49 200 90 153 124
+ 40 248 122 110 151 241 183 65 66 12 48 207 191 189 94 54
+ 186 61 165 156 94 28 123 10 149 10 78 59 138 231 109 252 58
+ 163 8 163 159 236 254 19 73 53 176 86 80 176 175 171 1 197
+ 107 185 248 77 101 105 103 51 204 187 36 199 24 25 39 255 0
+ 249 93 18 176 195 18 157 177 168 30 212 191 85 132 201 109
+ 39 134 138 204 227 110 8 160 175 232 210 227 196 226 14 170
+ 210 27 66 215 60 46 54 110 5 72 31 227 82 141 57 214 72 145
+ 137 198 64 237 70 127 148 13 146 219 107 208 145 150 5 240
+ 91 211 245 165 58 75 237 130 48 72 36 47 117 237 71 39 113
+ 4 23 248 216 202 224 96 100 114 107 24 148 183 126 62 213
+ 182 101 57 231 145 89 70 6 7 2 174 221 35 133 71 102 248 84
+ 40 245 172 110 57 38 182 175 3 140 86 19 1 142 194 145 182
+ 199 34 250 129 197 226 100 241 154 211 52 121 77 194 182
+ 234 67 117 238 223 236 162 150 17 248 81 218 138 116 52 72
+ 228 225 183 246 21 241 148 126 30 79 76 46 234 62 234 16 27
+ 181 7 34 55 135 55 63 250 116 232 210 118 168 117 167 172
+ 127 132 183 220 224 15 13 127 187 189 16 10 135 194 144 69
+ 43 176 144 155 88 23 212 71 70 32 110 251 129 165 170 25 99
+ 99 139 78 127 182 179 213 220 199 167 141 190 86 35 191 189
+ 42 241 228 132 174 50 65 246 162 53 9 89 172 227 221 158
+ 212 178 151 139 54 61 100 68 118 241 86 227 89 182 132 121
+ 247 72 1 2 186 187 225 157 184 131 70 182 143 28 162 128
+ 203 234 167 235 92 181 211 246 87 23 221 92 145 198 173 133
+ 144 121 192 249 107 170 250 103 242 236 35 241 147 194 157
+ 84 6 99 252 85 36 169 34 249 98 229 34 100 89 89 139 43 6
+ 97 192 35 211 233 95 94 86 17 2 199 56 238 105 119 226 188
+ 171 223 183 39 222 190 27 172 16 95 113 79 95 173 16 199 30
+ 134 246 242 11 133 60 242 59 212 75 226 103 77 91 235 58
+ 101 204 138 159 154 145 147 145 235 78 97 152 171 248 145
+ 200 10 31 65 222 138 155 100 200 21 178 222 167 29 171 5 87
+ 211 144 110 214 109 31 80 240 36 111 32 39 57 244 57 237 77
+ 224 152 92 69 226 174 49 142 126 149 105 124 86 232 27 125
+ 70 22 187 178 132 9 2 229 177 247 53 76 66 38 209 181 65
+ 109 48 111 8 156 18 123 81 229 20 170 201 101 196 253 163
+ 208 94 161 14 251 105 27 217 106 189 213 20 11 226 125 51
+ 138 177 181 70 205 153 104 249 87 28 85 117 117 253 117 247
+ 251 241 84 87 240 231 26 233 108 192 5 3 131 77 145 78 243
+ 74 180 213 193 7 138 115 18 229 137 172 227 33 27 48 183 64
+ 24 26 202 126 13 108 140 169 242 142 9 236 79 106 26 92 150
+ 228 250 209 140 93 140 124 254 48 107 34 195 39 154 215 255
+ 0 231 122 247 191 253 234 188 65 196 223 27 151 24 144 101
+ 253 40 152 179 130 49 233 90 109 85 29 124 217 163 226 218
+ 19 28 98 163 123 176 165 64 46 219 13 122 22 223 39 28 147
+ 216 86 219 133 4 19 90 1 240 161 50 28 131 252 52 91 131
+ 219 55 144 62 189 56 91 68 133 88 110 245 30 213 37 248 49
+ 210 178 106 58 188 51 73 144 138 119 19 233 140 208 189 61
+ 210 211 245 12 232 193 79 204 57 32 226 186 51 161 250 90
+ 195 65 211 161 138 8 255 0 51 104 46 125 106 115 146 78 145
+ 124 17 113 143 146 37 26 85 188 122 109 132 113 68 184 96
+ 49 159 165 125 185 185 85 59 90 64 119 124 198 180 205 43 5
+ 43 156 31 79 181 10 178 36 44 26 70 222 205 223 30 148 165
+ 210 177 139 150 149 10 227 98 142 192 250 214 155 147 253
+ 28 199 177 88 122 238 244 250 208 171 52 155 134 88 98 133
+ 150 237 164 36 46 112 15 53 129 56 190 145 65 255 0 148 77
+ 158 235 69 153 118 182 199 218 54 118 239 154 175 116 73 72
+ 181 129 135 204 203 218 174 31 142 22 18 234 26 36 203 2 72
+ 21 60 229 64 253 225 207 106 165 244 67 38 194 37 36 178
+ 240 51 90 91 175 248 104 234 13 18 169 228 221 230 127 46
+ 43 5 151 196 228 214 55 127 186 221 238 43 85 187 100 227
+ 158 213 94 71 20 180 232 103 23 43 197 125 145 84 168 201
+ 230 176 135 182 43 100 156 40 165 9 22 212 144 45 249 247
+ 163 161 254 174 40 93 79 157 67 62 153 166 22 234 166 1 197
+ 96 53 98 235 149 12 167 222 147 234 3 242 102 81 220 71 82
+ 41 99 12 59 129 74 117 91 114 45 167 117 31 250 103 251 169
+ 148 140 129 45 55 44 17 99 253 29 23 12 204 28 6 3 20 20 19
+ 127 71 139 159 253 42 223 28 129 136 7 156 154 103 208 255
+ 0 153 177 205 170 120 204 3 12 12 240 69 111 213 199 134
+ 145 66 163 36 143 90 246 154 141 148 231 143 74 203 89 138
+ 67 123 11 6 57 199 21 63 134 139 243 68 211 224 110 159 102
+ 218 140 243 189 188 178 60 152 249 192 192 171 213 173 128
+ 140 176 141 15 25 193 244 168 39 193 43 63 15 79 19 76 7
+ 140 199 206 184 171 30 250 50 146 43 42 228 48 193 168 219
+ 163 177 55 200 71 226 254 97 228 140 28 99 210 183 69 117
+ 30 226 31 105 30 222 148 46 161 152 75 141 229 148 156 226
+ 149 60 140 70 248 137 80 189 241 75 143 34 186 101 158 54
+ 201 25 102 241 55 70 35 3 216 118 162 108 39 87 144 66 242
+ 108 61 243 239 244 168 180 119 82 49 253 233 136 123 10 206
+ 207 82 89 36 88 174 150 38 195 121 37 76 247 250 213 123 36
+ 224 214 201 204 169 20 145 60 61 148 240 72 245 170 127 227
+ 23 70 172 150 134 226 214 223 107 103 141 130 173 155 70 86
+ 183 66 28 179 3 250 26 58 242 194 43 232 66 92 66 187 79
+ 189 115 201 108 56 230 163 105 156 115 105 60 208 196 214
+ 23 80 148 145 71 5 135 122 132 235 145 201 29 249 42 188 22
+ 245 174 164 248 151 240 207 198 70 212 45 21 81 145 142 204
+ 10 160 186 163 71 154 222 77 183 49 8 157 84 246 254 35 239
+ 93 112 206 180 145 203 60 93 201 116 37 211 39 10 0 126 41
+ 220 119 81 1 144 213 22 120 174 35 92 237 226 135 146 250
+ 234 33 235 143 65 87 228 217 13 50 87 226 199 254 144 126
+ 149 245 166 141 200 243 10 133 46 162 232 115 146 72 172
+ 206 175 41 238 191 223 67 147 9 51 12 132 227 114 214 82
+ 120 106 56 113 80 209 170 72 88 5 76 31 189 20 215 178 152
+ 212 149 201 197 50 102 37 118 211 195 242 150 227 222 140
+ 18 71 129 181 137 168 84 119 151 1 73 197 49 180 191 153
+ 148 110 200 199 106 231 250 104 246 74 29 148 174 230 227
+ 29 177 89 232 58 77 246 183 172 195 20 112 177 141 125 135
+ 6 153 244 151 75 234 157 65 36 113 136 241 9 0 230 186 15
+ 162 250 19 79 208 225 79 42 25 145 130 183 31 74 76 146 138
+ 71 84 49 211 183 209 143 68 244 245 174 149 167 6 252 56 86
+ 28 246 169 45 207 130 182 134 66 222 30 61 187 214 251 192
+ 182 235 26 15 40 39 210 144 107 247 22 176 249 46 37 36 124
+ 193 127 155 233 83 91 118 86 172 214 151 14 236 220 228 103
+ 130 222 213 147 204 138 164 48 86 39 185 168 228 218 149
+ 196 206 56 17 91 129 133 81 243 17 88 53 227 180 137 28 114
+ 56 92 122 247 170 27 241 177 225 187 24 231 251 171 43 85
+ 241 50 170 14 15 36 154 87 109 34 151 27 134 121 167 54 108
+ 225 129 12 118 251 82 185 168 151 112 226 129 250 130 194
+ 222 77 30 118 120 247 237 140 250 122 215 48 107 54 169 103
+ 169 201 224 163 129 188 240 195 138 235 187 203 101 109 50
+ 82 205 130 227 143 181 115 71 197 11 55 183 214 228 88 219
+ 17 239 224 1 244 162 157 171 57 102 252 68 107 48 54 234 27
+ 24 175 68 15 114 49 158 213 166 218 19 37 160 207 38 140
+ 137 120 10 220 145 86 198 173 108 227 123 9 130 182 203 218
+ 181 195 216 240 59 214 215 70 49 131 73 244 196 91 80 99
+ 248 197 62 230 152 193 145 111 145 75 245 24 207 226 147
+ 159 90 109 103 31 244 97 158 115 84 140 28 140 40 184 185
+ 117 148 100 12 118 173 183 172 143 165 92 48 193 34 39 175
+ 186 149 168 14 24 142 49 64 220 201 183 78 157 87 129 225
+ 61 43 84 232 196 94 55 155 195 207 134 216 61 168 155 89
+ 101 241 16 108 61 232 168 236 220 219 161 11 198 208 223
+ 219 91 173 172 157 100 86 32 119 166 109 80 30 201 95 79
+ 166 228 30 245 150 187 129 127 18 255 0 101 110 209 23 195
+ 43 246 175 107 136 5 253 171 30 119 29 181 54 44 125 209
+ 127 252 28 119 147 73 72 230 142 40 215 60 31 122 156 223
+ 199 182 38 200 192 3 32 212 119 225 21 138 174 131 12 155
+ 67 115 220 84 183 91 141 148 97 89 64 199 32 251 84 228 244
+ 119 67 216 175 53 163 38 215 30 25 199 112 213 29 69 63 48
+ 152 73 159 65 233 83 13 65 48 37 1 124 167 249 170 55 61
+ 169 40 20 109 200 254 90 129 218 4 247 78 190 70 24 83 220
+ 214 80 238 154 69 16 176 14 14 87 234 104 11 230 104 238 90
+ 118 5 84 252 202 125 190 148 126 152 158 21 202 220 69 135
+ 4 103 13 217 215 233 250 215 70 55 226 38 88 187 39 154 13
+ 208 252 34 163 33 141 193 243 231 212 251 211 251 121 149
+ 85 1 97 130 112 191 90 135 90 206 197 188 64 27 45 201 207
+ 127 214 134 215 181 195 98 143 189 138 237 77 203 207 99 70
+ 147 236 131 99 174 169 234 43 123 77 62 84 37 70 88 247 53
+ 203 223 20 122 138 214 234 127 203 100 102 12 71 7 177 230
+ 180 252 80 248 131 123 168 93 92 217 90 92 48 143 126 11 3
+ 85 179 199 52 132 72 237 36 140 199 144 125 105 163 26 232
+ 132 230 210 164 48 75 217 26 50 178 31 175 216 86 192 177
+ 179 120 114 70 67 241 199 223 181 123 78 176 141 158 25 60
+ 57 29 36 94 123 112 125 170 77 160 116 237 205 192 152 92
+ 70 3 69 180 142 14 72 30 149 94 150 201 70 42 93 246 70 127
+ 3 111 32 5 156 28 246 30 245 190 13 46 213 184 24 7 252 106
+ 204 181 232 39 188 134 25 214 2 158 110 1 167 211 252 45
+ 149 128 217 22 112 6 10 158 230 167 249 25 79 192 83 113 90
+ 218 43 149 217 141 188 156 214 187 150 139 38 69 97 207 165
+ 90 154 223 195 91 168 237 85 150 18 178 103 7 158 226 163
+ 250 159 68 74 152 183 104 138 133 245 230 154 51 108 73 97
+ 165 178 2 110 35 93 185 140 228 246 250 214 22 218 145 75
+ 144 79 49 169 237 237 76 239 180 139 136 30 225 167 183 116
+ 136 113 19 250 19 244 164 87 118 130 221 66 140 239 113 150
+ 255 0 84 123 26 210 236 17 199 79 146 58 87 225 47 85 90 20
+ 133 99 120 217 252 48 184 7 154 188 44 181 72 110 33 115 28
+ 138 189 178 107 243 247 73 212 245 13 34 238 43 139 91 150
+ 86 86 224 103 130 43 161 190 21 117 252 218 133 187 199 52
+ 195 196 199 42 79 57 169 101 130 173 150 89 37 47 133 243
+ 123 62 27 184 205 66 250 153 228 158 87 72 219 242 128 203
+ 31 230 250 83 11 125 67 241 86 98 67 184 239 92 140 119 20
+ 179 85 146 97 108 214 246 225 124 118 236 237 217 7 169 53
+ 139 136 77 210 199 8 240 215 106 142 5 122 9 94 225 177 34
+ 149 251 208 119 94 29 164 113 164 108 89 229 206 11 127 16
+ 254 111 181 21 167 69 35 196 145 178 183 3 230 247 165 148
+ 171 163 166 41 164 130 109 86 72 238 147 99 239 32 246 21
+ 50 208 67 51 13 202 70 225 138 143 217 91 1 54 246 198 79
+ 106 149 105 49 31 46 210 1 250 210 91 125 141 149 166 135
+ 114 167 244 87 221 194 162 96 31 173 115 103 199 23 118 190
+ 241 36 82 160 55 148 159 90 234 47 194 238 179 39 25 59 121
+ 246 174 109 255 0 40 116 120 110 193 194 99 119 97 84 199
+ 217 231 101 232 129 88 15 19 77 12 127 74 223 28 124 80 182
+ 50 40 176 133 70 70 70 236 125 40 181 124 40 198 106 216
+ 211 226 206 89 109 155 34 93 166 136 112 118 10 12 51 23 28
+ 26 222 242 16 170 190 227 251 40 168 180 18 63 170 115 121
+ 30 61 233 149 159 238 69 44 213 124 179 41 200 224 209 54
+ 210 55 130 49 197 27 163 25 220 166 238 105 102 167 24 91 9
+ 200 239 225 63 20 222 94 35 207 189 5 169 47 244 9 255 0
+ 221 61 43 70 54 233 208 175 236 235 101 33 79 228 35 103
+ 244 175 52 113 171 249 177 244 197 37 178 189 151 240 22
+ 235 26 231 108 64 22 250 14 212 76 115 74 236 190 76 156
+ 214 148 120 148 135 25 116 137 30 154 114 195 142 115 199
+ 181 103 212 2 69 22 211 42 134 41 38 15 181 97 165 135 104
+ 187 109 230 137 213 70 52 183 247 83 145 247 160 73 170 154
+ 103 65 124 33 150 245 186 106 18 99 120 198 121 199 106 156
+ 223 50 181 177 103 80 95 24 21 0 248 17 121 29 215 79 197
+ 27 206 216 7 154 178 245 45 63 242 188 72 206 83 28 87 61
+ 118 206 200 63 34 5 170 47 149 155 113 35 212 123 82 11 169
+ 21 163 11 24 218 71 114 106 73 171 90 72 204 237 27 21 199
+ 124 122 212 102 246 53 149 138 188 133 0 61 197 37 89 217
+ 29 136 53 75 171 111 21 13 192 196 108 112 91 218 137 211
+ 97 109 58 34 151 18 135 183 97 186 25 129 206 207 245 126
+ 212 171 82 145 33 117 180 155 5 91 129 159 74 81 38 165 119
+ 166 23 181 185 13 36 64 111 140 154 120 107 68 242 77 217
+ 59 186 215 99 183 178 109 201 135 81 232 121 199 215 235 84
+ 183 196 238 182 55 119 18 90 219 202 225 135 145 142 107
+ 221 79 213 32 192 235 24 33 241 140 3 233 239 85 212 183 17
+ 202 254 44 222 116 39 42 87 230 253 106 177 77 156 83 157
+ 61 31 45 237 237 239 1 102 27 100 118 207 29 137 246 21 186
+ 210 206 226 234 117 88 99 32 227 102 0 229 79 210 134 131
+ 114 220 179 91 169 147 235 31 106 184 62 29 116 188 215 205
+ 14 160 145 168 115 141 216 236 79 184 250 85 23 138 217 40
+ 183 116 197 93 13 210 179 94 74 18 230 213 114 14 72 92 240
+ 106 230 233 14 149 201 182 205 143 49 182 210 72 249 254
+ 245 48 233 30 132 176 210 209 47 24 174 233 57 97 252 167
+ 218 167 186 85 149 188 100 34 145 133 57 28 122 212 102 220
+ 186 58 97 20 182 200 190 129 210 227 194 72 103 183 201 140
+ 229 192 28 17 78 83 165 195 162 4 143 96 7 111 126 245 58
+ 210 108 148 90 143 40 231 191 214 137 154 200 237 77 168 54
+ 171 110 34 137 185 113 123 101 115 115 210 176 184 101 150
+ 223 113 81 198 106 35 212 61 46 204 146 44 118 104 3 38 204
+ 227 176 247 251 213 241 45 180 101 119 0 9 35 251 41 14 173
+ 104 170 73 101 10 153 224 208 119 240 50 148 89 202 157 87
+ 210 48 77 60 202 214 110 145 193 229 140 1 199 222 169 174
+ 161 208 175 22 242 86 75 117 218 95 31 252 215 114 106 218
+ 69 181 227 52 71 111 57 46 113 223 138 169 250 227 225 231
+ 131 110 90 216 198 94 224 22 231 209 126 149 162 223 45 154
+ 81 168 156 164 246 105 35 152 164 140 41 67 203 122 15 160
+ 172 244 205 66 77 47 82 51 89 54 17 78 55 19 203 125 233
+ 247 94 105 223 178 174 22 205 16 237 44 124 64 125 90 162
+ 182 234 136 155 102 138 70 62 137 31 173 94 124 90 57 84
+ 156 54 116 39 195 190 179 134 247 78 137 124 92 52 99 12 24
+ 250 84 190 125 74 222 228 22 13 148 35 12 7 241 125 15 210
+ 185 131 65 214 164 211 239 247 12 162 231 205 138 181 180
+ 30 166 140 66 173 183 114 133 221 180 251 251 212 163 217
+ 104 57 61 217 45 187 183 48 52 154 150 161 34 137 37 242 67
+ 26 246 81 232 61 233 182 153 49 100 85 229 112 63 90 138 45
+ 212 147 203 251 79 82 37 80 183 229 102 164 26 9 252 67 120
+ 146 72 85 91 145 72 227 114 59 160 237 18 88 219 116 161
+ 128 194 250 98 164 218 66 175 145 152 176 31 74 141 233 144
+ 188 234 35 221 177 148 246 247 169 118 137 110 210 97 23
+ 142 49 73 246 131 54 146 29 92 206 230 219 109 190 115 183
+ 140 251 87 51 255 0 148 20 183 13 170 120 78 170 124 221
+ 249 174 164 185 130 27 123 23 50 76 82 69 143 129 239 92
+ 167 241 178 239 241 93 84 144 43 29 170 196 55 214 169 141
+ 83 103 14 94 136 60 113 50 75 18 174 79 229 246 52 94 226 2
+ 231 223 154 250 84 199 50 150 228 142 7 218 177 118 12 221
+ 171 162 18 75 71 56 79 139 25 101 81 243 99 244 172 165 198
+ 194 27 185 239 143 74 24 174 210 24 112 43 207 32 216 41
+ 219 179 8 181 86 62 48 237 222 143 178 93 208 45 3 170 168
+ 241 215 143 90 105 166 46 97 24 246 169 72 198 115 174 16
+ 41 251 208 58 145 99 167 93 28 124 176 57 31 217 76 167 70
+ 35 147 64 234 8 223 179 47 121 255 0 246 207 255 0 45 82 49
+ 209 133 58 116 91 236 237 155 215 195 163 214 53 35 105 60
+ 208 186 71 245 59 111 247 99 251 232 167 39 120 199 189 115
+ 61 187 58 49 244 62 211 27 106 40 244 11 138 206 245 131 90
+ 52 110 112 15 124 250 80 182 59 150 60 230 183 93 131 52 5
+ 27 128 123 98 175 195 198 206 121 123 23 111 194 141 25 19
+ 165 163 146 25 150 25 163 228 146 123 213 139 166 235 6 72
+ 132 55 16 182 244 227 196 61 136 170 231 225 154 76 186 12
+ 22 208 179 49 99 134 250 138 156 221 168 180 182 82 216 81
+ 234 125 123 87 36 175 164 117 198 187 96 58 228 214 203 59
+ 186 202 20 145 242 147 193 53 1 215 181 21 183 159 204 200
+ 184 60 224 240 43 87 94 245 125 134 157 20 166 73 17 216
+ 118 25 230 168 174 178 235 171 237 81 90 222 215 114 199
+ 158 72 239 250 86 132 91 208 207 34 142 209 51 235 190 160
+ 181 86 120 81 64 43 192 57 245 168 68 189 85 123 61 177 130
+ 95 57 67 149 63 78 212 133 26 107 169 12 183 147 177 200
+ 245 61 205 1 113 118 200 204 145 224 15 173 118 67 29 171
+ 100 178 229 182 25 125 127 150 37 188 197 251 168 238 15
+ 189 39 185 59 88 239 96 227 233 90 204 153 36 243 156 250
+ 214 80 71 44 242 42 170 239 102 56 81 158 230 153 164 142
+ 87 119 100 211 225 206 159 38 163 172 70 24 180 11 24 192
+ 157 144 149 39 254 181 215 159 13 186 114 107 91 40 63 18
+ 33 155 114 143 204 72 246 156 125 126 149 76 255 0 147 198
+ 143 171 90 193 29 212 150 211 92 187 159 201 137 149 118
+ 238 29 192 231 57 31 95 210 186 179 67 253 204 19 79 111 28
+ 23 17 128 94 51 243 21 255 0 10 231 148 172 183 14 42 205
+ 194 198 51 182 56 212 246 239 76 244 141 60 52 109 25 57
+ 246 62 245 140 23 182 18 93 21 158 101 66 237 144 163 184
+ 167 169 60 62 42 219 197 177 155 211 111 183 189 78 154 232
+ 101 145 208 77 140 91 97 53 181 215 56 86 224 19 201 175
+ 182 255 0 153 207 99 244 237 88 207 34 169 11 131 222 155
+ 95 72 74 219 179 99 70 54 96 118 28 10 87 127 110 100 144
+ 112 118 47 115 77 147 204 156 80 119 141 180 129 42 159 15
+ 233 220 208 119 240 104 57 39 178 37 117 96 85 213 147 200
+ 51 198 125 105 102 187 166 69 54 157 34 149 46 249 193 30
+ 255 0 74 152 93 203 101 248 35 47 136 164 33 198 65 165 111
+ 61 188 182 243 165 187 70 230 70 249 143 96 43 36 238 217
+ 105 100 109 81 202 255 0 26 122 94 231 240 119 19 36 177 69
+ 30 60 177 32 36 177 255 0 189 115 30 160 38 130 83 13 194
+ 52 108 59 6 24 56 175 208 63 136 208 223 92 105 207 21 134
+ 158 207 19 103 243 21 87 43 199 98 73 239 92 75 241 71 69
+ 212 236 122 138 225 174 109 229 104 249 35 198 24 32 125 72
+ 227 251 234 139 100 114 69 209 22 180 152 162 121 78 1 245
+ 167 218 70 173 115 107 34 186 254 98 142 224 122 138 138 6
+ 100 227 248 79 106 221 5 228 177 159 47 98 49 85 171 22 46
+ 145 97 69 213 51 92 95 197 248 179 182 5 249 99 61 254 245
+ 105 116 222 187 111 113 98 30 50 170 84 236 7 61 207 181
+ 115 221 153 241 206 226 88 47 185 244 52 108 26 166 163 165
+ 220 175 225 238 11 170 182 229 0 240 77 35 196 213 179 170
+ 57 18 143 103 91 244 253 212 110 23 116 170 167 102 50 125
+ 13 77 116 75 168 109 109 131 33 103 25 229 147 214 185 131
+ 161 190 34 36 211 8 175 36 104 229 7 140 227 7 251 234 246
+ 233 77 90 222 254 213 26 9 55 2 61 235 145 220 101 208 202
+ 74 107 178 77 121 113 115 170 188 145 70 36 181 135 30 99
+ 47 241 253 171 159 62 46 90 90 218 245 34 77 104 193 54 183
+ 0 213 253 169 91 200 150 203 113 19 96 168 36 227 218 185
+ 235 226 187 51 106 194 86 112 70 227 192 239 84 199 53 100
+ 178 105 82 35 18 57 99 90 7 239 43 4 155 33 91 156 123 86
+ 107 203 110 174 142 36 101 166 19 130 0 200 199 21 237 170
+ 121 39 154 248 155 177 230 32 214 71 129 156 142 105 210
+ 179 8 245 140 248 163 138 109 163 200 162 223 130 51 138 85
+ 173 224 74 87 190 61 69 29 163 254 235 244 161 40 152 57
+ 183 51 103 6 131 213 8 93 58 247 60 127 71 127 249 104 238
+ 62 180 22 177 183 246 101 239 127 234 239 255 0 45 20 233
+ 24 85 167 73 26 216 65 158 254 18 86 70 100 50 129 159 90
+ 89 104 199 240 86 236 199 63 150 63 186 178 133 100 146 225
+ 112 199 147 197 69 37 101 99 145 116 137 133 143 154 42 223
+ 50 31 8 149 228 138 209 167 127 87 0 247 94 9 162 157 136
+ 78 14 51 222 171 242 136 228 246 39 127 8 122 155 193 211
+ 165 220 219 222 54 192 218 113 254 52 71 92 124 78 134 206
+ 23 182 242 187 28 252 196 228 113 244 170 88 223 220 219
+ 207 44 80 206 241 239 239 180 227 38 144 234 211 205 121 49
+ 73 228 101 63 206 79 45 244 169 180 145 73 78 162 107 234
+ 29 90 235 92 212 101 113 39 229 150 254 34 104 102 133 173
+ 146 56 230 104 163 6 61 202 249 206 107 11 155 118 183 143
+ 115 52 123 72 227 117 42 184 144 147 183 57 35 142 15 24
+ 167 142 136 115 114 14 212 175 140 155 18 48 170 23 212 122
+ 208 18 51 72 219 155 143 181 124 141 89 188 217 237 82 45
+ 15 165 239 239 228 64 35 220 172 50 60 164 211 60 180 168
+ 122 182 34 182 181 150 105 22 52 83 150 56 21 119 124 40
+ 232 61 22 11 120 117 14 162 91 71 193 223 137 156 141 163
+ 244 168 207 76 244 169 183 63 136 212 18 225 18 57 54 168
+ 100 219 185 135 63 225 91 58 183 90 125 107 82 255 0 195 61
+ 62 206 225 188 133 223 130 120 244 164 82 82 209 69 162 234
+ 185 248 149 211 250 36 150 134 27 173 53 90 60 43 62 205
+ 196 168 237 185 135 124 122 30 226 143 31 29 52 104 209 202
+ 95 254 32 5 27 100 36 236 45 159 148 10 175 236 62 14 116
+ 119 78 233 49 106 29 125 173 188 6 78 209 228 140 254 148
+ 143 173 126 25 244 255 0 254 31 184 234 111 135 186 191 237
+ 75 11 33 253 58 212 252 240 131 193 111 211 138 203 18 248
+ 105 41 203 127 11 55 77 248 167 13 230 169 52 150 247 62 32
+ 50 141 165 57 219 192 206 71 176 171 175 165 122 166 5 180
+ 105 218 238 57 174 14 11 190 120 198 63 135 233 92 19 209
+ 178 53 191 80 219 134 145 158 37 96 36 8 112 28 122 30 61
+ 49 87 123 245 75 105 182 99 207 52 183 69 118 195 26 0 16
+ 169 237 74 213 104 10 171 71 82 105 125 92 178 27 168 173
+ 231 133 252 12 41 37 143 45 235 68 75 172 79 115 181 162 5
+ 128 229 177 233 84 103 195 200 167 142 199 241 23 49 151
+ 121 21 93 163 36 242 199 230 63 165 90 218 115 72 203 28
+ 109 148 86 95 48 30 130 163 46 131 68 134 62 164 146 22 88
+ 78 21 152 231 46 120 197 44 126 179 134 226 226 72 124 104
+ 153 146 79 13 129 39 0 251 253 170 55 212 64 44 102 54 86
+ 40 36 33 28 158 7 21 76 245 62 169 115 211 218 200 159 30
+ 37 165 208 49 206 224 240 62 181 88 250 152 177 62 34 245
+ 140 58 102 239 2 121 12 14 222 120 80 249 147 237 244 168
+ 54 141 241 163 78 211 141 197 165 197 196 110 210 203 184
+ 16 199 40 158 223 78 113 222 160 191 17 53 127 196 104 134
+ 75 123 167 145 74 17 20 217 230 63 175 255 0 62 245 82 116
+ 190 137 169 117 70 175 107 165 233 240 120 183 183 79 225
+ 199 158 199 156 150 111 160 28 213 97 20 214 197 201 168
+ 218 58 99 87 248 221 161 73 107 36 48 234 16 164 172 70 232
+ 230 77 202 62 162 133 213 239 186 63 173 172 13 173 252 186
+ 108 175 26 9 160 13 46 213 115 245 3 147 81 85 248 123 240
+ 135 79 184 58 54 177 212 210 207 171 96 36 146 110 10 187
+ 253 64 250 103 181 70 126 35 124 48 190 232 99 6 191 161
+ 221 181 213 145 243 70 249 7 2 179 138 55 41 69 121 116 68
+ 62 34 244 106 232 154 139 73 100 209 61 179 246 17 146 66
+ 253 179 80 146 152 39 131 199 28 213 195 105 171 105 157 87
+ 161 143 26 59 165 188 183 127 13 178 23 185 254 44 14 194
+ 162 250 143 68 106 158 61 204 107 110 234 144 30 119 14 228
+ 250 214 186 216 120 166 66 226 186 146 33 181 64 42 79 57
+ 166 150 183 81 221 67 28 108 18 34 131 27 135 115 75 245 13
+ 58 230 209 218 57 151 105 30 148 26 50 169 243 12 143 106
+ 111 201 100 165 221 14 110 45 100 30 29 202 108 93 231 201
+ 176 249 179 245 169 239 195 46 190 155 65 116 134 233 140
+ 202 14 56 39 138 173 172 165 241 167 102 114 65 246 205 29
+ 45 139 162 248 204 228 123 82 154 13 217 214 154 111 94 193
+ 127 103 35 13 219 89 59 103 214 170 30 176 184 55 250 195
+ 158 200 28 241 237 81 14 158 212 46 196 42 137 52 136 163
+ 140 3 222 158 137 55 121 155 204 199 185 62 181 62 153 119
+ 177 106 33 86 39 146 15 247 81 80 227 28 214 137 102 84 57
+ 35 143 81 91 33 60 96 250 242 42 184 246 182 77 236 45 72
+ 53 242 65 229 28 154 249 12 110 20 229 189 107 50 141 142
+ 244 244 97 14 171 216 100 246 245 166 26 88 99 0 35 218 130
+ 215 35 41 149 62 180 126 145 34 139 101 76 115 75 35 4 237
+ 124 253 43 70 167 206 153 122 63 254 179 255 0 203 71 73
+ 185 87 191 122 7 80 255 0 54 94 255 0 237 223 254 90 41 42
+ 48 158 198 216 61 132 13 234 34 76 10 223 4 91 101 25 226
+ 129 180 188 95 192 192 168 74 159 13 123 253 40 136 174 55
+ 56 243 115 92 231 71 24 168 162 77 103 194 133 29 143 173
+ 23 183 3 142 104 29 53 183 69 159 173 28 161 137 32 48 31
+ 122 183 250 156 242 236 132 107 158 77 85 199 161 245 165
+ 154 157 228 75 20 143 224 147 38 208 160 254 180 95 83 57
+ 138 255 0 123 28 143 97 222 163 23 119 6 86 113 187 3 28 3
+ 64 73 118 105 188 158 75 137 188 71 96 196 142 62 149 164
+ 43 30 194 155 233 90 68 247 146 69 24 134 76 56 200 101 82
+ 71 247 84 150 223 225 254 169 117 125 13 172 54 206 217 30
+ 128 228 208 177 150 50 61 211 246 17 93 221 197 19 50 151
+ 102 24 78 228 254 149 210 29 55 105 99 164 244 220 104 153
+ 154 237 211 1 35 143 5 190 134 190 116 95 193 91 125 52 67
+ 53 238 212 144 12 22 9 206 126 149 105 216 232 54 58 126
+ 158 27 240 202 229 60 161 207 115 250 84 178 100 101 225
+ 138 145 205 127 16 35 235 141 54 194 107 169 173 82 194 202
+ 102 43 28 64 121 177 238 126 181 183 252 152 180 184 110
+ 186 206 59 139 153 55 120 114 255 0 23 124 138 184 254 36
+ 90 166 177 166 141 46 104 35 142 4 39 108 140 60 196 227
+ 176 199 115 84 102 142 215 157 3 174 165 245 152 155 98 49
+ 145 210 65 182 66 185 239 131 86 197 41 73 81 57 175 22 75
+ 126 54 92 222 106 189 105 168 45 206 80 193 62 200 131 127
+ 20 127 74 19 225 245 222 151 210 147 38 181 113 169 69 121
+ 103 125 101 56 212 44 99 102 221 6 60 168 178 103 131 158
+ 249 20 247 171 250 255 0 225 55 87 218 197 168 106 38 238
+ 29 67 24 153 33 139 7 31 169 239 80 253 42 199 77 234 9 221
+ 244 173 34 120 116 93 223 60 242 238 146 225 135 191 176
+ 197 36 63 140 227 147 155 122 59 223 245 28 95 218 44 42 62
+ 68 123 167 116 185 33 117 214 20 71 109 12 210 51 36 95 197
+ 180 158 0 171 51 165 244 73 181 27 215 191 191 183 154 71
+ 150 61 177 2 56 219 239 254 213 35 135 77 93 99 94 75 88 99
+ 72 173 161 199 135 10 231 9 138 187 122 35 69 184 136 199
+ 113 225 112 23 204 91 181 105 61 158 122 116 182 109 183
+ 177 142 215 72 137 99 152 44 139 202 169 238 135 220 211
+ 173 10 247 84 145 37 105 49 49 72 240 127 183 230 20 195
+ 195 180 216 86 107 115 34 158 225 69 108 183 146 21 220 177
+ 126 90 40 200 92 115 82 158 217 76 73 209 23 188 188 186
+ 187 184 17 77 43 73 110 173 231 66 57 205 36 235 93 26 222
+ 248 180 239 3 92 196 188 182 206 202 49 86 11 61 188 190
+ 105 20 200 254 158 80 48 43 69 253 168 184 183 219 28 107
+ 27 24 246 133 127 95 236 162 131 61 28 197 173 216 222 88
+ 217 13 44 226 43 73 31 242 89 255 0 139 239 65 124 52 190
+ 183 232 190 169 212 34 186 137 37 188 186 211 165 252 20
+ 241 182 10 183 7 106 159 114 1 171 31 226 39 74 188 150 165
+ 68 82 126 72 47 156 241 159 165 66 44 180 219 125 107 79 75
+ 123 168 137 187 181 36 199 112 14 10 48 237 131 86 134 153
+ 9 78 169 175 217 28 191 211 109 173 111 109 205 190 165 6
+ 167 45 196 98 226 89 34 13 152 157 143 40 229 191 136 122
+ 213 219 240 252 182 169 240 123 92 211 245 15 204 134 221
+ 191 163 153 62 94 59 129 85 78 147 168 244 85 173 233 139
+ 172 44 181 29 51 80 138 76 59 194 229 163 155 253 110 121
+ 201 246 169 111 88 252 86 233 143 252 53 7 76 244 23 143 35
+ 72 140 37 121 34 218 50 125 205 8 97 148 95 43 61 95 231
+ 255 0 59 22 124 80 140 35 180 82 80 254 51 75 234 219 152
+ 244 185 25 31 199 17 162 17 228 111 191 210 174 222 139 139
+ 169 109 103 71 234 59 16 208 73 134 91 132 28 99 218 162
+ 191 15 58 89 110 181 4 213 181 39 113 32 199 134 93 114 142
+ 255 0 82 43 162 180 147 22 161 107 2 222 219 198 147 162
+ 132 64 7 148 175 189 35 200 250 103 18 132 111 179 158 126
+ 54 232 182 47 178 234 216 143 12 182 230 34 169 75 216 226
+ 86 62 11 7 25 238 43 184 58 167 161 44 181 120 36 73 6 204
+ 140 99 195 4 19 238 42 138 248 143 240 98 250 192 126 51 78
+ 18 73 30 114 219 87 3 251 40 197 162 83 195 78 202 44 103
+ 52 211 78 187 145 54 164 135 122 127 47 168 167 119 125 31
+ 117 14 158 39 146 60 72 6 74 169 228 212 106 230 9 109 91
+ 44 172 185 28 110 20 233 139 199 137 59 211 30 223 194 6 21
+ 216 9 228 123 154 117 19 21 183 101 35 181 68 58 114 224 52
+ 41 184 147 232 64 247 169 58 179 120 108 164 130 77 35 236
+ 22 8 208 254 98 209 16 202 21 112 8 197 15 63 136 172 6 112
+ 125 43 234 35 110 238 0 255 0 173 87 23 65 24 66 236 121
+ 193 197 109 144 238 21 170 15 42 121 151 28 214 213 59 184
+ 170 24 79 174 144 84 145 216 246 173 250 79 238 135 218 133
+ 214 206 213 17 144 115 69 105 35 49 45 99 12 223 228 160
+ 245 15 243 101 239 254 217 255 0 229 163 101 24 10 191 74
+ 11 81 227 77 189 255 0 219 191 252 181 140 66 237 225 152
+ 136 216 103 105 143 138 42 222 57 150 117 57 39 154 107 103
+ 110 162 194 219 10 63 171 171 126 167 189 98 177 159 20 10
+ 230 67 56 162 65 166 16 176 15 122 57 202 178 141 172 115
+ 64 88 198 124 49 205 27 28 101 92 179 114 41 211 177 27 43
+ 190 181 38 61 66 76 115 159 127 74 142 91 196 102 157 87
+ 146 88 212 151 174 163 111 198 6 254 126 212 171 167 182
+ 166 169 24 144 2 50 57 62 156 208 151 236 120 165 106 206
+ 132 248 59 209 94 38 135 22 165 116 100 87 219 133 80 70 49
+ 138 180 58 43 73 68 189 154 226 52 220 241 182 23 35 56 160
+ 58 34 72 173 250 58 47 54 209 225 129 24 247 207 173 79 186
+ 31 77 16 218 248 219 67 25 6 226 42 13 203 224 242 236 123
+ 167 216 226 13 203 26 128 188 231 57 255 0 26 95 212 86 203
+ 14 38 0 224 17 188 125 42 75 20 6 20 41 26 240 252 40 164
+ 186 234 187 174 24 60 133 78 89 87 218 149 187 209 148 221
+ 236 138 245 22 157 60 140 183 218 74 1 34 249 247 204 160
+ 162 241 142 213 79 245 47 72 111 89 117 61 99 84 182 187
+ 158 103 33 174 166 206 10 255 0 42 133 245 251 213 175 213
+ 218 164 50 217 172 77 44 214 192 54 8 65 153 36 250 40 165
+ 235 164 216 95 233 145 223 73 17 140 91 201 143 195 177 220
+ 227 244 236 198 173 6 250 55 37 118 206 124 181 232 213 212
+ 181 136 196 118 238 246 80 74 54 160 1 90 97 239 159 229
+ 171 3 81 179 134 222 91 125 63 77 88 108 247 70 21 97 132
+ 238 43 245 53 45 120 119 180 159 135 218 145 202 124 24 230
+ 10 1 96 59 138 144 116 239 76 219 104 202 250 174 165 4 101
+ 194 238 201 94 91 218 157 201 213 11 26 91 162 47 209 221
+ 26 52 117 23 55 18 44 146 183 32 241 146 126 181 97 105 233
+ 20 118 239 243 120 107 243 2 121 52 161 18 107 251 179 117
+ 35 164 17 70 249 66 107 125 213 247 138 230 59 119 1 148
+ 224 149 236 106 118 51 105 187 99 27 235 207 20 237 133 85
+ 51 237 90 163 140 144 27 36 55 175 214 176 176 141 3 171 57
+ 220 128 242 222 212 213 32 181 101 44 179 99 53 59 41 141
+ 241 20 200 230 41 119 134 56 245 197 31 105 121 29 194 42
+ 177 193 3 134 254 42 198 107 120 2 16 178 100 251 210 153
+ 213 161 184 13 20 228 145 243 173 50 86 9 53 123 50 234 11
+ 11 107 132 41 134 60 99 35 4 255 0 125 85 157 71 210 82 232
+ 87 15 123 4 237 225 49 203 32 28 15 92 241 86 153 120 245
+ 40 4 33 140 12 220 54 239 152 214 173 37 225 148 75 165 223
+ 70 178 197 38 80 59 12 213 185 19 139 75 225 77 117 119 76
+ 218 117 23 78 199 47 225 99 146 248 121 146 242 54 243 3
+ 252 172 191 245 164 29 51 210 246 205 122 209 95 27 104 110
+ 162 249 76 132 248 83 143 117 43 87 61 247 76 54 135 118
+ 243 89 248 81 68 91 43 159 95 113 205 124 211 116 235 59
+ 199 54 23 81 195 110 249 202 133 64 54 122 231 39 248 104
+ 114 98 73 236 91 209 125 35 169 105 98 107 75 29 66 7 178
+ 150 60 155 57 0 59 121 244 39 154 176 161 130 56 45 161 131
+ 240 242 36 164 237 44 221 179 244 168 206 172 145 216 106
+ 169 111 43 77 19 68 121 184 135 229 199 250 223 79 168 169
+ 93 165 218 234 150 209 172 106 222 64 48 87 215 30 166 167
+ 40 219 177 137 5 164 77 225 36 102 48 236 7 36 210 254 160
+ 178 221 27 70 208 171 41 249 151 210 159 105 140 205 10 22
+ 12 209 109 192 217 232 126 191 90 251 119 110 165 6 236 183
+ 213 187 209 72 45 183 217 69 183 75 195 125 121 61 155 100
+ 5 30 184 205 115 207 198 174 155 151 68 213 222 32 25 161
+ 83 228 98 7 34 186 207 88 181 139 79 234 23 149 155 247 220
+ 10 163 255 0 202 41 80 99 115 120 135 178 3 252 67 6 155 28
+ 147 208 117 84 202 79 164 121 159 185 198 123 26 153 3 129
+ 233 81 14 155 253 250 152 252 188 224 129 233 82 233 50 23
+ 235 76 227 178 79 197 31 83 243 62 113 147 239 69 69 10 17
+ 207 56 237 66 70 234 20 224 115 68 71 56 0 125 120 167 197
+ 209 141 160 49 250 250 86 74 25 125 43 234 28 14 56 205 101
+ 147 239 84 48 155 89 82 249 46 54 159 165 109 209 219 49
+ 125 171 29 96 150 206 121 226 190 232 192 180 71 21 140 53
+ 145 153 136 192 29 168 109 70 54 253 151 120 205 192 54 207
+ 255 0 45 18 119 46 57 244 172 117 94 116 59 175 253 179 255
+ 0 202 107 24 142 89 51 27 24 6 15 238 146 183 163 13 224
+ 100 103 53 170 197 15 224 160 237 251 164 175 174 140 178
+ 175 110 245 199 99 146 109 59 247 127 173 22 85 73 60 208
+ 90 110 68 32 159 122 34 114 206 190 203 233 142 245 117 29
+ 89 39 221 16 158 179 54 177 220 6 150 54 101 29 212 54 9
+ 253 107 111 65 52 119 55 208 199 14 159 167 164 123 191 120
+ 209 111 147 191 189 1 214 76 222 33 221 130 113 71 252 41
+ 88 255 0 104 199 36 165 130 171 100 227 214 150 79 84 58
+ 126 71 78 217 170 67 162 91 71 31 38 76 42 17 235 86 191 71
+ 218 226 40 183 157 227 104 3 30 245 85 116 252 107 47 224
+ 147 147 26 121 176 106 212 209 200 68 130 221 153 131 103
+ 118 229 237 138 136 242 236 147 52 74 210 101 92 7 94 113
+ 81 206 163 180 146 65 45 212 115 0 66 224 212 170 13 172 85
+ 149 148 48 60 230 163 157 92 118 146 241 130 177 200 118 96
+ 251 227 63 244 167 125 0 170 250 146 107 143 26 41 174 154
+ 105 32 81 183 100 67 37 142 104 141 62 226 225 44 37 156
+ 192 167 127 149 93 184 194 251 154 34 85 150 107 205 145
+ 176 9 27 121 178 56 175 107 55 45 34 236 114 145 219 47 4
+ 142 9 164 10 179 239 79 89 193 97 27 94 77 34 162 47 152 51
+ 30 13 9 170 235 147 234 243 24 80 18 177 156 130 61 69 71
+ 239 239 159 88 188 88 85 21 45 226 60 5 39 154 51 80 158
+ 223 65 182 73 37 184 54 225 70 230 4 14 70 59 81 76 106 190
+ 198 23 55 145 91 233 127 141 105 132 48 198 48 238 199 3
+ 255 0 154 174 58 155 227 6 147 167 135 139 69 183 123 233
+ 84 238 241 230 249 11 85 101 241 47 174 53 30 162 190 154
+ 40 100 123 125 56 54 216 237 225 111 46 51 220 253 106 53
+ 162 195 249 223 155 143 15 235 70 43 147 7 137 100 15 139
+ 93 115 122 210 203 111 115 4 1 223 248 98 193 3 233 91 224
+ 235 142 190 159 44 117 201 23 112 254 17 66 244 246 143 9
+ 132 58 170 159 165 53 93 29 113 226 5 35 43 144 0 167 81
+ 127 161 185 68 15 255 0 212 47 136 86 174 118 234 178 76 23
+ 130 28 113 138 249 167 124 105 234 91 59 198 143 87 180 181
+ 188 182 99 229 35 190 62 148 116 154 76 126 31 238 219 44
+ 57 200 168 119 85 233 118 246 170 74 40 12 79 4 246 20 90
+ 111 224 27 139 46 222 152 235 237 19 169 151 109 140 198
+ 218 240 156 61 180 237 134 79 246 126 181 34 212 21 229 41
+ 26 161 241 147 204 8 244 250 215 29 239 158 206 100 158 41
+ 36 142 88 206 229 120 216 130 167 220 123 213 223 240 171
+ 175 165 212 172 19 76 214 36 205 194 174 216 238 9 229 135
+ 177 164 118 129 73 244 93 58 63 80 195 169 35 105 23 135
+ 108 177 46 6 238 198 129 182 183 146 199 89 146 65 27 74
+ 210 38 207 15 196 194 129 244 164 122 189 171 181 132 55 80
+ 183 134 20 238 18 47 175 222 138 210 117 111 218 67 240 247
+ 18 5 184 78 3 10 91 12 83 110 168 207 85 150 225 110 90 222
+ 68 144 6 95 202 42 60 195 234 79 173 72 186 125 111 38 252
+ 53 180 146 166 118 124 222 189 251 26 213 115 190 234 201 0
+ 88 214 88 142 85 241 233 68 116 235 184 34 119 145 222 69
+ 109 187 113 253 244 108 220 75 31 72 181 120 160 48 25 4
+ 128 12 144 43 116 176 199 248 15 13 99 98 8 230 182 105 222
+ 91 96 164 129 43 97 183 30 216 199 106 209 172 188 98 216
+ 198 172 195 234 180 91 36 221 58 43 158 186 142 72 46 32
+ 154 67 149 13 159 189 85 31 25 237 148 233 226 85 240 156
+ 21 220 168 235 184 30 61 69 91 221 94 127 21 104 95 4 140
+ 121 126 149 89 245 117 172 87 90 116 126 59 200 27 105 92
+ 142 64 21 37 26 118 91 134 172 230 221 62 226 221 53 16 143
+ 103 28 110 78 73 133 246 47 255 0 230 164 55 238 134 37 218
+ 70 61 57 165 29 89 165 92 104 218 195 188 136 230 34 124
+ 178 122 99 222 178 134 224 188 74 172 114 64 239 86 82 100
+ 166 188 67 34 108 46 115 69 71 38 229 238 41 100 47 199 122
+ 54 221 129 166 140 184 137 45 58 24 219 252 167 62 245 183
+ 156 103 210 180 68 234 171 94 150 96 20 14 106 139 34 97 0
+ 213 121 25 29 141 124 210 37 111 8 166 59 26 245 243 6 77
+ 163 248 123 159 122 195 70 238 212 121 196 195 144 196 247
+ 21 163 84 35 246 77 208 245 17 57 63 109 180 65 27 87 60 80
+ 154 145 255 0 203 111 127 246 207 254 24 173 206 38 21 233
+ 188 216 219 159 254 146 127 133 110 4 9 121 25 161 108 37
+ 85 177 183 95 85 140 110 250 226 136 143 243 36 7 208 26
+ 228 41 30 199 214 25 240 78 71 173 109 150 64 16 143 95 65
+ 239 88 90 16 109 248 227 28 86 139 146 119 231 60 142 213
+ 107 124 73 201 121 16 206 172 95 26 80 23 191 175 210 166
+ 191 9 186 121 141 170 220 180 51 57 39 129 129 239 222 144
+ 217 105 82 234 218 199 131 179 11 184 110 53 209 157 23 211
+ 214 182 122 44 81 201 48 241 182 0 61 49 74 24 251 14 122
+ 66 214 229 94 48 208 133 80 63 139 189 88 90 72 96 192 54
+ 56 236 105 7 78 88 164 31 52 129 163 94 88 231 204 79 181
+ 74 32 134 75 123 116 196 68 156 118 110 226 145 143 46 198
+ 179 58 65 18 179 74 219 207 112 59 84 115 170 46 217 180
+ 249 95 121 44 62 81 237 245 251 209 183 119 81 180 108 184
+ 238 42 25 212 90 162 174 228 102 93 157 155 119 96 41 152
+ 42 207 186 29 184 107 71 154 87 35 185 99 238 106 35 214 90
+ 132 78 5 157 187 22 99 232 41 157 222 169 44 26 83 52 101
+ 76 44 48 54 118 53 26 208 109 228 190 214 33 145 162 12 12
+ 152 25 246 164 47 12 111 76 155 124 53 233 149 16 45 197
+ 218 110 64 114 115 235 84 239 199 221 101 78 177 123 102
+ 140 26 56 188 160 102 186 123 67 179 75 123 51 101 8 13 193
+ 12 127 147 235 92 107 241 198 27 139 126 176 212 98 152 146
+ 230 124 159 246 105 148 28 132 134 68 242 52 200 12 48 44
+ 118 198 237 149 195 183 37 15 202 62 213 165 53 63 1 131 60
+ 39 195 251 84 155 168 46 180 217 180 109 62 218 212 51 92
+ 54 12 161 7 205 247 165 87 82 89 54 159 36 87 22 142 140 62
+ 94 59 85 34 168 156 161 110 209 97 124 56 215 45 245 8 28
+ 170 12 227 145 237 86 5 215 225 226 75 113 12 108 254 77
+ 217 110 56 170 35 225 13 243 91 235 38 53 243 161 111 238
+ 171 123 169 245 84 91 139 104 17 137 65 24 17 253 15 181
+ 116 66 105 160 113 67 109 70 91 88 173 214 118 0 239 5 72
+ 81 218 169 78 186 234 56 127 27 45 154 167 136 55 144 49
+ 222 173 110 160 212 29 58 101 228 42 5 202 198 66 12 122
+ 123 215 62 233 243 164 250 255 0 141 116 60 92 49 242 142
+ 237 247 161 55 72 220 80 93 188 222 50 8 230 132 164 141
+ 199 110 5 49 209 255 0 242 221 97 24 23 216 28 40 223 199
+ 127 181 107 189 186 73 119 50 219 202 189 176 224 114 121
+ 166 125 93 62 159 113 248 25 172 29 213 196 65 164 200 238
+ 213 12 177 114 141 153 73 69 209 212 95 8 26 223 168 186 54
+ 104 166 219 35 68 72 81 246 21 27 234 77 54 125 23 88 18
+ 236 216 132 242 69 51 255 0 37 139 27 166 208 175 174 74
+ 150 141 66 149 95 114 123 212 179 226 94 151 227 217 181
+ 196 42 36 98 114 19 249 126 149 25 174 40 188 50 46 64 61
+ 45 117 107 170 89 51 69 38 14 57 7 189 109 179 111 194 245
+ 10 13 196 46 60 195 211 25 168 15 76 222 92 88 234 70 5 5
+ 73 60 113 145 82 150 213 51 126 143 112 34 19 99 128 135
+ 119 30 249 255 0 165 104 116 52 210 79 69 167 109 119 185
+ 17 22 66 87 119 13 235 138 35 83 11 140 198 229 199 166 106
+ 45 162 220 120 138 36 207 25 230 164 81 75 226 40 88 227
+ 223 143 74 214 115 53 228 70 181 136 157 225 117 141 64 227
+ 133 53 93 235 150 179 52 130 23 132 62 14 0 95 191 173 90
+ 250 196 56 152 49 219 150 249 75 118 6 161 215 246 48 139
+ 215 146 105 24 130 48 71 240 211 36 55 39 209 207 127 20 33
+ 179 180 212 101 79 6 102 89 24 46 201 62 82 113 220 84 6 88
+ 22 44 52 44 206 159 94 226 174 175 140 58 47 137 104 38 179
+ 101 148 71 150 81 184 6 83 244 205 83 54 30 42 72 232 246
+ 243 3 159 48 200 110 126 244 64 246 104 220 241 131 186 137
+ 182 184 64 57 110 107 102 161 110 172 9 141 65 30 254 212
+ 166 104 218 35 156 253 42 148 128 210 100 129 46 99 63 197
+ 95 39 148 99 200 115 72 34 149 193 201 99 138 221 248 229
+ 67 207 106 87 20 128 208 222 233 129 143 30 222 190 245 142
+ 151 235 247 165 175 125 226 2 84 226 143 210 100 5 194 255
+ 0 53 40 7 133 191 44 80 90 144 206 153 122 114 127 171 61
+ 109 150 224 46 87 219 138 26 250 101 109 34 233 189 225 112
+ 126 213 168 70 221 137 52 247 111 194 91 140 28 136 249 166
+ 118 114 121 192 160 116 224 166 24 71 111 203 163 173 194
+ 248 234 5 98 204 146 89 170 152 115 187 239 66 223 99 5 148
+ 225 63 157 62 106 105 99 25 48 42 199 183 39 190 104 203
+ 189 29 230 179 1 21 83 112 249 143 111 238 172 37 48 14 133
+ 210 188 109 107 241 144 164 50 46 209 151 99 130 13 116 78
+ 131 56 158 218 20 150 81 189 80 13 158 131 235 85 223 195
+ 94 156 59 143 226 99 12 217 225 135 21 108 90 233 166 36 79
+ 10 30 0 239 88 172 152 218 198 23 133 149 225 96 185 238
+ 126 148 254 207 12 187 34 137 143 243 63 165 35 182 146 88
+ 80 35 67 128 79 239 15 240 253 41 148 55 50 71 3 198 155
+ 223 63 59 227 185 250 86 20 246 175 9 49 238 137 75 194 7
+ 14 59 26 171 122 185 101 146 252 170 221 70 138 79 57 171
+ 19 90 190 184 150 223 207 136 198 60 160 85 91 173 91 79
+ 121 123 35 126 42 20 85 57 229 143 253 169 39 236 52 59 21
+ 95 71 52 120 85 189 141 19 24 193 61 254 181 38 232 109 62
+ 56 84 95 120 139 52 177 12 70 23 208 251 210 8 45 33 102 62
+ 35 69 113 183 143 43 28 138 150 244 28 129 53 1 12 177 109
+ 133 56 69 30 223 90 89 71 145 87 58 90 44 222 153 135 108
+ 45 112 24 137 64 59 200 35 39 138 160 63 202 143 164 236
+ 110 35 77 90 16 177 220 71 31 157 207 118 63 203 255 0 95
+ 210 186 59 76 240 101 45 113 224 67 10 200 219 34 218 152
+ 57 168 199 95 116 226 234 154 109 212 19 66 158 32 207 206
+ 14 8 193 237 93 81 141 66 145 199 109 202 217 193 218 38
+ 143 125 172 92 206 182 82 120 115 194 3 167 250 199 216 81
+ 186 229 182 179 114 195 76 184 142 52 153 64 252 208 57 63
+ 83 79 238 108 238 58 51 172 102 142 72 93 32 119 36 100 119
+ 25 197 72 174 109 109 245 43 132 213 172 128 119 83 202 159
+ 81 83 166 116 173 171 43 142 148 209 167 210 53 87 186 109
+ 225 20 130 8 29 254 212 255 0 168 117 88 99 189 18 151 121
+ 75 184 112 15 163 10 115 169 205 104 214 160 109 219 47 168
+ 3 24 168 70 191 34 35 161 50 198 74 190 79 218 171 23 76 95
+ 199 68 203 87 214 37 213 236 26 53 97 28 146 199 220 255 0
+ 102 42 186 135 166 111 237 101 123 191 50 170 19 133 35 150
+ 251 84 183 68 104 4 177 177 98 112 6 125 170 84 82 27 248
+ 197 189 188 97 156 253 56 169 202 77 176 113 118 65 83 78
+ 215 58 130 206 36 216 150 214 208 121 188 131 131 250 210
+ 254 157 210 219 80 215 226 210 252 97 8 241 48 197 189 106
+ 194 214 117 11 77 19 76 125 54 215 30 57 82 9 28 3 79 255 0
+ 201 219 162 228 212 181 51 171 222 70 35 241 27 10 204 14
+ 59 131 237 70 9 216 217 101 20 182 116 135 194 61 10 223 71
+ 233 107 107 59 21 100 11 15 159 61 137 250 208 157 71 12 97
+ 154 215 143 1 137 222 171 83 13 26 218 43 88 139 75 108 35
+ 139 110 197 57 225 143 189 38 234 185 161 181 211 101 183
+ 48 140 177 224 142 226 182 98 56 211 178 137 234 75 3 103
+ 126 235 13 210 69 179 144 73 173 130 222 67 20 99 241 145
+ 191 102 220 13 27 168 199 28 215 18 77 53 184 93 195 130 79
+ 106 16 88 52 155 213 111 32 12 167 182 227 255 0 106 132
+ 186 59 155 209 97 116 84 108 85 3 72 36 56 192 34 167 80 70
+ 200 128 172 81 179 175 24 61 234 176 232 167 154 223 242
+ 154 101 45 191 131 159 165 88 208 95 93 44 106 165 81 128
+ 31 50 250 211 199 212 228 105 169 108 211 171 31 16 177 142
+ 51 27 145 202 159 74 142 94 195 25 140 200 192 22 94 114 87
+ 52 250 250 105 35 117 104 83 45 234 27 185 165 119 214 183
+ 19 184 62 25 85 110 227 183 52 76 85 255 0 17 132 154 166
+ 147 37 186 248 46 20 21 7 110 222 125 170 129 155 79 252 60
+ 230 39 32 182 79 145 107 171 122 135 68 142 75 86 221 25 92
+ 100 146 59 26 162 186 143 167 38 135 88 220 138 165 119 28
+ 30 107 24 133 203 14 207 44 159 150 79 240 175 99 75 110 45
+ 85 216 243 83 62 164 210 229 135 108 166 18 138 125 248 34
+ 163 110 129 92 228 86 17 232 71 37 152 0 226 130 158 215
+ 239 82 48 136 202 124 190 180 37 197 190 92 129 142 244 105
+ 152 143 205 19 33 242 127 109 63 233 213 252 149 242 146
+ 217 228 214 155 139 85 10 78 40 189 15 8 59 113 154 120 166
+ 96 249 147 50 29 220 26 211 168 68 19 72 186 62 190 11 147
+ 246 162 174 15 230 134 247 21 167 84 255 0 50 221 55 24 107
+ 119 24 162 97 14 159 36 102 218 32 205 180 248 116 198 213
+ 226 87 83 188 147 154 81 107 167 220 53 140 18 7 35 242 249
+ 163 44 237 37 105 17 119 28 131 147 82 28 156 233 82 143 18
+ 49 232 69 79 180 187 75 121 32 92 220 73 28 184 249 68 69
+ 133 65 186 106 197 231 158 36 49 201 38 61 87 210 174 190
+ 145 211 94 68 137 95 195 66 171 140 177 231 245 172 97 191
+ 72 233 106 109 6 103 93 195 186 142 230 167 58 110 155 149
+ 2 36 4 1 146 204 199 138 15 167 44 108 128 241 124 25 230
+ 127 226 240 71 203 82 107 123 49 34 172 113 248 241 71 156
+ 226 65 131 88 87 42 6 22 110 1 241 219 196 92 121 84 129
+ 138 211 5 149 227 238 88 149 84 19 252 93 170 65 111 103
+ 146 84 149 104 151 251 65 172 166 82 241 42 66 205 41 31
+ 194 220 17 253 148 44 28 209 92 245 109 181 212 113 110 220
+ 74 129 192 30 181 84 206 151 127 141 151 198 194 3 192 4
+ 213 229 213 154 108 146 218 14 114 49 230 95 229 174 127
+ 235 72 166 211 53 41 87 12 242 147 223 39 129 83 156 188
+ 139 225 142 218 26 233 208 201 11 157 171 16 82 114 78 78
+ 106 95 211 141 17 148 180 69 153 211 137 31 248 84 253 106
+ 187 210 229 27 98 154 234 102 10 87 29 253 106 99 211 247
+ 50 71 229 137 138 237 243 73 143 226 31 90 220 138 100 73
+ 45 23 31 79 177 184 177 104 84 141 225 195 120 141 198 71
+ 208 83 253 66 55 75 114 242 175 137 43 240 0 25 207 21 16
+ 233 137 18 107 104 217 110 11 55 0 15 166 123 84 230 250
+ 120 225 136 200 204 200 137 128 8 25 197 118 65 218 60 188
+ 146 119 163 156 190 49 244 36 186 173 171 92 181 143 225
+ 228 44 85 153 187 143 94 42 128 158 223 90 233 105 158 56
+ 219 198 133 143 215 143 181 117 247 196 9 154 123 217 165
+ 105 34 104 200 206 194 249 195 127 241 84 31 89 91 238 184
+ 157 99 133 30 82 55 40 29 143 214 169 197 23 199 41 112 162
+ 186 185 214 103 186 102 123 219 95 57 239 33 24 3 251 42 61
+ 172 120 51 36 69 109 119 3 47 206 61 78 15 21 33 184 142
+ 230 221 222 9 70 84 15 54 125 169 116 176 205 24 93 141 132
+ 241 6 6 59 26 159 17 249 72 198 214 241 98 108 27 117 4 224
+ 149 92 211 111 252 65 168 64 98 75 43 87 17 129 229 44 56
+ 199 233 205 3 107 110 99 99 52 152 50 150 56 99 237 154 123
+ 211 176 77 38 160 37 101 223 31 177 237 70 43 246 110 82 10
+ 232 190 141 212 53 205 71 241 87 143 28 140 88 121 125 43
+ 171 254 26 232 50 233 22 137 111 248 16 144 42 133 223 142
+ 9 170 163 225 212 126 10 143 13 109 192 115 128 31 230 253
+ 42 249 232 235 223 11 77 134 25 36 73 90 110 236 15 57 166
+ 215 194 25 174 84 55 189 178 97 21 188 74 235 225 15 54 210
+ 121 53 5 235 9 86 234 105 118 131 187 119 150 33 243 84 243
+ 168 21 134 153 148 145 35 216 255 0 49 238 56 170 163 172
+ 110 246 221 148 183 185 203 147 193 90 134 99 163 9 14 213
+ 90 57 49 224 176 111 230 87 226 144 79 4 139 52 147 43 196
+ 140 253 129 124 12 209 122 205 212 6 227 198 110 1 242 103
+ 63 197 239 81 141 94 238 226 25 194 40 87 70 244 127 81 244
+ 174 103 45 29 138 28 145 48 233 15 198 27 192 146 18 27 119
+ 163 2 63 76 85 189 164 89 221 73 26 42 185 200 28 131 85
+ 191 195 29 42 75 141 146 194 172 24 159 144 255 0 15 30 149
+ 113 233 150 55 16 170 135 252 206 60 210 123 85 99 234 114
+ 229 146 230 1 29 155 9 135 226 87 9 252 254 162 190 157 54
+ 73 150 76 206 179 156 121 119 112 64 253 42 68 34 23 10 4
+ 109 226 159 76 208 151 54 110 238 87 196 43 32 237 232 7
+ 222 137 62 104 132 107 26 118 99 219 226 136 152 14 121 205
+ 86 125 99 167 175 237 5 105 110 23 96 62 102 65 87 101 229
+ 188 101 30 59 139 121 159 159 51 70 50 13 67 181 253 46 209
+ 204 177 194 198 53 217 156 74 7 6 176 201 217 68 117 172 48
+ 8 222 72 228 50 38 223 33 116 108 230 160 19 129 180 62 59
+ 174 113 87 71 94 233 47 38 158 234 139 184 43 97 86 169 187
+ 184 158 34 241 200 48 85 138 129 236 43 2 74 221 128 250
+ 103 222 176 101 39 229 25 53 159 210 179 135 230 170 115 85
+ 64 52 201 22 80 150 24 56 161 172 78 217 8 0 119 166 23 142
+ 190 27 113 233 75 237 10 155 130 2 253 105 224 237 24 105
+ 58 110 10 223 74 18 255 0 63 178 110 193 244 129 218 143
+ 149 149 99 11 142 72 160 117 31 243 85 217 61 204 78 15 218
+ 131 236 193 186 90 198 116 139 76 50 159 232 201 254 21 240
+ 8 214 109 220 18 57 24 165 154 124 231 246 109 170 238 218
+ 22 221 20 215 212 185 118 155 195 29 189 234 35 147 62 151
+ 185 63 180 227 85 109 196 243 145 232 125 170 240 233 87
+ 154 98 130 117 42 224 113 159 90 231 254 159 141 77 220 110
+ 210 109 243 14 213 208 95 13 174 45 209 81 90 100 44 23 203
+ 187 146 127 178 177 139 91 167 68 45 106 163 233 147 24 238
+ 194 164 246 194 223 193 93 177 201 193 236 190 159 122 65
+ 161 25 226 95 204 138 16 51 198 79 27 105 254 159 226 186
+ 121 152 39 60 39 253 105 146 178 13 219 8 84 102 112 4 112
+ 237 246 207 52 108 80 71 23 155 240 209 243 245 175 145 32
+ 81 150 82 62 181 181 229 80 128 114 126 212 234 128 38 234
+ 59 17 121 1 113 181 118 131 149 240 176 107 157 254 36 105
+ 145 172 225 132 94 57 82 119 47 168 174 150 190 241 164 6
+ 72 31 195 35 212 142 106 176 235 237 5 174 124 86 101 12
+ 216 221 187 24 57 164 156 20 138 96 157 62 69 19 13 184 134
+ 214 71 243 120 132 102 52 147 248 105 222 141 61 221 194
+ 172 215 18 131 50 12 125 90 134 154 19 103 168 120 18 237
+ 96 217 0 125 104 103 241 173 101 252 106 134 27 79 111 74
+ 229 105 166 119 57 114 90 45 126 140 184 86 180 102 55 40 8
+ 237 205 78 191 31 60 86 95 135 107 229 220 190 111 47 36
+ 241 242 213 27 163 234 202 176 41 241 140 81 191 112 123
+ 211 185 186 180 219 217 198 209 221 168 144 143 56 99 206
+ 43 167 30 95 140 228 201 141 223 67 62 185 190 0 22 88 89
+ 78 194 89 166 24 85 62 245 68 234 173 20 200 146 120 151 15
+ 39 140 216 192 249 177 223 21 100 234 93 81 167 222 233 242
+ 121 135 138 27 206 9 24 97 75 172 109 244 123 201 222 118
+ 186 72 146 21 59 6 6 11 55 106 235 82 137 57 41 69 21 69
+ 244 107 60 211 93 169 222 178 249 75 55 4 26 2 230 55 93
+ 145 140 130 91 129 142 245 120 75 240 222 29 147 220 75 118
+ 30 222 100 81 28 157 134 226 70 72 166 215 191 0 76 154 124
+ 23 81 107 2 210 70 149 7 157 187 131 233 218 133 196 73 100
+ 226 172 231 200 35 12 21 130 144 9 218 51 234 105 173 147
+ 53 180 47 106 237 55 154 81 38 213 29 143 181 92 250 183
+ 193 155 93 2 226 207 241 55 27 217 230 97 184 158 15 181 0
+ 157 15 107 160 194 127 107 93 71 0 157 155 135 97 207 177
+ 173 113 30 18 114 86 36 232 155 166 181 212 229 142 20 15
+ 143 149 27 248 143 181 95 61 33 125 178 213 99 141 94 2 163
+ 115 73 32 242 131 237 84 149 189 254 147 167 202 177 171
+ 167 138 174 4 135 0 227 235 82 24 186 206 56 238 36 138 210
+ 113 176 227 37 143 31 165 36 164 146 26 172 183 53 139 233
+ 37 145 47 13 228 65 72 33 147 61 170 172 234 89 213 239 76
+ 97 195 43 49 243 10 217 127 212 139 61 152 48 202 93 149
+ 124 192 17 222 162 154 181 244 173 190 4 254 177 41 201 39
+ 176 251 87 62 73 166 138 98 139 176 77 70 226 105 110 227
+ 128 248 50 89 41 255 0 238 31 106 9 108 115 118 169 36 98
+ 88 216 249 95 209 13 31 102 134 210 220 137 35 60 142 239
+ 220 83 222 137 209 164 212 174 195 188 108 235 158 0 251
+ 215 53 72 232 121 20 116 139 19 225 174 154 190 12 107 17
+ 119 219 130 199 244 255 0 10 182 236 213 161 183 40 171 147
+ 237 81 142 150 210 174 172 237 217 18 40 227 82 0 5 187 212
+ 174 22 216 118 158 113 234 59 26 234 132 93 108 243 231 92
+ 172 209 53 180 127 188 240 78 87 156 30 213 161 217 164 25
+ 154 48 24 118 49 242 113 76 193 89 99 56 237 67 205 20 120
+ 199 202 125 13 55 16 8 111 196 76 140 161 37 39 25 203 14
+ 213 1 234 117 1 164 101 229 74 96 55 189 88 23 183 19 70
+ 204 138 137 142 217 62 181 21 215 72 134 54 150 70 183 84
+ 245 221 158 63 186 183 18 176 119 162 142 235 107 139 179
+ 101 112 48 74 131 149 250 213 55 169 21 153 101 109 195 118
+ 226 49 87 143 197 11 59 89 172 228 240 238 163 86 11 193 86
+ 242 213 7 168 41 183 153 227 13 189 119 119 20 133 31 26 4
+ 138 53 225 183 114 56 162 35 249 141 99 16 93 166 190 134
+ 10 199 218 177 51 11 207 221 183 218 128 179 230 224 227
+ 154 97 117 242 31 181 45 179 202 206 87 215 189 82 14 145
+ 135 197 65 136 103 142 40 13 74 48 116 219 220 28 255 0 70
+ 122 48 73 249 67 52 22 160 196 88 93 242 60 240 56 20 89
+ 132 246 173 33 176 131 211 242 147 181 25 98 164 202 55 122
+ 241 90 172 99 38 202 223 63 232 146 141 137 10 48 53 33 195
+ 237 36 17 76 55 59 140 28 241 86 191 194 221 82 71 187 85
+ 134 86 137 241 229 144 138 169 145 73 66 203 220 28 154 150
+ 252 57 214 154 199 83 71 134 72 163 97 235 39 106 198 58
+ 223 67 121 30 205 68 246 178 34 103 201 57 60 49 250 84 166
+ 202 250 59 114 171 42 153 28 140 2 7 97 80 110 157 214 5
+ 238 147 18 27 150 57 60 113 156 126 149 55 208 161 152 66
+ 38 143 136 200 198 120 57 63 173 89 164 186 57 199 169 35
+ 72 23 119 0 142 213 189 35 81 233 199 181 13 8 118 33 179
+ 192 224 209 101 148 32 227 154 6 62 50 174 119 99 129 233
+ 74 122 130 205 110 173 152 236 11 246 29 233 163 72 161 114
+ 71 21 131 48 145 10 178 239 83 233 237 65 179 45 20 167 88
+ 244 52 211 91 27 203 104 80 178 18 119 122 231 218 171 11
+ 187 123 200 110 31 78 189 93 162 67 243 123 87 79 107 176
+ 53 157 147 186 43 75 17 238 139 232 125 234 136 248 146 177
+ 73 114 100 84 96 155 185 13 195 126 181 25 70 203 225 156
+ 147 164 35 210 116 152 166 184 16 52 171 42 149 202 236 247
+ 170 207 226 54 139 175 105 90 204 242 61 196 190 11 28 198
+ 83 149 219 237 83 222 151 214 197 133 218 194 100 240 225
+ 249 67 96 114 61 170 196 212 52 152 117 189 17 90 56 209
+ 212 12 238 35 56 21 60 77 73 157 83 132 226 185 72 228 251
+ 45 112 139 146 26 86 59 20 134 4 156 22 162 52 205 98 226
+ 222 203 242 166 62 57 186 18 54 227 193 3 211 237 83 78 185
+ 248 112 99 190 184 149 45 13 188 32 231 116 125 152 213 121
+ 169 104 183 182 101 130 238 0 252 153 238 5 116 62 206 120
+ 228 82 123 39 58 151 88 245 117 197 134 159 165 75 124 86
+ 218 24 205 202 70 184 218 7 177 53 60 215 254 43 117 237
+ 199 75 232 182 247 182 18 89 199 225 44 214 243 173 187 21
+ 184 10 123 130 51 199 189 115 249 107 184 36 221 151 221
+ 141 188 156 241 237 82 109 7 226 31 89 104 177 71 109 109
+ 172 94 4 130 217 160 129 50 8 138 54 238 160 17 218 154 133
+ 88 87 254 139 31 226 175 196 126 181 234 43 13 48 94 88 61
+ 132 70 63 26 222 88 247 33 125 191 196 51 233 144 106 29
+ 212 157 103 212 58 189 165 140 186 165 244 83 35 32 88 176
+ 131 32 47 114 126 181 19 213 186 147 168 117 153 33 159 81
+ 212 174 238 154 217 12 80 120 178 110 240 211 249 71 211
+ 147 66 44 55 19 90 71 181 75 159 155 25 236 115 90 135 73
+ 46 221 140 238 53 67 251 78 238 95 20 178 77 146 50 121 205
+ 104 210 245 75 139 217 34 181 134 232 137 3 16 192 3 154 47
+ 67 232 251 173 64 201 227 187 71 35 225 148 14 248 207 106
+ 185 62 27 244 16 178 195 61 132 105 48 148 18 242 96 22 95
+ 214 132 163 171 4 230 170 162 7 208 29 47 125 30 141 53 238
+ 172 242 178 203 251 188 30 64 199 253 232 177 103 28 123
+ 100 241 137 149 120 84 110 199 239 83 126 177 191 182 208
+ 237 37 183 143 116 44 56 85 36 55 24 244 170 238 202 83 123
+ 118 94 66 67 19 148 106 228 116 203 168 73 18 94 153 233
+ 253 83 95 144 76 202 76 46 112 163 31 227 87 31 73 116 153
+ 210 204 49 204 170 14 1 194 210 111 135 23 11 20 34 8 35
+ 145 159 56 201 3 21 104 90 90 27 93 175 36 126 35 176 206
+ 242 79 31 74 233 199 7 86 206 60 143 97 118 241 133 77 187
+ 118 129 233 239 91 90 53 199 28 125 171 21 155 60 50 225
+ 171 238 252 119 170 217 42 53 58 136 187 51 42 250 129 65
+ 234 23 94 12 69 100 143 35 221 123 138 60 149 151 229 20 27
+ 169 71 219 252 62 223 90 1 35 215 115 43 40 113 32 251 55
+ 124 84 47 171 100 186 49 179 184 154 201 65 231 124 91 149
+ 170 85 173 98 202 233 252 103 42 224 121 152 199 145 223
+ 251 170 186 248 147 214 183 90 125 177 91 107 171 105 7 250
+ 223 246 53 138 68 162 190 47 107 186 95 138 214 49 248 190
+ 48 28 73 25 198 223 211 181 87 209 0 214 161 139 51 100 247
+ 110 244 87 94 106 67 88 234 55 186 240 194 31 92 113 154 14
+ 73 213 85 87 233 82 4 244 244 124 133 130 190 211 235 68 52
+ 89 229 73 52 2 183 155 121 163 109 174 50 160 131 233 88 17
+ 102 171 131 149 35 233 75 163 27 110 179 76 238 20 96 210
+ 213 254 179 85 198 149 14 54 149 179 26 231 142 61 41 102
+ 163 41 252 21 194 142 194 39 166 50 168 48 131 244 165 151
+ 202 63 5 63 251 167 162 251 17 183 102 122 48 63 179 160
+ 224 254 233 43 126 71 137 143 90 203 72 79 252 174 220 129
+ 222 36 197 18 45 198 75 17 81 101 227 217 227 251 146 61 77
+ 15 111 122 246 87 65 149 118 227 187 30 213 235 171 133 141
+ 128 57 237 90 226 219 121 34 110 71 40 7 56 28 154 186 143
+ 40 137 47 99 167 126 4 117 157 174 161 167 172 63 153 44
+ 136 120 24 171 231 78 212 65 81 225 218 249 118 231 115 28
+ 0 107 144 190 28 89 173 188 130 77 54 89 34 32 231 105 56
+ 39 237 138 178 180 238 161 234 84 87 102 17 76 136 48 6 9
+ 199 215 154 14 60 65 197 51 163 45 102 103 1 100 216 170
+ 121 5 78 69 99 169 220 54 192 163 201 236 199 214 170 77 11
+ 171 245 39 17 71 112 168 23 28 248 35 183 223 62 181 53 209
+ 175 226 185 45 33 153 131 255 0 44 188 98 164 251 19 36 117
+ 72 147 192 159 42 72 164 38 120 62 244 112 27 80 5 35 111
+ 160 165 118 19 120 142 1 96 223 202 1 230 152 44 168 80 110
+ 202 243 142 105 211 64 173 30 154 21 153 25 100 25 82 48 69
+ 84 255 0 18 122 82 19 35 155 101 32 179 100 10 183 3 46 56
+ 96 104 109 66 202 27 200 240 200 140 222 153 173 40 218 27
+ 28 169 232 228 91 238 152 186 91 147 43 63 135 20 71 60 142
+ 255 0 74 125 211 93 69 117 98 88 93 200 22 221 92 4 207 160
+ 171 91 173 250 76 108 150 72 227 80 51 187 143 106 165 250
+ 146 41 68 141 111 29 187 8 213 253 185 205 113 188 124 37
+ 103 124 36 178 42 147 44 121 46 108 53 205 177 220 69 249
+ 108 155 65 247 250 212 119 170 190 23 217 155 104 37 134
+ 225 10 63 203 143 240 164 218 37 252 214 58 188 112 204 228
+ 64 202 48 79 189 89 90 93 253 188 177 237 89 214 103 253
+ 214 210 123 15 113 245 170 71 43 229 103 52 177 46 52 138
+ 27 93 248 99 116 151 210 44 86 251 160 69 196 44 163 211
+ 220 84 30 247 64 107 107 182 140 171 56 31 46 7 173 118 133
+ 237 180 90 149 144 93 194 54 141 118 57 42 57 250 138 137
+ 106 125 33 167 197 120 100 88 86 104 216 96 101 107 174 50
+ 199 37 105 28 235 179 155 116 14 140 186 212 193 240 55 51
+ 49 206 208 188 226 167 125 55 240 195 54 203 45 210 186 72
+ 143 198 70 55 15 122 186 52 46 153 179 177 138 55 182 217
+ 20 217 228 99 140 83 173 90 104 225 84 141 97 141 86 49 134
+ 36 96 181 53 165 234 138 37 201 144 171 110 135 210 116 79
+ 10 226 121 20 205 225 229 4 124 130 107 238 173 212 150 246
+ 54 203 105 24 72 156 55 151 216 241 254 53 171 169 181 136
+ 109 237 36 219 112 30 68 114 145 166 114 77 87 147 73 121
+ 168 91 139 182 87 46 210 121 71 176 174 73 101 116 209 214
+ 176 213 51 45 96 106 26 245 227 195 122 216 99 204 45 232 5
+ 54 233 30 147 152 202 177 205 147 199 3 20 227 163 244 134
+ 213 30 40 228 140 164 138 70 25 187 26 185 250 111 167 99
+ 183 132 60 209 70 37 3 154 92 80 79 108 76 217 56 233 25
+ 116 63 79 219 217 233 161 221 79 138 125 79 165 74 23 229
+ 25 227 28 115 88 194 137 12 33 19 140 119 175 179 58 38 55
+ 56 31 90 233 163 142 105 182 99 58 163 46 230 96 160 118
+ 165 215 146 52 67 197 102 150 48 222 168 51 69 207 44 126
+ 25 60 176 250 14 212 174 246 96 84 171 178 178 5 200 32 240
+ 69 103 163 40 114 26 137 15 135 230 81 199 203 187 179 80
+ 83 95 73 202 136 33 56 255 0 91 154 134 235 29 68 108 99 48
+ 219 9 166 0 124 199 24 63 110 106 11 172 117 110 189 53 203
+ 197 225 196 233 140 169 112 114 181 135 88 210 44 46 168
+ 215 33 143 79 157 228 73 85 84 16 222 249 250 87 37 124 96
+ 235 11 91 205 78 75 11 75 153 21 131 19 137 70 56 171 39 86
+ 212 53 237 70 57 32 188 185 82 161 14 28 13 187 87 254 188
+ 213 69 213 58 29 188 241 201 42 67 113 123 118 92 225 136 0
+ 99 251 107 112 79 232 106 136 45 172 37 228 105 14 112 123
+ 31 122 33 161 221 231 60 55 108 125 40 217 99 104 81 97 112
+ 145 183 177 239 65 22 96 73 244 237 74 218 163 27 60 53 9
+ 206 43 43 104 195 112 57 172 21 183 33 251 215 212 98 157
+ 142 13 32 12 175 65 7 145 74 155 137 197 57 148 111 83 187
+ 154 73 38 127 24 71 165 60 69 147 25 187 226 49 142 120 165
+ 247 103 117 189 217 247 183 113 250 209 172 165 163 31 106
+ 22 244 40 211 231 199 205 225 62 105 133 25 233 30 109 42
+ 213 113 140 198 159 225 154 57 216 44 44 48 59 119 160 52
+ 103 85 211 44 148 142 76 8 127 93 180 85 196 171 225 242 42
+ 71 74 116 70 181 2 242 94 14 113 199 97 247 169 87 65 219
+ 36 215 177 195 40 220 8 228 47 113 253 180 141 109 252 107
+ 213 37 60 184 239 237 83 174 143 211 149 39 87 0 110 35 200
+ 195 131 138 180 102 170 137 190 236 187 58 103 166 236 35
+ 48 52 114 32 24 221 133 249 170 91 107 165 194 210 5 148 4
+ 24 192 56 168 247 77 204 176 89 68 222 55 138 83 229 76 14
+ 126 149 52 209 238 55 145 226 76 129 217 126 87 3 129 90 82
+ 85 70 74 194 44 116 24 227 153 78 119 103 182 208 48 71 214
+ 155 92 104 236 214 174 17 76 111 252 203 220 211 109 38 72
+ 100 140 6 240 164 218 118 249 123 230 152 203 11 109 9 28
+ 140 152 244 32 100 84 69 110 136 158 149 251 66 218 111 194
+ 218 184 47 158 78 114 5 72 45 159 86 128 156 172 114 40 93
+ 204 199 57 253 41 93 196 81 199 127 137 15 131 38 120 34
+ 155 219 106 64 58 195 28 121 80 57 111 115 72 60 23 137 178
+ 29 74 89 38 86 154 45 171 252 195 176 251 209 173 121 8 5
+ 150 64 9 249 72 245 173 55 48 174 4 182 234 178 49 30 104
+ 207 111 191 222 180 189 188 19 219 238 145 124 39 95 238
+ 166 78 76 87 75 160 203 219 113 121 98 20 190 254 57 35 214
+ 161 183 93 11 13 220 146 220 54 84 224 236 80 7 38 165 58
+ 35 53 189 185 93 199 104 244 166 73 134 1 135 108 230 179
+ 175 160 230 215 69 41 170 244 5 221 179 37 204 176 248 171
+ 17 59 84 14 231 235 81 248 244 109 67 78 159 196 11 34 144
+ 251 184 245 174 141 101 220 140 49 201 239 154 73 168 104
+ 208 238 105 240 173 207 153 113 72 240 193 236 172 103 162
+ 162 147 168 46 237 252 56 132 78 217 143 156 131 205 101
+ 107 212 23 37 89 165 134 70 77 222 78 15 53 53 189 211 108
+ 154 225 166 107 120 194 42 144 191 65 65 219 221 104 214 54
+ 107 248 235 88 252 36 82 219 206 125 234 111 148 53 101 249
+ 127 194 40 122 138 227 204 86 41 3 231 142 15 106 211 125
+ 123 169 234 176 162 109 146 54 3 146 163 189 74 236 166 211
+ 53 75 176 109 97 70 129 135 151 138 145 105 90 109 177 111
+ 195 248 9 145 242 253 41 146 151 105 153 78 190 21 78 149
+ 210 55 151 72 200 33 98 31 141 199 146 15 189 75 116 79 135
+ 114 8 209 111 35 196 123 118 140 119 31 90 179 52 205 54 27
+ 24 246 140 125 168 227 207 113 84 73 62 200 203 249 18 122
+ 100 95 167 186 102 29 46 97 225 64 133 23 213 187 231 222
+ 164 83 203 28 108 25 164 31 111 122 251 43 108 224 71 147
+ 239 154 80 109 218 109 77 228 152 17 30 121 25 239 77 72
+ 156 83 126 193 247 23 107 26 144 60 205 232 40 24 111 174
+ 166 111 14 8 145 142 78 75 103 138 222 87 50 5 130 208 2 59
+ 190 79 21 153 11 103 110 207 18 6 62 173 236 105 28 218 10
+ 236 85 123 38 178 45 252 88 165 81 144 67 32 30 148 134 222
+ 198 235 80 184 114 210 22 10 249 108 30 62 195 233 79 46 46
+ 86 123 98 100 102 137 7 30 94 228 214 26 28 69 220 52 56 95
+ 109 180 109 181 108 51 175 245 23 221 104 208 203 25 13 31
+ 229 129 194 251 210 27 221 6 56 84 182 239 46 120 12 163 2
+ 172 115 20 110 160 110 19 183 169 110 21 62 216 168 230 179
+ 52 101 156 43 64 138 157 234 170 104 69 127 74 251 80 209
+ 225 184 180 144 51 194 168 14 15 166 106 191 234 221 39 75
+ 179 211 165 184 146 21 154 112 126 84 98 23 245 171 39 87
+ 185 202 186 49 71 82 114 25 71 106 174 122 230 37 156 40 50
+ 77 55 180 64 0 15 246 86 228 53 20 87 81 74 130 251 153 35
+ 67 39 101 143 36 99 238 104 9 50 234 54 142 213 35 235 13
+ 19 195 45 36 96 65 27 252 170 57 231 245 168 229 186 201 20
+ 4 73 195 103 24 247 20 128 122 116 122 47 148 253 235 9 178
+ 172 72 247 172 226 32 3 159 122 215 63 53 128 213 133 195
+ 34 136 200 60 253 233 61 209 254 151 156 12 102 155 69 26
+ 176 198 222 244 166 249 130 92 5 250 211 196 70 168 105 11
+ 47 131 230 224 80 87 255 0 212 238 63 221 191 248 86 208
+ 219 160 3 210 133 190 99 248 41 249 255 0 210 122 167 17 92
+ 141 118 127 137 253 159 1 207 30 18 86 196 51 186 156 182
+ 87 212 211 13 50 12 216 64 27 31 186 76 140 246 162 217 225
+ 136 120 123 80 41 224 115 206 106 40 232 98 43 123 241 111
+ 55 242 128 113 147 235 86 7 70 235 76 246 230 31 197 68 140
+ 195 200 164 237 96 62 135 214 163 182 90 28 218 158 99 130
+ 221 164 59 178 0 198 15 235 239 83 110 151 232 9 102 141 45
+ 238 237 102 138 39 28 156 252 191 98 41 210 160 39 68 255 0
+ 165 250 138 212 58 193 170 73 178 233 134 228 73 134 1 30
+ 245 97 104 186 198 154 206 169 103 118 214 236 71 158 25
+ 198 232 228 63 70 244 168 62 133 208 169 21 164 118 179 70
+ 211 148 27 99 71 200 199 234 65 53 34 178 233 77 74 194 47
+ 232 114 58 143 68 151 133 31 99 89 171 11 157 178 203 176
+ 99 185 30 56 210 54 198 74 171 102 50 61 193 247 166 203
+ 120 56 63 32 61 188 78 23 244 53 94 105 26 213 214 151 34
+ 65 172 88 220 66 190 147 198 165 215 63 92 122 84 202 206
+ 234 75 168 188 68 219 34 158 79 151 1 190 191 74 70 19 118
+ 187 11 222 67 44 177 177 18 6 220 184 239 75 186 90 250 71
+ 102 183 153 124 225 176 64 244 250 211 153 97 142 226 50
+ 193 164 82 7 96 188 138 91 106 39 134 247 250 138 202 231
+ 141 231 130 71 181 35 84 131 21 240 154 167 49 34 238 13
+ 199 24 160 103 45 29 214 214 82 84 247 241 56 81 69 217 110
+ 49 40 48 52 89 28 140 19 254 21 246 250 214 73 151 104 141
+ 217 125 8 28 212 219 108 77 38 107 71 120 216 109 66 69 16
+ 38 82 128 134 28 156 80 86 73 58 66 99 117 124 158 57 70
+ 255 0 181 100 201 60 78 89 81 153 49 200 8 114 63 186 130
+ 116 48 99 44 138 63 45 178 123 226 132 186 185 120 226 220
+ 97 102 63 196 69 97 52 178 170 171 68 178 242 57 204 109
+ 255 0 106 85 169 92 92 179 21 69 112 185 231 32 138 22 195
+ 24 41 50 63 213 151 154 140 182 87 118 246 208 73 27 225
+ 138 101 126 149 203 122 183 93 117 30 165 38 161 167 94 204
+ 208 248 19 164 109 30 48 78 61 8 174 179 185 188 189 92 25
+ 97 105 87 248 252 157 197 85 223 17 250 3 72 234 125 66 13
+ 98 214 217 180 157 71 112 23 37 99 32 78 61 73 24 239 79 39
+ 25 157 120 230 177 233 171 1 248 55 105 213 17 233 144 222
+ 220 248 50 217 52 132 194 7 204 23 255 0 154 187 244 141 66
+ 229 131 52 208 177 193 218 131 28 154 143 104 115 197 97
+ 103 13 142 159 96 237 28 40 168 143 225 156 240 63 252 52
+ 217 46 47 152 134 48 50 182 253 196 178 145 71 81 68 114 91
+ 118 137 97 184 157 190 85 49 159 102 172 252 67 180 110 96
+ 88 154 77 109 119 50 219 170 24 228 45 252 71 109 24 101
+ 102 64 162 57 11 247 225 73 197 73 79 147 209 37 141 160
+ 167 186 40 14 197 220 115 130 7 165 7 113 54 223 48 243 159
+ 85 126 194 182 71 11 42 110 109 229 255 0 216 108 127 133
+ 105 72 101 150 243 196 145 88 133 236 2 54 15 247 83 59 176
+ 85 5 105 241 55 134 93 243 188 118 52 46 171 34 67 3 185
+ 145 93 199 101 3 36 83 68 142 84 92 172 100 125 233 38 189
+ 36 203 4 135 240 108 231 30 163 138 165 94 128 145 12 135
+ 241 90 158 160 99 86 111 12 54 91 105 201 21 39 134 85 183
+ 137 98 82 177 198 6 60 79 251 82 189 46 217 152 134 104 12
+ 1 142 78 208 114 104 235 213 217 228 142 57 60 188 6 101
+ 237 246 166 173 81 154 62 94 77 44 150 225 83 42 23 213 199
+ 155 244 21 29 213 174 34 181 133 247 220 69 1 3 45 52 190
+ 103 31 65 255 0 106 47 91 215 45 44 81 252 95 21 220 29 171
+ 26 33 44 199 219 21 16 190 126 161 214 8 240 109 13 165 190
+ 237 202 146 99 113 250 241 154 41 1 161 62 179 175 104 240
+ 69 36 239 49 42 23 205 52 173 134 99 238 61 170 187 215 53
+ 233 37 34 230 214 241 150 215 186 60 131 195 76 125 9 239
+ 86 14 163 209 114 73 40 146 238 54 109 195 45 189 72 254
+ 193 138 135 117 47 195 150 190 148 93 78 178 76 35 253 216
+ 201 217 143 246 79 21 130 138 135 172 58 169 217 198 39 142
+ 64 252 43 3 197 34 211 238 191 16 134 70 238 220 131 232 69
+ 75 117 206 133 188 138 228 205 37 140 174 15 206 242 112
+ 168 61 197 71 36 129 44 93 193 85 69 221 181 85 152 3 143
+ 240 166 143 96 146 189 131 187 237 63 74 196 29 195 53 186
+ 102 73 6 236 167 232 192 255 0 133 106 85 227 140 99 239 79
+ 45 128 38 30 212 162 251 139 174 120 230 156 64 8 250 15
+ 189 1 168 70 11 124 188 147 223 35 20 189 9 35 116 37 90
+ 223 5 128 29 243 65 234 18 255 0 67 184 255 0 116 244 90 41
+ 16 1 142 195 222 151 106 24 252 61 194 110 27 188 54 227 61
+ 179 78 165 162 110 34 139 47 220 55 251 165 160 238 251 175
+ 251 85 234 245 73 118 116 190 131 109 63 174 219 83 53 253
+ 234 126 181 234 245 80 80 139 143 222 15 189 122 95 221 143
+ 189 122 189 88 198 235 207 234 95 253 163 252 107 86 155
+ 251 179 246 175 87 169 31 209 144 77 191 121 255 0 217 173
+ 49 127 90 95 246 133 122 189 74 198 143 99 214 236 104 22
+ 253 243 125 235 213 234 148 69 126 198 211 251 197 175 79
+ 251 179 94 175 80 8 60 191 187 95 181 100 191 184 74 245
+ 122 153 244 62 46 204 26 180 183 239 79 218 189 94 166 47
+ 30 205 144 126 248 81 147 250 215 171 213 136 100 236 244
+ 63 45 125 184 253 239 255 0 109 122 189 80 143 177 51 91
+ 252 181 157 167 205 94 175 85 95 208 154 161 175 147 126
+ 234 111 246 63 235 94 175 83 46 204 129 173 191 131 237 91
+ 117 15 221 138 245 122 156 192 58 215 249 246 111 247 149
+ 242 127 221 39 251 85 234 245 17 88 116 223 212 135 218 148
+ 220 254 224 87 171 212 16 77 109 253 105 105 76 159 214 222
+ 189 94 162 140 205 87 255 0 50 255 0 179 88 71 242 10 245
+ 122 156 64 133 253 217 161 174 254 85 255 0 106 189 94 165
+ 125 139 35 47 253 58 105 99 253 68 255 0 186 175 87 168 174
+ 133 63 255 217 13 10 45 45 45 45 45 45 45 45 45 45 45 45 45
+ 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 49 49 51 55
+ 53 50 50 53 48 51 49 52 52 49 50 56 50 51 50 55 49 54 53 51
+ 49 55 50 57 13 10 67 111 110 116 101 110 116 45 68 105 115
+ 112 111 115 105 116 105 111 110 58 32 102 111 114 109 45
+ 100 97 116 97 59 32 110 97 109 101 61 34 102 105 108 101 50
+ 34 59 32 102 105 108 101 110 97 109 101 61 34 116 101 115
+ 116 46 116 120 116 34 13 10 67 111 110 116 101 110 116 45
+ 84 121 112 101 58 32 116 101 120 116 47 112 108 97 105 110
+ 13 10 13 10 116 101 115 116 10 13 10 45 45 45 45 45 45 45
+ 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45
+ 45 45 49 49 51 55 53 50 50 53 48 51 49 52 52 49 50 56 50 51
+ 50 55 49 54 53 51 49 55 50 57 13 10 67 111 110 116 101 110
+ 116 45 68 105 115 112 111 115 105 116 105 111 110 58 32 102
+ 111 114 109 45 100 97 116 97 59 32 110 97 109 101 61 34 102
+ 105 108 101 51 34 59 32 102 105 108 101 110 97 109 101 61
+ 34 34 13 10 67 111 110 116 101 110 116 45 84 121 112 101 58
+ 32 97 112 112 108 105 99 97 116 105 111 110 47 111 99 116
+ 101 116 45 115 116 114 101 97 109 13 10 13 10 13 10 45 45
+ 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45
+ 45 45 45 45 45 45 45 49 49 51 55 53 50 50 53 48 51 49 52 52
+ 49 50 56 50 51 50 55 49 54 53 51 49 55 50 57 45 45 13 10
+ } ;
+
+: test-file ( bytes -- seq )
+ binary <byte-reader> parse-multipart ;
+
+: test-file1 ( bytes -- ? )
+ test-file
+ first [ filename>> "dog.jpg" = ] [ name>> "file1" = ]
+ [ path>> md5 checksum-file B{ 172 192 179 2 18 210 155 156 115 186 169 30 147 51 91 82 } = ] tri and and ;
+
+: test-file2 ( bytes -- ? )
+ test-file
+ second [ filename>> "test.txt" = ] [ name>> "file2" = ]
+ [ path>> ascii file-contents "test\n" = ] tri and and ;
+
+: test-file3 ( bytes -- ? )
+ test-file
+ third [ filename>> "" = ]
+ [ name>> "file3" = ]
+ [ path>> file-info size>> 0 = ] tri and and ;
+
+[ t ] [ dog-test-empty-bytes-firefox test-file1 ] unit-test
+[ t ] [ dog-test-empty-bytes-firefox test-file2 ] unit-test
+[ t ] [ dog-test-empty-bytes-firefox test-file3 ] unit-test
+
+[ t ] [ dog-test-empty-bytes-safari test-file1 ] unit-test
+[ t ] [ dog-test-empty-bytes-safari test-file2 ] unit-test
+[ t ] [ dog-test-empty-bytes-safari test-file3 ] unit-test
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators io kernel locals math multiline
+sequences splitting prettyprint namespaces http.parsers
+ascii assocs unicode.case io.files.unique io.files io.encodings.binary
+byte-arrays io.encodings make fry ;
+IN: mime.multipart
+
+TUPLE: multipart-stream stream n leftover separator ;
+
+: <multipart-stream> ( stream separator -- multipart-stream )
+ multipart-stream new
+ swap >>separator
+ swap >>stream
+ 16 2^ >>n ;
+
+<PRIVATE
+
+: ?append ( seq1 seq2 -- newseq/seq2 )
+ over [ append ] [ nip ] if ;
+
+: ?cut* ( seq n -- before after )
+ over length over <= [ drop f swap ] [ cut* ] if ;
+
+: read-n ( stream -- bytes end-stream? )
+ [ f ] change-leftover
+ [ n>> ] [ stream>> ] bi stream-read [ ?append ] keep not ;
+
+: multipart-split ( bytes separator -- before after seq=? )
+ 2dup sequence= [ 2drop f f t ] [ split1 f ] if ;
+
+:: multipart-step-found ( bytes stream quot: ( bytes -- ) -- ? )
+ bytes [ quot unless-empty ]
+ [ stream (>>leftover) quot unless-empty ] if-empty f ; inline
+
+:: multipart-step-not-found ( bytes stream end-stream? separator quot: ( bytes -- ) -- ? )
+ bytes end-stream? [
+ quot unless-empty f
+ ] [
+ separator length 1- ?cut* stream (>>leftover)
+ quot unless-empty t
+ ] if ; inline
+
+:: multipart-step ( stream bytes end-stream? separator quot: ( bytes -- ) -- ? end-stream? )
+ #! return t to loop again
+ bytes separator multipart-split
+ [ 2drop f ]
+ [
+ [ stream quot multipart-step-found ]
+ [ stream end-stream? separator quot multipart-step-not-found ] if*
+ ] if stream leftover>> end-stream? not or >boolean ;
+
+
+:: multipart-step-loop ( stream quot1: ( bytes -- ) -- ? )
+ stream dup [ read-n ] [ separator>> ] bi quot1 multipart-step
+ swap [ drop stream quot1 multipart-step-loop ] when ; inline recursive
+
+SYMBOL: header
+SYMBOL: parsed-header
+SYMBOL: magic-separator
+
+: trim-blanks ( str -- str' ) [ blank? ] trim ;
+
+: trim-quotes ( str -- str' )
+ [ [ CHAR: " = ] [ CHAR: ' = ] bi or ] trim ;
+
+: parse-content-disposition ( str -- content-disposition hash )
+ ";" split [ first ] [ rest-slice ] bi [ "=" split ] map
+ [ [ trim-blanks ] [ trim-quotes ] bi* ] H{ } assoc-map-as ;
+
+: parse-multipart-header ( string -- headers )
+ "\r\n" split harvest
+ [ parse-header-line first2 ] H{ } map>assoc ;
+
+ERROR: expected-file ;
+
+TUPLE: uploaded-file path filename name ;
+
+: (parse-multipart) ( stream -- ? )
+ "\r\n\r\n" >>separator
+ header off
+ dup [ header [ prepend ] change ] multipart-step-loop drop
+ header get dup magic-separator get [ length ] bi@ < [
+ 2drop f
+ ] [
+ parse-multipart-header
+ parsed-header set
+ "\r\n" magic-separator get append >>separator
+ "factor-upload" "httpd" make-unique-file tuck
+ binary [ [ write ] multipart-step-loop ] with-file-writer swap
+ "content-disposition" parsed-header get at parse-content-disposition
+ nip [ "filename" swap at ] [ "name" swap at ] bi
+ uploaded-file boa ,
+ ] if ;
+
+PRIVATE>
+
+: parse-multipart ( stream -- array )
+ [
+ "\r\n" <multipart-stream>
+ magic-separator off
+ dup [ magic-separator [ prepend ] change ]
+ multipart-step-loop drop
+ '[ [ _ (parse-multipart) ] loop ] { } make
+ ] with-scope ;
--- /dev/null
+Slava Pestov
--- /dev/null
+# This is a comment. I love comments.
+
+# This file controls what Internet media types are sent to the client for
+# given file extension(s). Sending the correct media type to the client
+# is important so they know how to handle the content of the file.
+# Extra types can either be added here or by using an AddType directive
+# in your config files. For more information about Internet media types,
+# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type
+# registry is at <http://www.iana.org/assignments/media-types/>.
+
+# MIME type Extensions
+application/activemessage
+application/andrew-inset ez
+application/applefile
+application/atom+xml atom
+application/atomcat+xml atomcat
+application/atomicmail
+application/atomsvc+xml atomsvc
+application/auth-policy+xml
+application/batch-smtp
+application/beep+xml
+application/cals-1840
+application/ccxml+xml ccxml
+application/cellml+xml
+application/cnrp+xml
+application/commonground
+application/conference-info+xml
+application/cpl+xml
+application/csta+xml
+application/cstadata+xml
+application/cybercash
+application/davmount+xml davmount
+application/dca-rft
+application/dec-dx
+application/dialog-info+xml
+application/dicom
+application/dns
+application/dvcs
+application/ecmascript ecma
+application/edi-consent
+application/edi-x12
+application/edifact
+application/epp+xml
+application/eshop
+application/fastinfoset
+application/fastsoap
+application/fits
+application/font-tdpfr pfr
+application/h224
+application/http
+application/hyperstudio stk
+application/iges
+application/im-iscomposing+xml
+application/index
+application/index.cmd
+application/index.obj
+application/index.response
+application/index.vnd
+application/iotp
+application/ipp
+application/isup
+application/javascript js
+application/json json
+application/kpml-request+xml
+application/kpml-response+xml
+application/mac-binhex40 hqx
+application/mac-compactpro cpt
+application/macwriteii
+application/marc mrc
+application/mathematica ma nb mb
+application/mathml+xml mathml
+application/mbms-associated-procedure-description+xml
+application/mbms-deregister+xml
+application/mbms-envelope+xml
+application/mbms-msk+xml
+application/mbms-msk-response+xml
+application/mbms-protection-description+xml
+application/mbms-reception-report+xml
+application/mbms-register+xml
+application/mbms-register-response+xml
+application/mbms-user-service-description+xml
+application/mbox mbox
+application/mediaservercontrol+xml mscml
+application/mikey
+application/mp4 mp4s
+application/mpeg4-generic
+application/mpeg4-iod
+application/mpeg4-iod-xmt
+application/msword doc dot
+application/mxf mxf
+application/nasdata
+application/news-message-id
+application/news-transmission
+application/nss
+application/ocsp-request
+application/ocsp-response
+application/octet-stream bin dms lha lzh class so iso dmg dist distz pkg bpk dump elc scpt
+application/oda oda
+application/oebps-package+xml
+application/ogg ogg
+application/parityfec
+application/pdf pdf
+application/pgp-encrypted pgp
+application/pgp-keys
+application/pgp-signature asc sig
+application/pics-rules prf
+application/pidf+xml
+application/pkcs10 p10
+application/pkcs7-mime p7m p7c
+application/pkcs7-signature p7s
+application/pkix-cert cer
+application/pkix-crl crl
+application/pkix-pkipath pkipath
+application/pkixcmp pki
+application/pls+xml pls
+application/poc-settings+xml
+application/postscript ai eps ps
+application/prs.alvestrand.titrax-sheet
+application/prs.cww cww
+application/prs.nprend
+application/prs.plucker
+application/qsig
+application/rdf+xml rdf
+application/reginfo+xml rif
+application/relax-ng-compact-syntax rnc
+application/remote-printing
+application/resource-lists+xml rl
+application/riscos
+application/rlmi+xml
+application/rls-services+xml rs
+application/rsd+xml rsd
+application/rss+xml rss
+application/rtf rtf
+application/rtx
+application/samlassertion+xml
+application/samlmetadata+xml
+application/sbml+xml sbml
+application/sdp sdp
+application/set-payment
+application/set-payment-initiation setpay
+application/set-registration
+application/set-registration-initiation setreg
+application/sgml
+application/sgml-open-catalog
+application/shf+xml shf
+application/sieve
+application/simple-filter+xml
+application/simple-message-summary
+application/simplesymbolcontainer
+application/slate
+application/smil
+application/smil+xml smi smil
+application/soap+fastinfoset
+application/soap+xml
+application/spirits-event+xml
+application/srgs gram
+application/srgs+xml grxml
+application/ssml+xml ssml
+application/timestamp-query
+application/timestamp-reply
+application/tve-trigger
+application/vemmi
+application/vividence.scriptfile
+application/vnd.3gpp.bsf+xml
+application/vnd.3gpp.pic-bw-large plb
+application/vnd.3gpp.pic-bw-small psb
+application/vnd.3gpp.pic-bw-var pvb
+application/vnd.3gpp.sms
+application/vnd.3gpp2.bcmcsinfo+xml
+application/vnd.3gpp2.sms
+application/vnd.3m.post-it-notes pwn
+application/vnd.accpac.simply.aso aso
+application/vnd.accpac.simply.imp imp
+application/vnd.acucobol acu
+application/vnd.acucorp atc acutc
+application/vnd.adobe.xdp+xml xdp
+application/vnd.adobe.xfdf xfdf
+application/vnd.aether.imp
+application/vnd.amiga.ami ami
+application/vnd.anser-web-certificate-issue-initiation cii
+application/vnd.anser-web-funds-transfer-initiation fti
+application/vnd.antix.game-component atx
+application/vnd.apple.installer+xml mpkg
+application/vnd.audiograph aep
+application/vnd.autopackage
+application/vnd.avistar+xml
+application/vnd.blueice.multipass mpm
+application/vnd.bmi bmi
+application/vnd.businessobjects rep
+application/vnd.cab-jscript
+application/vnd.canon-cpdl
+application/vnd.canon-lips
+application/vnd.cendio.thinlinc.clientconf
+application/vnd.chemdraw+xml cdxml
+application/vnd.chipnuts.karaoke-mmd mmd
+application/vnd.cinderella cdy
+application/vnd.cirpack.isdn-ext
+application/vnd.claymore cla
+application/vnd.clonk.c4group c4g c4d c4f c4p c4u
+application/vnd.commerce-battelle
+application/vnd.commonspace csp cst
+application/vnd.contact.cmsg cdbcmsg
+application/vnd.cosmocaller cmc
+application/vnd.crick.clicker clkx
+application/vnd.crick.clicker.keyboard clkk
+application/vnd.crick.clicker.palette clkp
+application/vnd.crick.clicker.template clkt
+application/vnd.crick.clicker.wordbank clkw
+application/vnd.criticaltools.wbs+xml wbs
+application/vnd.ctc-posml pml
+application/vnd.cups-pdf
+application/vnd.cups-postscript
+application/vnd.cups-ppd ppd
+application/vnd.cups-raster
+application/vnd.cups-raw
+application/vnd.curl curl
+application/vnd.cybank
+application/vnd.data-vision.rdz rdz
+application/vnd.denovo.fcselayout-link fe_launch
+application/vnd.dna dna
+application/vnd.dolby.mlp mlp
+application/vnd.dpgraph dpg
+application/vnd.dreamfactory dfac
+application/vnd.dvb.esgcontainer
+application/vnd.dvb.ipdcesgaccess
+application/vnd.dxr
+application/vnd.ecdis-update
+application/vnd.ecowin.chart mag
+application/vnd.ecowin.filerequest
+application/vnd.ecowin.fileupdate
+application/vnd.ecowin.series
+application/vnd.ecowin.seriesrequest
+application/vnd.ecowin.seriesupdate
+application/vnd.enliven nml
+application/vnd.epson.esf esf
+application/vnd.epson.msf msf
+application/vnd.epson.quickanime qam
+application/vnd.epson.salt slt
+application/vnd.epson.ssf ssf
+application/vnd.ericsson.quickcall
+application/vnd.eszigno3+xml es3 et3
+application/vnd.eudora.data
+application/vnd.ezpix-album ez2
+application/vnd.ezpix-package ez3
+application/vnd.fdf fdf
+application/vnd.ffsns
+application/vnd.fints
+application/vnd.flographit gph
+application/vnd.fluxtime.clip ftc
+application/vnd.framemaker fm frame maker
+application/vnd.frogans.fnc fnc
+application/vnd.frogans.ltf ltf
+application/vnd.fsc.weblaunch fsc
+application/vnd.fujitsu.oasys oas
+application/vnd.fujitsu.oasys2 oa2
+application/vnd.fujitsu.oasys3 oa3
+application/vnd.fujitsu.oasysgp fg5
+application/vnd.fujitsu.oasysprs bh2
+application/vnd.fujixerox.art-ex
+application/vnd.fujixerox.art4
+application/vnd.fujixerox.hbpl
+application/vnd.fujixerox.ddd ddd
+application/vnd.fujixerox.docuworks xdw
+application/vnd.fujixerox.docuworks.binder xbd
+application/vnd.fut-misnet
+application/vnd.fuzzysheet fzs
+application/vnd.genomatix.tuxedo txd
+application/vnd.google-earth.kml+xml kml
+application/vnd.google-earth.kmz kmz
+application/vnd.grafeq gqf gqs
+application/vnd.gridmp
+application/vnd.groove-account gac
+application/vnd.groove-help ghf
+application/vnd.groove-identity-message gim
+application/vnd.groove-injector grv
+application/vnd.groove-tool-message gtm
+application/vnd.groove-tool-template tpl
+application/vnd.groove-vcard vcg
+application/vnd.handheld-entertainment+xml zmm
+application/vnd.hbci hbci
+application/vnd.hcl-bireports
+application/vnd.hhe.lesson-player les
+application/vnd.hp-hpgl hpgl
+application/vnd.hp-hpid hpid
+application/vnd.hp-hps hps
+application/vnd.hp-jlyt jlt
+application/vnd.hp-pcl pcl
+application/vnd.hp-pclxl pclxl
+application/vnd.httphone
+application/vnd.hzn-3d-crossword x3d
+application/vnd.ibm.afplinedata
+application/vnd.ibm.electronic-media
+application/vnd.ibm.minipay mpy
+application/vnd.ibm.modcap afp listafp list3820
+application/vnd.ibm.rights-management irm
+application/vnd.ibm.secure-container sc
+application/vnd.igloader igl
+application/vnd.immervision-ivp ivp
+application/vnd.immervision-ivu ivu
+application/vnd.informedcontrol.rms+xml
+application/vnd.intercon.formnet xpw xpx
+application/vnd.intertrust.digibox
+application/vnd.intertrust.nncp
+application/vnd.intu.qbo qbo
+application/vnd.intu.qfx qfx
+application/vnd.ipunplugged.rcprofile rcprofile
+application/vnd.irepository.package+xml irp
+application/vnd.is-xpr xpr
+application/vnd.jam jam
+application/vnd.japannet-directory-service
+application/vnd.japannet-jpnstore-wakeup
+application/vnd.japannet-payment-wakeup
+application/vnd.japannet-registration
+application/vnd.japannet-registration-wakeup
+application/vnd.japannet-setstore-wakeup
+application/vnd.japannet-verification
+application/vnd.japannet-verification-wakeup
+application/vnd.jcp.javame.midlet-rms rms
+application/vnd.jisp jisp
+application/vnd.kahootz ktz ktr
+application/vnd.kde.karbon karbon
+application/vnd.kde.kchart chrt
+application/vnd.kde.kformula kfo
+application/vnd.kde.kivio flw
+application/vnd.kde.kontour kon
+application/vnd.kde.kpresenter kpr kpt
+application/vnd.kde.kspread ksp
+application/vnd.kde.kword kwd kwt
+application/vnd.kenameaapp htke
+application/vnd.kidspiration kia
+application/vnd.kinar kne knp
+application/vnd.koan skp skd skt skm
+application/vnd.liberty-request+xml
+application/vnd.llamagraphics.life-balance.desktop lbd
+application/vnd.llamagraphics.life-balance.exchange+xml lbe
+application/vnd.lotus-1-2-3 123
+application/vnd.lotus-approach apr
+application/vnd.lotus-freelance pre
+application/vnd.lotus-notes nsf
+application/vnd.lotus-organizer org
+application/vnd.lotus-screencam scm
+application/vnd.lotus-wordpro lwp
+application/vnd.macports.portpkg portpkg
+application/vnd.marlin.drm.actiontoken+xml
+application/vnd.marlin.drm.conftoken+xml
+application/vnd.marlin.drm.mdcf
+application/vnd.mcd mcd
+application/vnd.medcalcdata mc1
+application/vnd.mediastation.cdkey cdkey
+application/vnd.meridian-slingshot
+application/vnd.mfer mwf
+application/vnd.mfmp mfm
+application/vnd.micrografx.flo flo
+application/vnd.micrografx.igx igx
+application/vnd.mif mif
+application/vnd.minisoft-hp3000-save
+application/vnd.mitsubishi.misty-guard.trustweb
+application/vnd.mobius.daf daf
+application/vnd.mobius.dis dis
+application/vnd.mobius.mbk mbk
+application/vnd.mobius.mqy mqy
+application/vnd.mobius.msl msl
+application/vnd.mobius.plc plc
+application/vnd.mobius.txf txf
+application/vnd.mophun.application mpn
+application/vnd.mophun.certificate mpc
+application/vnd.motorola.flexsuite
+application/vnd.motorola.flexsuite.adsi
+application/vnd.motorola.flexsuite.fis
+application/vnd.motorola.flexsuite.gotap
+application/vnd.motorola.flexsuite.kmr
+application/vnd.motorola.flexsuite.ttc
+application/vnd.motorola.flexsuite.wem
+application/vnd.mozilla.xul+xml xul
+application/vnd.ms-artgalry cil
+application/vnd.ms-asf asf
+application/vnd.ms-cab-compressed cab
+application/vnd.ms-excel xls xlm xla xlc xlt xlw
+application/vnd.ms-fontobject eot
+application/vnd.ms-htmlhelp chm
+application/vnd.ms-ims ims
+application/vnd.ms-lrm lrm
+application/vnd.ms-playready.initiator+xml
+application/vnd.ms-powerpoint ppt pps pot
+application/vnd.ms-project mpp mpt
+application/vnd.ms-tnef
+application/vnd.ms-wmdrm.lic-chlg-req
+application/vnd.ms-wmdrm.lic-resp
+application/vnd.ms-wmdrm.meter-chlg-req
+application/vnd.ms-wmdrm.meter-resp
+application/vnd.ms-works wps wks wcm wdb
+application/vnd.ms-wpl wpl
+application/vnd.ms-xpsdocument xps
+application/vnd.mseq mseq
+application/vnd.msign
+application/vnd.music-niff
+application/vnd.musician mus
+application/vnd.ncd.control
+application/vnd.nervana
+application/vnd.netfpx
+application/vnd.neurolanguage.nlu nlu
+application/vnd.noblenet-directory nnd
+application/vnd.noblenet-sealer nns
+application/vnd.noblenet-web nnw
+application/vnd.nokia.catalogs
+application/vnd.nokia.conml+wbxml
+application/vnd.nokia.conml+xml
+application/vnd.nokia.isds-radio-presets
+application/vnd.nokia.iptv.config+xml
+application/vnd.nokia.landmark+wbxml
+application/vnd.nokia.landmark+xml
+application/vnd.nokia.landmarkcollection+xml
+application/vnd.nokia.n-gage.ac+xml
+application/vnd.nokia.n-gage.data ngdat
+application/vnd.nokia.n-gage.symbian.install n-gage
+application/vnd.nokia.ncd
+application/vnd.nokia.pcd+wbxml
+application/vnd.nokia.pcd+xml
+application/vnd.nokia.radio-preset rpst
+application/vnd.nokia.radio-presets rpss
+application/vnd.novadigm.edm edm
+application/vnd.novadigm.edx edx
+application/vnd.novadigm.ext ext
+application/vnd.oasis.opendocument.chart odc
+application/vnd.oasis.opendocument.chart-template otc
+application/vnd.oasis.opendocument.formula odf
+application/vnd.oasis.opendocument.formula-template otf
+application/vnd.oasis.opendocument.graphics odg
+application/vnd.oasis.opendocument.graphics-template otg
+application/vnd.oasis.opendocument.image odi
+application/vnd.oasis.opendocument.image-template oti
+application/vnd.oasis.opendocument.presentation odp
+application/vnd.oasis.opendocument.presentation-template otp
+application/vnd.oasis.opendocument.spreadsheet ods
+application/vnd.oasis.opendocument.spreadsheet-template ots
+application/vnd.oasis.opendocument.text odt
+application/vnd.oasis.opendocument.text-master otm
+application/vnd.oasis.opendocument.text-template ott
+application/vnd.oasis.opendocument.text-web oth
+application/vnd.obn
+application/vnd.olpc-sugar xo
+application/vnd.oma-scws-config
+application/vnd.oma-scws-http-request
+application/vnd.oma-scws-http-response
+application/vnd.oma.bcast.associated-procedure-parameter+xml
+application/vnd.oma.bcast.drm-trigger+xml
+application/vnd.oma.bcast.imd+xml
+application/vnd.oma.bcast.notification+xml
+application/vnd.oma.bcast.sgboot
+application/vnd.oma.bcast.sgdd+xml
+application/vnd.oma.bcast.sgdu
+application/vnd.oma.bcast.simple-symbol-container
+application/vnd.oma.bcast.smartcard-trigger+xml
+application/vnd.oma.bcast.sprov+xml
+application/vnd.oma.dd2+xml dd2
+application/vnd.oma.drm.risd+xml
+application/vnd.oma.group-usage-list+xml
+application/vnd.oma.poc.groups+xml
+application/vnd.oma.xcap-directory+xml
+application/vnd.omads-email+xml
+application/vnd.omads-file+xml
+application/vnd.omads-folder+xml
+application/vnd.omaloc-supl-init
+application/vnd.openofficeorg.extension oxt
+application/vnd.osa.netdeploy
+application/vnd.osgi.dp dp
+application/vnd.otps.ct-kip+xml
+application/vnd.palm prc pdb pqa oprc
+application/vnd.paos.xml
+application/vnd.pg.format str
+application/vnd.pg.osasli ei6
+application/vnd.piaccess.application-licence
+application/vnd.picsel efif
+application/vnd.poc.group-advertisement+xml
+application/vnd.pocketlearn plf
+application/vnd.powerbuilder6 pbd
+application/vnd.powerbuilder6-s
+application/vnd.powerbuilder7
+application/vnd.powerbuilder7-s
+application/vnd.powerbuilder75
+application/vnd.powerbuilder75-s
+application/vnd.preminet
+application/vnd.previewsystems.box box
+application/vnd.proteus.magazine mgz
+application/vnd.publishare-delta-tree qps
+application/vnd.pvi.ptid1 ptid
+application/vnd.pwg-multiplexed
+application/vnd.pwg-xhtml-print+xml
+application/vnd.qualcomm.brew-app-res
+application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb
+application/vnd.rapid
+application/vnd.recordare.musicxml mxl
+application/vnd.recordare.musicxml+xml
+application/vnd.renlearn.rlprint
+application/vnd.rn-realmedia rm
+application/vnd.ruckus.download
+application/vnd.s3sms
+application/vnd.scribus
+application/vnd.sealed.3df
+application/vnd.sealed.csf
+application/vnd.sealed.doc
+application/vnd.sealed.eml
+application/vnd.sealed.mht
+application/vnd.sealed.net
+application/vnd.sealed.ppt
+application/vnd.sealed.tiff
+application/vnd.sealed.xls
+application/vnd.sealedmedia.softseal.html
+application/vnd.sealedmedia.softseal.pdf
+application/vnd.seemail see
+application/vnd.sema sema
+application/vnd.semd semd
+application/vnd.semf semf
+application/vnd.shana.informed.formdata ifm
+application/vnd.shana.informed.formtemplate itp
+application/vnd.shana.informed.interchange iif
+application/vnd.shana.informed.package ipk
+application/vnd.simtech-mindmapper twd twds
+application/vnd.smaf mmf
+application/vnd.solent.sdkm+xml sdkm sdkd
+application/vnd.spotfire.dxp dxp
+application/vnd.spotfire.sfs sfs
+application/vnd.sss-cod
+application/vnd.sss-dtf
+application/vnd.sss-ntf
+application/vnd.street-stream
+application/vnd.sun.wadl+xml
+application/vnd.sus-calendar sus susp
+application/vnd.svd svd
+application/vnd.swiftview-ics
+application/vnd.syncml+xml xsm
+application/vnd.syncml.dm+wbxml bdm
+application/vnd.syncml.dm+xml xdm
+application/vnd.syncml.ds.notification
+application/vnd.tao.intent-module-archive tao
+application/vnd.tmobile-livetv tmo
+application/vnd.trid.tpt tpt
+application/vnd.triscape.mxs mxs
+application/vnd.trueapp tra
+application/vnd.truedoc
+application/vnd.ufdl ufd ufdl
+application/vnd.uiq.theme utz
+application/vnd.umajin umj
+application/vnd.unity unityweb
+application/vnd.uoml+xml uoml
+application/vnd.uplanet.alert
+application/vnd.uplanet.alert-wbxml
+application/vnd.uplanet.bearer-choice
+application/vnd.uplanet.bearer-choice-wbxml
+application/vnd.uplanet.cacheop
+application/vnd.uplanet.cacheop-wbxml
+application/vnd.uplanet.channel
+application/vnd.uplanet.channel-wbxml
+application/vnd.uplanet.list
+application/vnd.uplanet.list-wbxml
+application/vnd.uplanet.listcmd
+application/vnd.uplanet.listcmd-wbxml
+application/vnd.uplanet.signal
+application/vnd.vcx vcx
+application/vnd.vd-study
+application/vnd.vectorworks
+application/vnd.vidsoft.vidconference
+application/vnd.visio vsd vst vss vsw
+application/vnd.visionary vis
+application/vnd.vividence.scriptfile
+application/vnd.vsf vsf
+application/vnd.wap.sic
+application/vnd.wap.slc
+application/vnd.wap.wbxml wbxml
+application/vnd.wap.wmlc wmlc
+application/vnd.wap.wmlscriptc wmlsc
+application/vnd.webturbo wtb
+application/vnd.wfa.wsc
+application/vnd.wordperfect wpd
+application/vnd.wqd wqd
+application/vnd.wrq-hp3000-labelled
+application/vnd.wt.stf stf
+application/vnd.wv.csp+wbxml
+application/vnd.wv.csp+xml
+application/vnd.wv.ssp+xml
+application/vnd.xara xar
+application/vnd.xfdl xfdl
+application/vnd.xmpie.cpkg
+application/vnd.xmpie.dpkg
+application/vnd.xmpie.plan
+application/vnd.xmpie.ppkg
+application/vnd.xmpie.xlim
+application/vnd.yamaha.hv-dic hvd
+application/vnd.yamaha.hv-script hvs
+application/vnd.yamaha.hv-voice hvp
+application/vnd.yamaha.smaf-audio saf
+application/vnd.yamaha.smaf-phrase spf
+application/vnd.yellowriver-custom-menu cmp
+application/vnd.zzazz.deck+xml zaz
+application/voicexml+xml vxml
+application/watcherinfo+xml
+application/whoispp-query
+application/whoispp-response
+application/winhlp hlp
+application/wita
+application/wordperfect5.1
+application/wsdl+xml wsdl
+application/wspolicy+xml wspolicy
+application/x-ace-compressed ace
+application/x-bcpio bcpio
+application/x-bittorrent torrent
+application/x-bzip bz
+application/x-bzip2 bz2 boz
+application/x-cdlink vcd
+application/x-chat chat
+application/x-chess-pgn pgn
+application/x-compress
+application/x-cpio cpio
+application/x-csh csh
+application/x-director dcr dir dxr fgd
+application/x-dvi dvi
+application/x-futuresplash spl
+application/x-gtar gtar
+application/x-gzip
+application/x-hdf hdf
+application/x-java-jnlp-file jnlp
+application/x-latex latex
+application/x-ms-wmd wmd
+application/x-ms-wmz wmz
+application/x-msaccess mdb
+application/x-msbinder obd
+application/x-mscardfile crd
+application/x-msclip clp
+application/x-msdownload exe dll com bat msi
+application/x-msmediaview mvb m13 m14
+application/x-msmetafile wmf
+application/x-msmoney mny
+application/x-mspublisher pub
+application/x-msschedule scd
+application/x-msterminal trm
+application/x-mswrite wri
+application/x-netcdf nc cdf
+application/x-pkcs12 p12 pfx
+application/x-pkcs7-certificates p7b spc
+application/x-pkcs7-certreqresp p7r
+application/x-rar-compressed rar
+application/x-sh sh
+application/x-shar shar
+application/x-shockwave-flash swf
+application/x-stuffit sit
+application/x-stuffitx sitx
+application/x-sv4cpio sv4cpio
+application/x-sv4crc sv4crc
+application/x-tar tar
+application/x-tcl tcl
+application/x-tex tex
+application/x-texinfo texinfo texi
+application/x-ustar ustar
+application/x-wais-source src
+application/x-x509-ca-cert der crt
+application/x400-bp
+application/xcap-att+xml
+application/xcap-caps+xml
+application/xcap-el+xml
+application/xcap-error+xml
+application/xcap-ns+xml
+application/xenc+xml xenc
+application/xhtml+xml xhtml xht
+application/xml xml xsl
+application/xml-dtd dtd
+application/xml-external-parsed-entity
+application/xmpp+xml
+application/xop+xml xop
+application/xslt+xml xslt
+application/xspf+xml xspf
+application/xv+xml mxml xhvml xvml xvm
+application/zip zip
+audio/32kadpcm
+audio/3gpp
+audio/3gpp2
+audio/ac3
+audio/amr
+audio/amr-wb
+audio/amr-wb+
+audio/asc
+audio/basic au snd
+audio/bv16
+audio/bv32
+audio/clearmode
+audio/cn
+audio/dat12
+audio/dls
+audio/dsr-es201108
+audio/dsr-es202050
+audio/dsr-es202211
+audio/dsr-es202212
+audio/dvi4
+audio/eac3
+audio/evrc
+audio/evrc-qcp
+audio/evrc0
+audio/evrc1
+audio/evrcb
+audio/evrcb0
+audio/evrcb1
+audio/g722
+audio/g7221
+audio/g723
+audio/g726-16
+audio/g726-24
+audio/g726-32
+audio/g726-40
+audio/g728
+audio/g729
+audio/g7291
+audio/g729d
+audio/g729e
+audio/gsm
+audio/gsm-efr
+audio/ilbc
+audio/l16
+audio/l20
+audio/l24
+audio/l8
+audio/lpc
+audio/midi mid midi kar rmi
+audio/mobile-xmf
+audio/mp4 mp4a
+audio/mp4a-latm m4a m4p
+audio/mpa
+audio/mpa-robust
+audio/mpeg mpga mp2 mp2a mp3 m2a m3a
+audio/mpeg4-generic
+audio/parityfec
+audio/pcma
+audio/pcmu
+audio/prs.sid
+audio/qcelp
+audio/red
+audio/rtp-enc-aescm128
+audio/rtp-midi
+audio/rtx
+audio/smv
+audio/smv0
+audio/smv-qcp
+audio/sp-midi
+audio/t140c
+audio/t38
+audio/telephone-event
+audio/tone
+audio/vdvi
+audio/vmr-wb
+audio/vnd.3gpp.iufp
+audio/vnd.4sb
+audio/vnd.audiokoz
+audio/vnd.celp
+audio/vnd.cisco.nse
+audio/vnd.cmles.radio-events
+audio/vnd.cns.anp1
+audio/vnd.cns.inf1
+audio/vnd.digital-winds eol
+audio/vnd.dlna.adts
+audio/vnd.dolby.mlp
+audio/vnd.everad.plj
+audio/vnd.hns.audio
+audio/vnd.lucent.voice lvp
+audio/vnd.nokia.mobile-xmf
+audio/vnd.nortel.vbk
+audio/vnd.nuera.ecelp4800 ecelp4800
+audio/vnd.nuera.ecelp7470 ecelp7470
+audio/vnd.nuera.ecelp9600 ecelp9600
+audio/vnd.octel.sbc
+audio/vnd.qcelp
+audio/vnd.rhetorex.32kadpcm
+audio/vnd.sealedmedia.softseal.mpeg
+audio/vnd.vmx.cvsd
+audio/wav wav
+audio/x-aiff aif aiff aifc
+audio/x-mpegurl m3u
+audio/x-ms-wax wax
+audio/x-ms-wma wma
+audio/x-pn-realaudio ram ra
+audio/x-pn-realaudio-plugin rmp
+audio/x-wav wav
+chemical/x-cdx cdx
+chemical/x-cif cif
+chemical/x-cmdf cmdf
+chemical/x-cml cml
+chemical/x-csml csml
+chemical/x-pdb pdb
+chemical/x-xyz xyz
+image/bmp bmp
+image/cgm cgm
+image/fits
+image/g3fax g3
+image/gif gif
+image/ief ief
+image/jp2 jp2
+image/jpeg jpeg jpg jpe
+image/jpm
+image/jpx
+image/naplps
+image/pict pict pic pct
+image/png png
+image/prs.btif btif
+image/prs.pti
+image/svg+xml svg svgz
+image/t38
+image/tiff tiff tif
+image/tiff-fx
+image/vnd.adobe.photoshop psd
+image/vnd.cns.inf2
+image/vnd.djvu djvu djv
+image/vnd.dwg dwg
+image/vnd.dxf dxf
+image/vnd.fastbidsheet fbs
+image/vnd.fpx fpx
+image/vnd.fst fst
+image/vnd.fujixerox.edmics-mmr mmr
+image/vnd.fujixerox.edmics-rlc rlc
+image/vnd.globalgraphics.pgb
+image/vnd.microsoft.icon ico
+image/vnd.mix
+image/vnd.ms-modi mdi
+image/vnd.net-fpx npx
+image/vnd.sealed.png
+image/vnd.sealedmedia.softseal.gif
+image/vnd.sealedmedia.softseal.jpg
+image/vnd.svf
+image/vnd.wap.wbmp wbmp
+image/vnd.xiff xif
+image/x-cmu-raster ras
+image/x-cmx cmx
+image/x-icon
+image/x-macpaint pntg pnt mac
+image/x-pcx pcx
+image/x-pict pic pct
+image/x-portable-anymap pnm
+image/x-portable-bitmap pbm
+image/x-portable-graymap pgm
+image/x-portable-pixmap ppm
+image/x-quicktime qtif qti
+image/x-rgb rgb
+image/x-xbitmap xbm
+image/x-xpixmap xpm
+image/x-xwindowdump xwd
+message/cpim
+message/delivery-status
+message/disposition-notification
+message/external-body
+message/http
+message/news
+message/partial
+message/rfc822 eml mime
+message/s-http
+message/sip
+message/sipfrag
+message/tracking-status
+model/iges igs iges
+model/mesh msh mesh silo
+model/vnd.dwf dwf
+model/vnd.flatland.3dml
+model/vnd.gdl gdl
+model/vnd.gs.gdl
+model/vnd.gtw gtw
+model/vnd.moml+xml
+model/vnd.mts mts
+model/vnd.parasolid.transmit.binary
+model/vnd.parasolid.transmit.text
+model/vnd.vtu vtu
+model/vrml wrl vrml
+multipart/alternative
+multipart/appledouble
+multipart/byteranges
+multipart/digest
+multipart/encrypted
+multipart/form-data
+multipart/header-set
+multipart/mixed
+multipart/parallel
+multipart/related
+multipart/report
+multipart/signed
+multipart/voice-message
+text/calendar ics ifb
+text/css css
+text/csv csv
+text/directory
+text/dns
+text/enriched
+text/html html htm
+text/parityfec
+text/plain txt text conf def list log in
+text/prs.fallenstein.rst
+text/prs.lines.tag dsc
+text/red
+text/rfc822-headers
+text/richtext rtx
+text/rtf
+text/rtp-enc-aescm128
+text/rtx
+text/sgml sgml sgm
+text/t140
+text/tab-separated-values tsv
+text/troff t tr roff man me ms
+text/uri-list uri uris urls
+text/vnd.abc
+text/vnd.curl
+text/vnd.dmclientscript
+text/vnd.esmertec.theme-descriptor
+text/vnd.fly fly
+text/vnd.fmi.flexstor flx
+text/vnd.in3d.3dml 3dml
+text/vnd.in3d.spot spot
+text/vnd.iptc.newsml
+text/vnd.iptc.nitf
+text/vnd.latex-z
+text/vnd.motorola.reflex
+text/vnd.ms-mediapackage
+text/vnd.net2phone.commcenter.command
+text/vnd.sun.j2me.app-descriptor jad
+text/vnd.trolltech.linguist
+text/vnd.wap.si
+text/vnd.wap.sl
+text/vnd.wap.wml wml
+text/vnd.wap.wmlscript wmls
+text/x-asm s asm
+text/x-c c cc cxx cpp h hh dic
+text/x-fortran f for f77 f90
+text/x-pascal p pas
+text/x-java-source java
+text/x-setext etx
+text/x-uuencode uu
+text/x-vcalendar vcs
+text/x-vcard vcf
+text/xml
+text/xml-external-parsed-entity
+video/3gpp 3gp
+video/3gpp-tt
+video/3gpp2 3g2
+video/bmpeg
+video/bt656
+video/celb
+video/dv
+video/h261 h261
+video/h263 h263
+video/h263-1998
+video/h263-2000
+video/h264 h264
+video/jpeg jpgv
+video/jpm jpm jpgm
+video/mj2 mj2 mjp2
+video/mp1s
+video/mp2p
+video/mp2t
+video/mp4 mp4 mp4v mpg4 m4v
+video/mp4v-es
+video/mpeg mpeg mpg mpe m1v m2v
+video/mpeg4-generic
+video/mpv
+video/nv
+video/parityfec
+video/pointer
+video/quicktime qt mov
+video/raw
+video/rtp-enc-aescm128
+video/rtx
+video/smpte292m
+video/vc1
+video/vnd.dlna.mpeg-tts
+video/vnd.fvt fvt
+video/vnd.hns.video
+video/vnd.motorola.video
+video/vnd.motorola.videop
+video/vnd.mpegurl mxu m4u
+video/vnd.nokia.interleaved-multimedia
+video/vnd.nokia.videovoip
+video/vnd.objectvideo
+video/vnd.sealed.mpeg1
+video/vnd.sealed.mpeg4
+video/vnd.sealed.swf
+video/vnd.sealedmedia.softseal.mov
+video/vnd.vivo viv
+video/x-dv dv dif
+video/x-fli fli
+video/x-ms-asf asf asx
+video/x-ms-wm wm
+video/x-ms-wmv wmv
+video/x-ms-wmx wmx
+video/x-ms-wvx wvx
+video/x-msvideo avi
+video/x-sgi-movie movie
+x-conference/x-cooltalk ice
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: assocs help.markup help.syntax io.streams.string sequences ;
+IN: mime.types
+
+HELP: mime-db
+{ $values
+
+ { "seq" sequence } }
+{ $description "Outputs an array where the first element is a MIME type and the rest of the array is file extensions that have that MIME type." } ;
+
+HELP: mime-type
+{ $values
+ { "filename" "a filename" }
+ { "mime-type" "a MIME type string" } }
+{ $description "Outputs the MIME type associtated with a path by parsing the path's file extension and looking it up in the table returned by " { $link mime-types } "." } ;
+
+HELP: mime-types
+{ $values
+
+ { "assoc" assoc } }
+{ $description "Outputs an " { $snippet "assoc" } " made from the data in the " { $link mime-db } " word where the keys are file extensions and the values are the corresponding MIME types." } ;
+
+HELP: nonstandard-mime-types
+{ $values
+
+ { "assoc" assoc } }
+{ $description "A list of Factor-specific MIME types that are added to the MIME database loaded from disk." } ;
+
+ARTICLE: "mime.types" "MIME types"
+"The " { $vocab-link "mime.types" } " vocabulary loads a file of MIME types and provides a word to look up the MIME type based on a file extension." $nl
+"Looking up a MIME type:"
+{ $subsection mime-type } ;
+
+ABOUT: "mime.types"
--- /dev/null
+IN: mime.types.tests
+USING: mime.types tools.test ;
+
+[ "application/postscript" ] [ "foo.ps" mime-type ] unit-test
+[ "application/octet-stream" ] [ "foo.ps.gz" mime-type ] unit-test
+[ "text/plain" ] [ "foo.factor" mime-type ] unit-test
--- /dev/null
+! Copyright (C) 2004, 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: io.files io.encodings.ascii assocs sequences splitting
+kernel namespaces fry memoize ;
+IN: mime.types
+
+MEMO: mime-db ( -- seq )
+ "resource:basis/mime/types/mime.types" ascii file-lines
+ [ "#" head? not ] filter [ " \t" split harvest ] map harvest ;
+
+: nonstandard-mime-types ( -- assoc )
+ H{
+ { "factor" "text/plain" }
+ { "cgi" "application/x-cgi-script" }
+ { "fhtml" "application/x-factor-server-page" }
+ } ;
+
+MEMO: mime-types ( -- assoc )
+ [
+ mime-db [ unclip '[ [ _ ] dip set ] each ] each
+ ] H{ } make-assoc
+ nonstandard-mime-types assoc-union ;
+
+: mime-type ( filename -- mime-type )
+ file-extension mime-types at "application/octet-stream" or ;
\r
: go-back/forward ( history to from -- )\r
[ 2drop ]\r
- [ >r dupd (add-history) r> pop swap set-model ] if-empty ;\r
+ [ [ dupd (add-history) ] dip pop swap set-model ] if-empty ;\r
\r
: go-back ( history -- )\r
dup [ forward>> ] [ back>> ] bi go-back/forward ;\r
] if ;
: ((change-model)) ( model quot -- newvalue model )
- over >r >r value>> r> call r> ; inline
+ over [ [ value>> ] dip call ] dip ; inline
: change-model ( model quot -- )
((change-model)) set-model ; inline
\r
TUPLE: range < compose ;\r
\r
-: <range> ( value min max page -- range )\r
+: <range> ( value page min max -- range )\r
4array [ <model> ] map range new-compose ;\r
\r
: range-model ( range -- model ) dependencies>> first ;\r
: (parse-multiline-string) ( start-index end-text -- end-index )
lexer get line-text>> [
2dup start
- [ rot dupd >r >r swap subseq % r> r> length + ] [
+ [ rot dupd [ swap subseq % ] 2dip length + ] [
rot tail % "\n" % 0
lexer get next-line swap (parse-multiline-string)
] if*
--- /dev/null
+USING: nibble-arrays tools.test sequences kernel math ;
+IN: nibble-arrays.tests
+
+[ t ] [ 16 dup >nibble-array sequence= ] unit-test
+[ N{ 4 2 1 3 } ] [ N{ 3 1 2 4 } reverse ] unit-test
+[ N{ 1 4 9 0 9 4 } ] [ N{ 1 2 3 4 5 6 } [ sq ] map ] unit-test
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: math kernel sequences sequences.private byte-arrays
+alien.c-types prettyprint.custom parser accessors ;
+IN: nibble-arrays
+
+TUPLE: nibble-array
+{ length array-capacity read-only }
+{ underlying byte-array read-only } ;
+
+<PRIVATE
+
+: nibble BIN: 1111 ; inline
+
+: nibbles>bytes 1 + 2/ ; inline
+
+: byte/nibble ( n -- shift n' )
+ [ 1 bitand 2 shift ] [ -1 shift ] bi ; inline
+
+: get-nibble ( n byte -- nibble )
+ swap neg shift nibble bitand ; inline
+
+: set-nibble ( value n byte -- byte' )
+ nibble pick shift bitnot bitand -rot shift bitor ; inline
+
+: nibble@ ( n nibble-array -- shift n' byte-array )
+ [ >fixnum byte/nibble ] [ underlying>> ] bi* ; inline
+
+PRIVATE>
+
+: <nibble-array> ( n -- nibble-array )
+ dup nibbles>bytes <byte-array> nibble-array boa ; inline
+
+M: nibble-array length length>> ;
+
+M: nibble-array nth-unsafe
+ nibble@ nth-unsafe get-nibble ;
+
+M: nibble-array set-nth-unsafe
+ nibble@ [ nth-unsafe set-nibble ] 2keep set-nth-unsafe ;
+
+M: nibble-array clone
+ [ length>> ] [ underlying>> clone ] bi nibble-array boa ;
+
+: >nibble-array ( seq -- nibble-array )
+ T{ nibble-array } clone-like ; inline
+
+M: nibble-array like
+ drop dup nibble-array? [ >nibble-array ] unless ;
+
+M: nibble-array new-sequence drop <nibble-array> ;
+
+M: nibble-array equal?
+ over nibble-array? [ sequence= ] [ 2drop f ] if ;
+
+M: nibble-array resize
+ [ drop ] [
+ [ nibbles>bytes ] [ underlying>> ] bi*
+ resize-byte-array
+ ] 2bi
+ nibble-array boa ;
+
+M: nibble-array byte-length length nibbles>bytes ;
+
+: N{ \ } [ >nibble-array ] parse-literal ; parsing
+
+INSTANCE: nibble-array sequence
+
+M: nibble-array pprint-delims drop \ N{ \ } ;
+M: nibble-array >pprint-sequence ;
+M: nibble-array pprint* pprint-object ;
: n, ( obj n -- ) get-building-seq push ;
: n% ( seq n -- ) get-building-seq push-all ;
-: n# ( num n -- ) >r number>string r> n% ;
+: n# ( num n -- ) [ number>string ] dip n% ;
: 0, ( obj -- ) 0 n, ;
: 0% ( seq -- ) 0 n% ;
-USING: alien alien.syntax combinators kernel parser sequences
-system words namespaces hashtables init math arrays assocs
-continuations lexer ;
+USING: alien alien.syntax alien.parser combinators
+kernel parser sequences system words namespaces hashtables init
+math arrays assocs continuations lexer fry locals ;
IN: opengl.gl.extensions
ERROR: unknown-gl-platform ;
: gl-function-pointer ( names n -- funptr )
gl-function-context 2array dup +gl-function-pointers+ get-global at
[ 2nip ] [
- >r [ gl-function-address ] map [ ] find nip
- dup [ "OpenGL function not available" throw ] unless
- dup r>
+ [
+ [ gl-function-address ] map [ ] find nip
+ dup [ "OpenGL function not available" throw ] unless
+ dup
+ ] dip
+gl-function-pointers+ get-global set-at
] if* ;
+: indirect-quot ( function-ptr-quot return types abi -- quot )
+ '[ @ _ _ _ alien-indirect ] ;
+
+:: define-indirect ( abi return function-ptr-quot function-name parameters -- )
+ function-name create-in dup reset-generic
+ function-ptr-quot return
+ parameters return parse-arglist [ abi indirect-quot ] dip
+ define-declared ;
+
: GL-FUNCTION:
gl-function-calling-convention
scan
namespaces math.vectors math.constants math.functions
math.parser opengl.gl opengl.glu combinators arrays sequences
splitting words byte-arrays assocs colors accessors
-generalizations locals memoize ;
+generalizations locals specialized-arrays.float
+specialized-arrays.uint ;
IN: opengl
: color>raw ( object -- r g b a )
[ glDisableClientState ] each ; inline
MACRO: all-enabled ( seq quot -- )
- >r words>values r> [ (all-enabled) ] 2curry ;
+ [ words>values ] dip [ (all-enabled) ] 2curry ;
MACRO: all-enabled-client-state ( seq quot -- )
- >r words>values r> [ (all-enabled-client-state) ] 2curry ;
+ [ words>values ] dip [ (all-enabled-client-state) ] 2curry ;
: do-matrix ( mode quot -- )
swap [ glMatrixMode glPushMatrix call ] keep
glMatrixMode glPopMatrix ; inline
: gl-material ( face pname params -- )
- >c-float-array glMaterialfv ;
+ float-array{ } like underlying>> glMaterialfv ;
: gl-vertex-pointer ( seq -- )
- [ 2 GL_FLOAT 0 ] dip glVertexPointer ; inline
+ [ 2 GL_FLOAT 0 ] dip underlying>> glVertexPointer ; inline
: gl-color-pointer ( seq -- )
- [ 4 GL_FLOAT 0 ] dip glColorPointer ; inline
+ [ 4 GL_FLOAT 0 ] dip underlying>> glColorPointer ; inline
: gl-texture-coord-pointer ( seq -- )
- [ 2 GL_FLOAT 0 ] dip glTexCoordPointer ; inline
+ [ 2 GL_FLOAT 0 ] dip underlying>> glTexCoordPointer ; inline
: line-vertices ( a b -- )
- append >c-float-array gl-vertex-pointer ;
+ [ first2 [ 0.5 + ] bi@ ] bi@ 4 float-array{ } nsequence
+ gl-vertex-pointer ;
: gl-line ( a b -- )
line-vertices GL_LINES 0 2 glDrawArrays ;
: (rect-vertices) ( dim -- vertices )
+ #! We use GL_LINE_STRIP with a duplicated first vertex
+ #! instead of GL_LINE_LOOP to work around a bug in Apple's
+ #! X3100 driver.
{
[ drop 0.5 0.5 ]
- [ first 0.5 - 0.5 ]
- [ [ first 0.5 - ] [ second 0.5 - ] bi ]
- [ second 0.5 - 0.5 swap ]
- } cleave 8 narray >c-float-array ;
+ [ first 0.3 - 0.5 ]
+ [ [ first 0.3 - ] [ second 0.3 - ] bi ]
+ [ second 0.3 - 0.5 swap ]
+ [ drop 0.5 0.5 ]
+ } cleave 10 float-array{ } nsequence ;
: rect-vertices ( dim -- )
(rect-vertices) gl-vertex-pointer ;
: (gl-rect) ( -- )
- GL_LINE_LOOP 0 4 glDrawArrays ;
+ GL_LINE_STRIP 0 5 glDrawArrays ;
: gl-rect ( dim -- )
rect-vertices (gl-rect) ;
[ first 0 ]
[ first2 ]
[ second 0 swap ]
- } cleave 8 narray >c-float-array ;
+ } cleave 8 float-array{ } nsequence ;
: fill-rect-vertices ( dim -- )
(fill-rect-vertices) gl-vertex-pointer ;
: circle-points ( loc dim steps -- points )
circle-steps unit-circle adjust-points scale-points ;
+: close-path ( points -- points' )
+ dup first suffix ;
+
: circle-vertices ( loc dim steps -- vertices )
- circle-points concat >c-float-array ;
+ #! We use GL_LINE_STRIP with a duplicated first vertex
+ #! instead of GL_LINE_LOOP to work around a bug in Apple's
+ #! X3100 driver.
+ circle-points close-path concat >float-array ;
+
+: fill-circle-vertices ( loc dim steps -- vertices )
+ circle-points concat >float-array ;
: (gen-gl-object) ( quot -- id )
- >r 1 0 <uint> r> keep *uint ; inline
+ [ 1 0 <uint> ] dip keep *uint ; inline
: gen-texture ( -- id )
[ glGenTextures ] (gen-gl-object) ;
[ glGenBuffers ] (gen-gl-object) ;
: (delete-gl-object) ( id quot -- )
- >r 1 swap <uint> r> call ; inline
+ [ 1 swap <uint> ] dip call ; inline
: delete-texture ( id -- )
[ glDeleteTextures ] (delete-gl-object) ;
: <gl-buffer> ( target data hint -- id )
pick gen-gl-buffer [ [
- >r dup byte-length swap r> glBufferData
+ [ dup byte-length swap ] dip glBufferData
] with-gl-buffer ] keep ;
: buffer-offset ( int -- alien )
glActiveTexture swap glBindTexture gl-error ;
: (set-draw-buffers) ( buffers -- )
- dup length swap >c-uint-array glDrawBuffers ;
+ [ length ] [ >uint-array underlying>> ] bi glDrawBuffers ;
MACRO: set-draw-buffers ( buffers -- )
words>values [ (set-draw-buffers) ] curry ;
gen-texture [
GL_TEXTURE_BIT [
GL_TEXTURE_2D swap glBindTexture
- >r >r GL_TEXTURE_2D 0 GL_RGBA r>
- sprite-size2 0 GL_LUMINANCE_ALPHA
- GL_UNSIGNED_BYTE r> glTexImage2D
+ [
+ [ GL_TEXTURE_2D 0 GL_RGBA ] dip
+ sprite-size2 0 GL_LUMINANCE_ALPHA
+ GL_UNSIGNED_BYTE
+ ] dip glTexImage2D
] do-attribs
] keep ;
: gl-translate ( point -- ) first2 0.0 glTranslated ;
-MEMO: (rect-texture-coords) ( -- seq )
- { 0 0 1 0 1 1 0 1 } >c-float-array ;
-
: rect-texture-coords ( -- )
- (rect-texture-coords) gl-texture-coord-pointer ;
+ float-array{ 0 0 1 0 1 1 0 1 } gl-texture-coord-pointer ;
: draw-sprite ( sprite -- )
GL_TEXTURE_COORD_ARRAY [
[ nip [ free-sprite ] when* ] assoc-each ;
: with-translation ( loc quot -- )
- GL_MODELVIEW [ >r gl-translate r> call ] do-matrix ; inline
+ GL_MODELVIEW [ [ gl-translate ] dip call ] do-matrix ; inline
: fix-coordinates ( point1 point2 -- x1 y2 x2 y2 )
[ first2 [ >fixnum ] bi@ ] bi@ ;
FUNCTION: void* BIO_f_ssl ( ) ;
: SSL_CTX_set_tmp_rsa ( ctx rsa -- n )
- >r SSL_CTRL_SET_TMP_RSA 0 r> SSL_CTX_ctrl ;
+ [ SSL_CTRL_SET_TMP_RSA 0 ] dip SSL_CTX_ctrl ;
: SSL_CTX_set_tmp_dh ( ctx dh -- n )
- >r SSL_CTRL_SET_TMP_DH 0 r> SSL_CTX_ctrl ;
+ [ SSL_CTRL_SET_TMP_DH 0 ] dip SSL_CTX_ctrl ;
: SSL_CTX_set_session_cache_mode ( ctx mode -- n )
- >r SSL_CTRL_SET_SESS_CACHE_MODE r> f SSL_CTX_ctrl ;
+ [ SSL_CTRL_SET_SESS_CACHE_MODE ] dip f SSL_CTX_ctrl ;
: SSL_SESS_CACHE_OFF HEX: 0000 ; inline
: SSL_SESS_CACHE_CLIENT HEX: 0001 ; inline
! Copyright (C) 2007, 2008, Slava Pestov, Elie CHAFTARI.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors byte-arrays kernel debugger sequences namespaces math
-math.order combinators init alien alien.c-types alien.strings libc
-continuations destructors debugger summary splitting assocs
-random math.parser locals unicode.case
-openssl.libcrypto openssl.libssl
-io.backend io.ports io.files io.encodings.8-bit io.sockets.secure
-io.timeouts ;
+USING: init kernel namespaces openssl.libcrypto openssl.libssl
+sequences ;
IN: openssl
! This code is based on http://www.rtfm.com/openssl-examples/
SINGLETON: openssl
-GENERIC: ssl-method ( symbol -- method )
-
-M: SSLv2 ssl-method drop SSLv2_client_method ;
-M: SSLv23 ssl-method drop SSLv23_method ;
-M: SSLv3 ssl-method drop SSLv3_method ;
-M: TLSv1 ssl-method drop TLSv1_method ;
-
: (ssl-error-string) ( n -- string )
ERR_clear_error f ERR_error_string ;
] unless ;
[ f ssl-initialized? set-global ] "openssl" add-init-hook
-
-TUPLE: openssl-context < secure-context aliens sessions ;
-
-: set-session-cache ( ctx -- )
- handle>>
- [ SSL_SESS_CACHE_BOTH SSL_CTX_set_session_cache_mode ssl-error ]
- [ 32 random-bits >hex dup length SSL_CTX_set_session_id_context ssl-error ]
- bi ;
-
-: load-certificate-chain ( ctx -- )
- dup config>> key-file>> [
- [ handle>> ] [ config>> key-file>> (normalize-path) ] bi
- SSL_CTX_use_certificate_chain_file
- ssl-error
- ] [ drop ] if ;
-
-: password-callback ( -- alien )
- "int" { "void*" "int" "bool" "void*" } "cdecl"
- [| buf size rwflag password! |
- password [ B{ 0 } password! ] unless
-
- [let | len [ password strlen ] |
- buf password len 1+ size min memcpy
- len
- ]
- ] alien-callback ;
-
-: default-pasword ( ctx -- alien )
- [ config>> password>> latin1 malloc-string ] [ aliens>> ] bi
- [ push ] [ drop ] 2bi ;
-
-: set-default-password ( ctx -- )
- [ handle>> password-callback SSL_CTX_set_default_passwd_cb ]
- [
- [ handle>> ] [ default-pasword ] bi
- SSL_CTX_set_default_passwd_cb_userdata
- ] bi ;
-
-: use-private-key-file ( ctx -- )
- dup config>> key-file>> [
- [ handle>> ] [ config>> key-file>> (normalize-path) ] bi
- SSL_FILETYPE_PEM SSL_CTX_use_PrivateKey_file
- ssl-error
- ] [ drop ] if ;
-
-: load-verify-locations ( ctx -- )
- dup config>> [ ca-file>> ] [ ca-path>> ] bi or [
- [ handle>> ]
- [
- config>>
- [ ca-file>> dup [ (normalize-path) ] when ]
- [ ca-path>> dup [ (normalize-path) ] when ] bi
- ] bi
- SSL_CTX_load_verify_locations
- ] [ handle>> SSL_CTX_set_default_verify_paths ] if ssl-error ;
-
-: set-verify-depth ( ctx -- )
- dup config>> verify-depth>> [
- [ handle>> ] [ config>> verify-depth>> ] bi
- SSL_CTX_set_verify_depth
- ] [ drop ] if ;
-
-TUPLE: bio handle disposed ;
-
-: <bio> ( handle -- bio ) f bio boa ;
-
-M: bio dispose* handle>> BIO_free ssl-error ;
-
-: <file-bio> ( path -- bio )
- normalize-path "r" BIO_new_file dup ssl-error <bio> ;
-
-: load-dh-params ( ctx -- )
- dup config>> dh-file>> [
- [ handle>> ] [ config>> dh-file>> ] bi <file-bio> &dispose
- handle>> f f f PEM_read_bio_DHparams dup ssl-error
- SSL_CTX_set_tmp_dh ssl-error
- ] [ drop ] if ;
-
-TUPLE: rsa handle disposed ;
-
-: <rsa> ( handle -- rsa ) f rsa boa ;
-
-M: rsa dispose* handle>> RSA_free ;
-
-: generate-eph-rsa-key ( ctx -- )
- [ handle>> ]
- [
- config>> ephemeral-key-bits>> RSA_F4 f f RSA_generate_key
- dup ssl-error <rsa> &dispose handle>>
- ] bi
- SSL_CTX_set_tmp_rsa ssl-error ;
-
-: <openssl-context> ( config ctx -- context )
- openssl-context new
- swap >>handle
- swap >>config
- V{ } clone >>aliens
- H{ } clone >>sessions ;
-
-M: openssl <secure-context> ( config -- context )
- maybe-init-ssl
- [
- dup method>> ssl-method SSL_CTX_new
- dup ssl-error <openssl-context> |dispose
- {
- [ set-session-cache ]
- [ load-certificate-chain ]
- [ set-default-password ]
- [ use-private-key-file ]
- [ load-verify-locations ]
- [ set-verify-depth ]
- [ load-dh-params ]
- [ generate-eph-rsa-key ]
- [ ]
- } cleave
- ] with-destructors ;
-
-M: openssl-context dispose*
- [ aliens>> [ free ] each ]
- [ sessions>> values [ SSL_SESSION_free ] each ]
- [ handle>> SSL_CTX_free ]
- tri ;
-
-TUPLE: ssl-handle file handle connected disposed ;
-
-SYMBOL: default-secure-context
-
-: context-expired? ( context -- ? )
- dup [ handle>> expired? ] [ drop t ] if ;
-
-: current-secure-context ( -- ctx )
- secure-context get [
- default-secure-context get dup context-expired? [
- drop
- <secure-config> <secure-context> default-secure-context set-global
- current-secure-context
- ] when
- ] unless* ;
-
-: <ssl-handle> ( fd -- ssl )
- current-secure-context handle>> SSL_new dup ssl-error
- f f ssl-handle boa ;
-
-M: ssl-handle dispose*
- [ handle>> SSL_free ] [ file>> dispose ] bi ;
-
-: check-verify-result ( ssl-handle -- )
- SSL_get_verify_result dup X509_V_OK =
- [ drop ] [ verify-message certificate-verify-error ] if ;
-
-: common-name ( certificate -- host )
- X509_get_subject_name
- NID_commonName 256 <byte-array>
- [ 256 X509_NAME_get_text_by_NID ] keep
- swap -1 = [ drop f ] [ latin1 alien>string ] if ;
-
-: common-names-match? ( expected actual -- ? )
- [ >lower ] bi@ "*." ?head [ tail? ] [ = ] if ;
-
-: check-common-name ( host ssl-handle -- )
- SSL_get_peer_certificate common-name
- 2dup common-names-match?
- [ 2drop ] [ common-name-verify-error ] if ;
-
-M: openssl check-certificate ( host ssl -- )
- current-secure-context config>> verify>> [
- handle>>
- [ nip check-verify-result ]
- [ check-common-name ]
- 2bi
- ] [ 2drop ] if ;
-
-: get-session ( addrspec -- session/f )
- current-secure-context sessions>> at
- dup expired? [ drop f ] when ;
-
-: save-session ( session addrspec -- )
- current-secure-context sessions>> set-at ;
-
-openssl secure-socket-backend set-global
--- /dev/null
+USING: io kernel accessors math.parser sequences prettyprint
+debugger peg ;
+IN: peg.debugger
+
+M: parse-error error.
+ "Peg parsing error at character position " write dup position>> number>string write
+ "." print "Expected " write messages>> [ " or " write ] [ write ] interleave nl ;
+
+M: parse-failed error.
+ "The " write dup word>> pprint " word could not parse the following input:" print nl
+ input>> . ;
+
continuations peg peg.parsers unicode.categories multiline\r
splitting accessors effects sequences.deep peg.search\r
combinators.short-circuit lexer io.streams.string stack-checker\r
-io prettyprint combinators parser ;\r
+io combinators parser ;\r
IN: peg.ebnf\r
\r
: rule ( name word -- parser )\r
M: object build-locals ( code ast -- )\r
drop ;\r
\r
+ERROR: bad-effect quot effect ;\r
+\r
: check-action-effect ( quot -- quot )\r
dup infer {\r
{ [ dup (( a -- b )) effect<= ] [ drop ] }\r
{ [ dup (( -- b )) effect<= ] [ drop [ drop ] prepose ] }\r
- [\r
- [ \r
- "Bad effect: " write effect>string write \r
- " for quotation " write pprint\r
- ] with-string-writer throw\r
- ]\r
+ [ bad-effect ]\r
} cond ;\r
\r
M: ebnf-action (transform) ( ast -- parser )\r
! Copyright (C) 2007, 2008 Chris Double, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences strings namespaces make math assocs
-shuffle vectors arrays math.parser accessors unicode.categories
+vectors arrays math.parser accessors unicode.categories
sequences.deep peg peg.private peg.search math.ranges words ;
IN: peg.parsers
: 1token ( ch -- parser ) 1string token ;
: (list-of) ( items separator repeat1? -- parser )
- >r over 2seq r> [ repeat1 ] [ repeat0 ] if [ concat ] action 2seq
+ [ over 2seq ] dip [ repeat1 ] [ repeat0 ] if [ concat ] action 2seq
[ unclip 1vector swap first append ] action ;
: list-of ( items separator -- parser )
[ flatten-vectors ] action ;
: from-m-to-n ( parser m n -- parser' )
- >r [ exactly-n ] 2keep r> swap - at-most-n 2seq
+ [ [ exactly-n ] 2keep ] dip swap - at-most-n 2seq
[ flatten-vectors ] action ;
: pack ( begin body end -- parser )
- >r >r hide r> r> hide 3seq [ first ] action ;
+ [ hide ] 2dip hide 3seq [ first ] action ;
: surrounded-by ( parser begin end -- parser' )
[ token ] bi@ swapd pack ;
! Copyright (C) 2007, 2008 Chris Double.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences strings fry namespaces make math assocs
-shuffle debugger io vectors arrays math.parser math.order
-vectors combinators classes sets unicode.categories
-compiler.units parser words quotations effects memoize accessors
-locals effects splitting combinators.short-circuit
-combinators.short-circuit.smart generalizations ;
+io vectors arrays math.parser math.order vectors combinators
+classes sets unicode.categories compiler.units parser words
+quotations effects memoize accessors locals effects splitting
+combinators.short-circuit generalizations ;
IN: peg
-USE: prettyprint
-
TUPLE: parse-result remaining ast ;
TUPLE: parse-error position messages ;
TUPLE: parser peg compiled id ;
C: <parse-result> parse-result
C: <parse-error> parse-error
-M: parse-error error.
- "Peg parsing error at character position " write dup position>> number>string write
- "." print "Expected " write messages>> [ " or " write ] [ write ] interleave nl ;
-
SYMBOL: error-stack
: (merge-errors) ( a b -- c )
pos set dup involved-set>> clone >>eval-set drop ;
: (grow-lr) ( h p r: ( -- result ) m -- )
- >r >r [ setup-growth ] 2keep r> r>
- >r dup eval-rule r> swap
+ [ [ setup-growth ] 2keep ] 2dip
+ [ dup eval-rule ] dip swap
dup pick stop-growth? [
5 ndrop
] [
] if ; inline recursive
: grow-lr ( h p r m -- ast )
- >r >r [ heads set-at ] 2keep r> r>
- pick over >r >r (grow-lr) r> r>
+ [ [ heads set-at ] 2keep ] 2dip
+ pick over [ (grow-lr) ] 2dip
swap heads delete-at
dup pos>> pos set ans>>
; inline
nip
] if ;
-USE: prettyprint
-
: apply-rule ( r p -- ast )
! 2dup [ rule-id ] dip 2array "apply-rule: " write .
2dup recall [
: parser-body ( parser -- quot )
#! Return the body of the word that is the compiled version
#! of the parser.
- gensym 2dup swap peg>> (compile) 0 1 <effect> define-declared swap dupd id>> "peg-id" set-word-prop
+ gensym 2dup swap peg>> (compile) (( -- result )) define-declared
+ swap dupd id>> "peg-id" set-word-prop
[ execute-parser ] curry ;
: preset-parser-word ( parser -- parser word )
#! Work through all delayed parsers and recompile their
#! words to have the correct bodies.
delayed get [
- call compile-parser 1quotation 0 1 <effect> define-declared
+ call compile-parser 1quotation (( -- result )) define-declared
] assoc-each ;
: compile ( parser -- word )
[ ?head-slice ] keep swap [
<parse-result> f f add-error
] [
- >r drop pos get "token '" r> append "'" append 1vector add-error f
+ [ drop pos get "token '" ] dip append "'" append 1vector add-error f
] if ;
M: token-parser (compile) ( peg -- quot )
[
parsers>> unclip compile-parser 1quotation [ parse-seq-element ] curry ,
[ compile-parser 1quotation [ merge-errors ] compose [ parse-seq-element ] curry , ] each
- ] { } make , \ && ,
+ ] { } make , \ 1&& ,
] [ ] make ;
TUPLE: choice-parser parsers ;
[
parsers>> [ compile-parser ] map
unclip 1quotation , [ 1quotation [ merge-errors ] compose , ] each
- ] { } make , \ || ,
+ ] { } make , \ 0|| ,
] [ ] make ;
TUPLE: repeat0-parser p1 ;
ERROR: parse-failed input word ;
-M: parse-failed error.
- "The " write dup word>> pprint " word could not parse the following input:" print nl
- input>> . ;
-
: PEG:
(:)
[let | def [ ] word [ ] |
] with-compilation-unit
] over push-all
] ; parsing
+
+USING: vocabs vocabs.loader ;
+
+"debugger" vocab [
+ "peg.debugger" require
+] when
! Based on Clojure's PersistentHashMap by Rich Hickey.
USING: kernel math accessors assocs fry combinators parser
-prettyprint.backend make
+prettyprint.custom make
persistent.assocs
persistent.hashtables.nodes
persistent.hashtables.nodes.empty
! Based on Clojure's PersistentVector by Rich Hickey.
USING: math accessors kernel sequences.private sequences arrays
-combinators combinators.short-circuit parser prettyprint.backend
+combinators combinators.short-circuit parser prettyprint.custom
persistent.sequences ;
IN: persistent.vectors
HELP: present
{ $values { "object" object } { "string" string } }
{ $contract "Outputs a human-readable string from an object." }
-{ $notes "New methods can be defined by user code. Most often, this is done so that the object can be used with various words in the " { $vocab-link "html.components" } " or " { $link "urls" } " vocabularies." } ;
+{ $notes "New methods can be defined by user code. Most often, this is done so that the object can be used with various words in the " { $vocab-link "html.components" } " or " { $vocab-link "urls" } " vocabularies." } ;
ABOUT: "present"
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors math math.parser calendar calendar.format
-strings words kernel effects ;
+USING: accessors math math.parser strings words kernel effects ;
IN: present
GENERIC: present ( object -- string )
M: real present number>string ;
-M: timestamp present timestamp>string ;
-
M: string present ;
M: word present name>> ;
USING: help.markup help.syntax io kernel
-prettyprint.config prettyprint.sections words strings ;
+prettyprint.config prettyprint.sections prettyprint.custom
+words strings ;
IN: prettyprint.backend
ABOUT: "prettyprint-extension"
-HELP: pprint*
-{ $values { "obj" "an object" } }
-{ $contract "Adds sections to the current block corresponding to the prettyprinted representation of the object." }
-$prettyprinting-note ;
-
HELP: pprint-word
{ $values { "word" "a word" } }
{ $description "Adds a text section for the word. Unlike the " { $link word } " method of " { $link pprint* } ", this does not add a " { $link POSTPONE: POSTPONE: } " prefix to parsing words." }
! Copyright (C) 2003, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays byte-arrays byte-vectors generic
-hashtables io assocs kernel math namespaces make sequences
-strings sbufs io.styles vectors words prettyprint.config
+USING: accessors arrays byte-arrays generic hashtables io assocs
+kernel math namespaces make sequences strings sbufs io.styles
+vectors words prettyprint.config prettyprint.custom
prettyprint.sections quotations io io.files math.parser effects
classes.tuple math.order classes.tuple.private classes
combinators colors ;
IN: prettyprint.backend
-GENERIC: pprint* ( obj -- )
-
-M: effect pprint* effect>string "(" swap ")" 3append text ;
+M: effect pprint* effect>string "(" ")" surround text ;
: ?effect-height ( word -- n )
stack-effect [ effect-height ] [ 0 ] if* ;
: ?end-group ( word -- )
?effect-height 0 < [ end-group ] when ;
-\ >r hard "break-before" set-word-prop
-\ r> hard "break-after" set-word-prop
-
! Atoms
: word-style ( word -- style )
dup "word-style" word-prop >hashtable [
] H{ } make-assoc ;
: unparse-string ( str prefix suffix -- str )
- [ >r % do-string-limit [ unparse-ch ] each r> % ] "" make ;
+ [ [ % do-string-limit [ unparse-ch ] each ] dip % ] "" make ;
: pprint-string ( obj str prefix suffix -- )
unparse-string swap string-style styled-text ;
: do-length-limit ( seq -- trimmed n/f )
length-limit get dup [
over length over [-]
- dup zero? [ 2drop f ] [ >r head r> ] if
+ dup zero? [ 2drop f ] [ [ head ] dip ] if
] when ;
: pprint-elements ( seq -- )
- do-length-limit >r
- [ pprint* ] each
- r> [ "~" swap number>string " more~" 3append text ] when* ;
-
-GENERIC: pprint-delims ( obj -- start end )
+ do-length-limit
+ [ [ pprint* ] each ] dip
+ [ "~" swap number>string " more~" 3append text ] when* ;
M: quotation pprint-delims drop \ [ \ ] ;
M: curry pprint-delims drop \ [ \ ] ;
M: compose pprint-delims drop \ [ \ ] ;
M: array pprint-delims drop \ { \ } ;
M: byte-array pprint-delims drop \ B{ \ } ;
-M: byte-vector pprint-delims drop \ BV{ \ } ;
M: vector pprint-delims drop \ V{ \ } ;
M: hashtable pprint-delims drop \ H{ \ } ;
M: tuple pprint-delims drop \ T{ \ } ;
M: wrapper pprint-delims drop \ W{ \ } ;
M: callstack pprint-delims drop \ CS{ \ } ;
-GENERIC: >pprint-sequence ( obj -- seq )
-
M: object >pprint-sequence ;
-
M: vector >pprint-sequence ;
-M: byte-vector >pprint-sequence ;
M: curry >pprint-sequence ;
M: compose >pprint-sequence ;
M: hashtable >pprint-sequence >alist ;
[ class ] [ tuple-slots ] bi
[ 1array ] [ [ f 2array ] dip append ] if-empty ;
-GENERIC: pprint-narrow? ( obj -- ? )
-
M: object pprint-narrow? drop f ;
-
M: array pprint-narrow? drop t ;
M: vector pprint-narrow? drop t ;
M: hashtable pprint-narrow? drop t ;
M: tuple pprint-narrow? drop t ;
-: pprint-object ( obj -- )
+M: object pprint-object ( obj -- )
[
<flow
- dup pprint-delims >r pprint-word
- dup pprint-narrow? <inset
- >pprint-sequence pprint-elements
- block> r> pprint-word block>
+ dup pprint-delims [
+ pprint-word
+ dup pprint-narrow? <inset
+ >pprint-sequence pprint-elements
+ block>
+ ] dip pprint-word block>
] check-recursion ;
M: object pprint* pprint-object ;
M: vector pprint* pprint-object ;
-M: byte-vector pprint* pprint-object ;
M: hashtable pprint* pprint-object ;
-
-M: curry pprint*
- dup quot>> callable? [ pprint-object ] [
- "( invalid curry )" swap present-text
- ] if ;
-
-M: compose pprint*
- dup [ first>> callable? ] [ second>> callable? ] bi and
- [ pprint-object ] [
- "( invalid compose )" swap present-text
- ] if ;
+M: curry pprint* pprint-object ;
+M: compose pprint* pprint-object ;
M: wrapper pprint*
dup wrapped>> word? [
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel help.markup help.syntax ;
+IN: prettyprint.custom
+
+HELP: pprint*
+{ $values { "obj" object } }
+{ $contract "Adds sections to the current block corresponding to the prettyprinted representation of the object." }
+$prettyprinting-note ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+IN: prettyprint.custom
+
+GENERIC: pprint* ( obj -- )
+GENERIC: pprint-object ( obj -- )
+GENERIC: pprint-delims ( obj -- start end )
+GENERIC: >pprint-sequence ( obj -- seq )
+GENERIC: pprint-narrow? ( obj -- ? )
-USING: prettyprint.backend prettyprint.config
+USING: prettyprint.backend prettyprint.config prettyprint.custom
prettyprint.sections prettyprint.private help.markup help.syntax
io kernel words definitions quotations strings generic classes ;
IN: prettyprint
"Prettyprinting any stack:"
{ $subsection stack. }
"Prettyprinting any call stack:"
-{ $subsection callstack. } ;
+{ $subsection callstack. }
+"Note that calls to " { $link .s } " can also be included inside words as a debugging aid, however a more convenient way to achieve this is to use the annotation facility. See " { $link "tools.annotations" } "." ;
ARTICLE: "prettyprint-variables" "Prettyprint control variables"
"The following variables affect the " { $link . } " and " { $link pprint } " words if set in the current dynamic scope:"
[ \ method-layout see-methods ] with-string-writer "\n" split
] unit-test
-: retain-stack-test
- {
- "USING: io kernel sequences words ;"
- "IN: prettyprint.tests"
- ": retain-stack-layout ( x -- )"
- " dup stream-readln stream-readln"
- " >r [ define ] map r>"
- " define ;"
- } ;
-
-[ t ] [
- "retain-stack-layout" retain-stack-test check-see
-] unit-test
-
: soft-break-test
{
"USING: kernel math sequences strings ;"
"soft-break-layout" soft-break-test check-see
] unit-test
-: another-retain-layout-test
- {
- "USING: kernel sequences ;"
- "IN: prettyprint.tests"
- ": another-retain-layout ( seq1 seq2 quot -- newseq )"
- " -rot 2dup dupd min-length [ each drop roll ] map"
- " >r 3drop r> ; inline"
- } ;
-
-[ t ] [
- "another-retain-layout" another-retain-layout-test check-see
-] unit-test
-
DEFER: parse-error-file
: another-soft-break-test
"USING: kernel sequences ;"
"IN: prettyprint.tests"
": final-soft-break-layout ( class dim -- view )"
- " >r \"alloc\" send 0 0 r>"
- " first2 <NSRect>"
+ " [ \"alloc\" send 0 0 ] dip first2 <NSRect>"
" <PixelFormat> \"initWithFrame:pixelFormat:\" send"
" dup 1 \"setPostsBoundsChangedNotifications:\" send"
" dup 1 \"setPostsFrameChangedNotifications:\" send ;"
[ 2 break 2 \ + (step-into-execute) . ] (remove-breakpoints)
] unit-test
-[ ] [ 1 \ + curry unparse drop ] unit-test
-
-[ ] [ 1 \ + compose unparse drop ] unit-test
-
GENERIC: generic-see-test-with-f ( obj -- obj )
M: f generic-see-test-with-f ;
[ ] [ \ curry see ] unit-test
[ "POSTPONE: [" ] [ \ [ unparse ] unit-test
+
+TUPLE: started-out-hustlin' ;
+
+GENERIC: ended-up-ballin'
+
+M: started-out-hustlin' ended-up-ballin' ; inline
+
+[ "USING: prettyprint.tests ;\nM: started-out-hustlin' ended-up-ballin' ; inline\n" ] [
+ [ { started-out-hustlin' ended-up-ballin' } see ] with-string-writer
+] unit-test
! See http://factorcode.org/license.txt for BSD license.
USING: arrays generic generic.standard assocs io kernel math
namespaces make sequences strings io.styles io.streams.string
-vectors words prettyprint.backend prettyprint.sections
-prettyprint.config sorting splitting grouping math.parser vocabs
-definitions effects classes.builtin classes.tuple io.files
-classes continuations hashtables classes.mixin classes.union
-classes.intersection classes.predicate classes.singleton
-combinators quotations sets accessors colors ;
+vectors words prettyprint.backend prettyprint.custom
+prettyprint.sections prettyprint.config sorting splitting
+grouping math.parser vocabs definitions effects classes.builtin
+classes.tuple io.files classes continuations hashtables
+classes.mixin classes.union classes.intersection
+classes.predicate classes.singleton combinators quotations sets
+accessors colors parser summary ;
IN: prettyprint
: make-pprint ( obj quot -- block in use )
] with-pprint nl
] unless-empty ;
-: vocabs. ( in use -- )
+: use/in. ( in use -- )
dupd remove [ { "syntax" "scratchpad" } member? not ] filter
use. in. ;
+: vocab-names ( words -- vocabs )
+ dictionary get
+ [ [ words>> eq? nip ] with assoc-find 2drop ] curry map sift ;
+
+: prelude. ( -- )
+ in get use get vocab-names use/in. ;
+
+[
+ nl
+ "Restarts were invoked adding vocabularies to the search path." print
+ "To avoid doing this in the future, add the following USING:" print
+ "and IN: forms at the top of the source file:" print nl
+ prelude.
+ nl
+] print-use-hook set-global
+
: with-use ( obj quot -- )
- make-pprint vocabs. do-pprint ; inline
+ make-pprint use/in. do-pprint ; inline
: with-in ( obj quot -- )
make-pprint drop [ write-in bl ] when* do-pprint ; inline
: remove-breakpoints ( quot pos -- quot' )
over quotation? [
1+ cut [ (remove-breakpoints) ] bi@
- [ -> ] swap 3append
+ [ -> ] glue
] [
drop
] if ;
[ synopsis* ] with-in
] with-string-writer ;
+M: word summary synopsis ;
+
: synopsis-alist ( definitions -- alist )
[ dup synopsis swap ] { } map>assoc ;
block>
] with-use nl ;
+M: method-spec see
+ first2 method see ;
+
GENERIC: see-class* ( word -- )
M: union-class see-class*
: (see-methods) ( generic -- seq )
"methods" word-prop values natural-sort ;
-: see-methods ( word -- )
+: methods ( word -- seq )
[
dup class? [ dup (see-implementors) % ] when
dup generic? [ dup (see-methods) % ] when
drop
- ] { } make prune see-all ;
+ ] { } make prune ;
+
+: see-methods ( word -- )
+ methods see-all ;
: text-fits? ( len -- ? )
margin get dup zero?
- [ 2drop t ] [ >r pprinter get indent>> + r> <= ] if ;
+ [ 2drop t ] [ [ pprinter get indent>> + ] dip <= ] if ;
! break only if position margin 2 / >
SYMBOL: soft
: empty-block? ( block -- ? ) sections>> empty? ;
: if-nonempty ( block quot -- )
- >r dup empty-block? [ drop ] r> if ; inline
+ [ dup empty-block? [ drop ] ] dip if ; inline
: (<block) ( block -- ) pprinter-stack get push ;
HELP: QUALIFIED:
{ $syntax "QUALIFIED: vocab" }
{ $description "Similar to " { $link POSTPONE: USE: } " but loads vocabulary with prefix." }
-{ $examples { $code
- "QUALIFIED: math\n1 2 math:+ ! ==> 3" } } ;
+{ $examples { $example
+ "USING: prettyprint qualified ;"
+ "QUALIFIED: math"
+ "1 2 math:+ ." "3"
+} } ;
HELP: QUALIFIED-WITH:
{ $syntax "QUALIFIED-WITH: vocab word-prefix" }
{ $description "Works like " { $link POSTPONE: QUALIFIED: } " but uses " { $snippet "word-prefix" } " as prefix." }
{ $examples { $code
- "QUALIFIED-WITH: math m\n1 2 m:+ ! ==> 3" } } ;
+ "USING: prettyprint qualified ;"
+ "QUALIFIED-WITH: math m"
+ "1 2 m:+ ."
+ "3"
+} } ;
HELP: FROM:
{ $syntax "FROM: vocab => words ... ;" }
HELP: RENAME:
{ $syntax "RENAME: word vocab => newname " }
{ $description "Imports " { $snippet "word" } " from " { $snippet "vocab" } ", but renamed to " { $snippet "newname" } "." }
-{ $examples { $code
+{ $examples { $example
+ "USING: prettyprint qualified ;"
"RENAME: + math => -"
- "2 3 - ! => 5" } } ;
+ "2 3 - ."
+ "5"
+} } ;
ARTICLE: "qualified" "Qualified word lookup"
"The " { $vocab-link "qualified" } " vocabulary provides a handful of parsing words which give more control over word lookup than is offered by " { $link POSTPONE: USE: } " and " { $link POSTPONE: USING: } "."
! Copyright (C) 2007, 2008 Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences assocs hashtables parser lexer
-vocabs words namespaces vocabs.loader debugger sets fry ;
+vocabs words namespaces vocabs.loader sets fry ;
IN: qualified
: define-qualified ( vocab-name prefix-name -- )
#! Syntax: QUALIFIED-WITH: vocab prefix
scan scan define-qualified ; parsing
-: expect=> ( -- ) scan "=>" assert= ;
-
: partial-vocab ( words vocab -- assoc )
'[ dup _ lookup [ no-word-error ] unless* ]
{ } map>assoc ;
: FROM:
#! Syntax: FROM: vocab => words... ;
- scan dup load-vocab drop expect=>
+ scan dup load-vocab drop "=>" expect
";" parse-tokens swap partial-vocab use get push ; parsing
: partial-vocab-excluding ( words vocab -- assoc )
: EXCLUDE:
#! Syntax: EXCLUDE: vocab => words ... ;
- scan expect=>
+ scan "=>" expect
";" parse-tokens swap partial-vocab-excluding use get push ; parsing
: RENAME:
#! Syntax: RENAME: word vocab => newname
scan scan dup load-vocab drop
dupd lookup [ ] [ no-word-error ] ?if
- expect=>
+ "=>" expect
scan associate use get push ; parsing
100 [ 100 random ] replicate ;
: test-rng ( seed quot -- )
- >r <mersenne-twister> r> with-random ;
+ [ <mersenne-twister> ] dip with-random ;
[ f ] [ 1234 [ randoms randoms = ] test-rng ] unit-test
! See http://factorcode.org/license.txt for BSD license.
! mersenne twister based on
! http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c
-USING: arrays kernel math namespaces sequences system init
-accessors math.ranges random circular math.bitwise
-combinators ;
+USING: kernel math namespaces sequences sequences.private system
+init accessors math.ranges random math.bitwise combinators
+specialized-arrays.uint fry ;
IN: random.mersenne-twister
<PRIVATE
-TUPLE: mersenne-twister seq i ;
+TUPLE: mersenne-twister { seq uint-array } { i fixnum } ;
-: mt-n 624 ; inline
-: mt-m 397 ; inline
-: mt-a HEX: 9908b0df ; inline
+: n 624 ; inline
+: m 397 ; inline
+: a uint-array{ 0 HEX: 9908b0df } ; inline
-: calculate-y ( n seq -- y )
- [ nth 31 mask-bit ]
- [ [ 1+ ] [ nth ] bi* 31 bits ] 2bi bitor ; inline
+: y ( n seq -- y )
+ [ nth-unsafe 31 mask-bit ]
+ [ [ 1+ ] [ nth-unsafe ] bi* 31 bits ] 2bi bitor ; inline
-: (mt-generate) ( n seq -- next-mt )
+: mt[k] ( offset n seq -- )
[
- calculate-y
- [ 2/ ] [ odd? mt-a 0 ? ] bi bitxor
- ] [
- [ mt-m + ] [ nth ] bi*
- ] 2bi bitxor ;
+ [ [ + ] dip nth-unsafe ]
+ [ y [ 2/ ] [ 1 bitand a nth ] bi bitxor ] 2bi
+ bitxor
+ ] 2keep set-nth-unsafe ; inline
: mt-generate ( mt -- )
[
- mt-n swap seq>> [
- [ (mt-generate) ] [ set-nth ] 2bi
- ] curry each
- ] [ 0 >>i drop ] bi ;
+ seq>>
+ [ [ n m - ] dip '[ [ m ] dip _ mt[k] ] each ]
+ [ [ m 1- ] dip '[ [ m n - ] [ n m - + ] bi* _ mt[k] ] each ]
+ bi
+ ] [ 0 >>i drop ] bi ; inline
: init-mt-formula ( i seq -- f(seq[i]) )
- dupd nth dup -30 shift bitxor 1812433253 * + 1+ 32 bits ;
+ dupd nth dup -30 shift bitxor 1812433253 * + 1+ 32 bits ; inline
: init-mt-rest ( seq -- )
- mt-n 1- swap [
- [ init-mt-formula ] [ >r 1+ r> set-nth ] 2bi
- ] curry each ;
+ n 1- swap '[
+ _ [ init-mt-formula ] [ [ 1+ ] dip set-nth ] 2bi
+ ] each ; inline
: init-mt-seq ( seed -- seq )
- 32 bits mt-n 0 <array> <circular>
- [ set-first ] [ init-mt-rest ] [ ] tri ;
+ 32 bits n <uint-array>
+ [ set-first ] [ init-mt-rest ] [ ] tri ; inline
: mt-temper ( y -- yt )
dup -11 shift bitxor
dup -18 shift bitxor ; inline
: next-index ( mt -- i )
- dup i>> dup mt-n < [ nip ] [ drop mt-generate 0 ] if ;
+ dup i>> dup n < [ nip ] [ drop mt-generate 0 ] if ; inline
PRIVATE>
M: mersenne-twister random-32* ( mt -- r )
[ next-index ]
- [ seq>> nth mt-temper ]
+ [ seq>> nth-unsafe mt-temper ]
[ [ 1+ ] change-i drop ] tri ;
USE: init
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors hashtables kernel math state-tables vars vectors ;
+USING: accessors hashtables kernel math vectors ;
IN: regexp.backend
TUPLE: regexp
raw
- { stack vector }
- parse-tree
{ options hashtable }
+ stack
+ parse-tree
nfa-table
dfa-table
minimized-table
+ matchers
{ nfa-traversal-flags hashtable }
{ dfa-traversal-flags hashtable }
{ state integer }
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel math math.order symbols regexp.parser
+USING: accessors kernel math math.order symbols
words regexp.utils unicode.categories combinators.short-circuit ;
IN: regexp.classes
+SINGLETONS: any-char any-char-no-nl
+letter-class LETTER-class Letter-class digit-class
+alpha-class non-newline-blank-class
+ascii-class punctuation-class java-printable-class blank-class
+control-character-class hex-digit-class java-blank-class c-identifier-class
+unmatchable-class terminator-class word-boundary-class ;
+
+SINGLETONS: beginning-of-input beginning-of-line
+end-of-input end-of-line ;
+
+MIXIN: node
+TUPLE: character-class-range from to ; INSTANCE: character-class-range node
+
GENERIC: class-member? ( obj class -- ? )
-M: word class-member? ( obj class -- ? ) 2drop f ;
+M: t class-member? ( obj class -- ? ) 2drop f ;
+
M: integer class-member? ( obj class -- ? ) 2drop f ;
M: character-class-range class-member? ( obj class -- ? )
M: any-char class-member? ( obj class -- ? )
2drop t ;
-
+
+M: any-char-no-nl class-member? ( obj class -- ? )
+ drop CHAR: \n = not ;
+
M: letter-class class-member? ( obj class -- ? )
drop letter? ;
M: digit-class class-member? ( obj class -- ? )
drop digit? ;
+M: c-identifier-class class-member? ( obj class -- ? )
+ drop
+ { [ digit? ] [ Letter? ] [ CHAR: _ = ] } 1|| ;
+
M: alpha-class class-member? ( obj class -- ? )
drop alpha? ;
M: unmatchable-class class-member? ( obj class -- ? )
2drop f ;
+
+M: terminator-class class-member? ( obj class -- ? )
+ drop {
+ [ CHAR: \r = ]
+ [ CHAR: \n = ]
+ [ CHAR: \u000085 = ]
+ [ CHAR: \u002028 = ]
+ [ CHAR: \u002029 = ]
+ } 1|| ;
+
+M: beginning-of-line class-member? ( obj class -- ? )
+ 2drop f ;
+
+M: end-of-line class-member? ( obj class -- ? )
+ 2drop f ;
dupd pop dup pick find-transitions rot
[
[ [ find-closure ] 2keep nip dupd add-todo-state ] 3keep
- >r swapd transition make-transition r> dfa-table>> add-transition
+ [ swapd transition make-transition ] dip
+ dfa-table>> add-transition
] curry with each
new-transitions
] if-empty ;
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs grouping kernel regexp.backend
-locals math namespaces regexp.parser sequences state-tables fry
-quotations math.order math.ranges vectors unicode.categories
-regexp.utils regexp.transition-tables words sets ;
+locals math namespaces regexp.parser sequences fry quotations
+math.order math.ranges vectors unicode.categories regexp.utils
+regexp.transition-tables words sets regexp.classes unicode.case ;
IN: regexp.nfa
SYMBOL: negation-mode
SINGLETON: lookbehind-off INSTANCE: lookbehind-off traversal-flag
SINGLETON: capture-group-on INSTANCE: capture-group-on traversal-flag
SINGLETON: capture-group-off INSTANCE: capture-group-off traversal-flag
+SINGLETON: front-anchor INSTANCE: front-anchor traversal-flag
+SINGLETON: back-anchor INSTANCE: back-anchor traversal-flag
+SINGLETON: word-boundary INSTANCE: word-boundary traversal-flag
+
+: options ( -- obj ) current-regexp get options>> ;
+
+: option? ( obj -- ? ) options key? ;
+
+: option-on ( obj -- ) options conjoin ;
+
+: option-off ( obj -- ) options delete-at ;
: next-state ( regexp -- state )
[ state>> ] [ [ 1+ ] change-state drop ] bi ;
M: concatenation nfa-node ( node -- )
seq>>
+ reversed-regexp option? [ <reversed> ] when
[ [ nfa-node ] each ]
[ length 1- [ concatenate-nodes ] times ] bi ;
[ length 1- [ alternate-nodes ] times ] bi ;
M: constant nfa-node ( node -- )
- char>> literal-transition add-simple-entry ;
+ case-insensitive option? [
+ dup char>> [ ch>lower ] [ ch>upper ] bi
+ 2dup = [
+ 2drop
+ char>> literal-transition add-simple-entry
+ ] [
+ [ literal-transition add-simple-entry ] bi@
+ alternate-nodes drop
+ ] if
+ ] [
+ char>> literal-transition add-simple-entry
+ ] if ;
M: epsilon nfa-node ( node -- )
drop eps literal-transition add-simple-entry ;
-M: word nfa-node ( node -- )
+M: word nfa-node ( node -- ) class-transition add-simple-entry ;
+
+M: any-char nfa-node ( node -- )
+ [ dotall option? ] dip any-char-no-nl ?
class-transition add-simple-entry ;
+! M: beginning-of-text nfa-node ( node -- ) ;
+
+M: beginning-of-line nfa-node ( node -- ) class-transition add-simple-entry ;
+
+M: end-of-line nfa-node ( node -- ) class-transition add-simple-entry ;
+
+: choose-letter-class ( node -- node' )
+ case-insensitive option? Letter-class rot ? ;
+
+M: letter-class nfa-node ( node -- )
+ choose-letter-class class-transition add-simple-entry ;
+
+M: LETTER-class nfa-node ( node -- )
+ choose-letter-class class-transition add-simple-entry ;
+
M: character-class-range nfa-node ( node -- )
- class-transition add-simple-entry ;
+ case-insensitive option? [
+ dup [ from>> ] [ to>> ] bi
+ 2dup [ Letter? ] bi@ and [
+ rot drop
+ [ [ ch>lower ] bi@ character-class-range boa ]
+ [ [ ch>upper ] bi@ character-class-range boa ] 2bi
+ [ class-transition add-simple-entry ] bi@
+ alternate-nodes
+ ] [
+ 2drop
+ class-transition add-simple-entry
+ ] if
+ ] [
+ class-transition add-simple-entry
+ ] if ;
M: capture-group nfa-node ( node -- )
eps literal-transition add-simple-entry
M: reluctant-kleene-star nfa-node ( node -- )
term>> <kleene-star> nfa-node ;
-!
-
M: negation nfa-node ( node -- )
negation-mode inc
term>> nfa-node
lookbehind-off add-traversal-flag
2 [ concatenate-nodes ] times ;
+M: option nfa-node ( node -- )
+ [ option>> ] [ on?>> ] bi [ option-on ] [ option-off ] if
+ eps literal-transition add-simple-entry ;
+
: construct-nfa ( regexp -- )
[
reset-regexp
[ ] [ "(?:a)" test-regexp ] unit-test
[ ] [ "(?i:a)" test-regexp ] unit-test
[ ] [ "(?-i:a)" test-regexp ] unit-test
-[ "(?z:a)" test-regexp ] [ bad-option? ] must-fail-with
-[ "(?-z:a)" test-regexp ] [ bad-option? ] must-fail-with
+[ "(?z:a)" test-regexp ] [ unknown-regexp-option? ] must-fail-with
+[ "(?-z:a)" test-regexp ] [ unknown-regexp-option? ] must-fail-with
[ ] [ "(?=a)" test-regexp ] unit-test
kernel math math.parser namespaces qualified sets
quotations sequences splitting symbols vectors math.order
unicode.categories strings regexp.backend regexp.utils
-unicode.case words ;
+unicode.case words locals regexp.classes ;
IN: regexp.parser
FROM: math.ranges => [a,b] ;
-MIXIN: node
TUPLE: concatenation seq ; INSTANCE: concatenation node
TUPLE: alternation seq ; INSTANCE: alternation node
TUPLE: kleene-star term ; INSTANCE: kleene-star node
TUPLE: comment-group term ; INSTANCE: comment-group node
INSTANCE: comment-group parentheses-group
-TUPLE: character-class-range from to ; INSTANCE: character-class-range node
SINGLETON: epsilon INSTANCE: epsilon node
-SINGLETON: any-char INSTANCE: any-char node
-SINGLETON: front-anchor INSTANCE: front-anchor node
-SINGLETON: back-anchor INSTANCE: back-anchor node
-
-TUPLE: option-on option ; INSTANCE: option-on node
-TUPLE: option-off option ; INSTANCE: option-off node
-SINGLETONS: unix-lines dotall multiline comments case-insensitive unicode-case reversed-regexp ;
-
-SINGLETONS: letter-class LETTER-class Letter-class digit-class
-alpha-class non-newline-blank-class
-ascii-class punctuation-class java-printable-class blank-class
-control-character-class hex-digit-class java-blank-class c-identifier-class
-unmatchable-class ;
-
-SINGLETONS: beginning-of-group end-of-group
-beginning-of-character-class end-of-character-class
+
+TUPLE: option option on? ; INSTANCE: option node
+
+SINGLETONS: unix-lines dotall multiline comments case-insensitive
+unicode-case reversed-regexp ;
+
+SINGLETONS: beginning-of-character-class end-of-character-class
left-parenthesis pipe caret dash ;
-: get-option ( option -- ? ) current-regexp get options>> at ;
-: get-unix-lines ( -- ? ) unix-lines get-option ;
-: get-dotall ( -- ? ) dotall get-option ;
-: get-multiline ( -- ? ) multiline get-option ;
-: get-comments ( -- ? ) comments get-option ;
-: get-case-insensitive ( -- ? ) case-insensitive get-option ;
-: get-unicode-case ( -- ? ) unicode-case get-option ;
-: get-reversed-regexp ( -- ? ) reversed-regexp get-option ;
+: push1 ( obj -- ) input-stream get stream>> push ;
+: peek1 ( -- obj ) input-stream get stream>> [ f ] [ peek ] if-empty ;
+: pop3 ( seq -- obj1 obj2 obj3 ) [ pop ] [ pop ] [ pop ] tri spin ;
+: drop1 ( -- ) read1 drop ;
+
+: stack ( -- obj ) current-regexp get stack>> ;
+: change-whole-stack ( quot -- )
+ current-regexp get
+ [ stack>> swap call ] keep (>>stack) ; inline
+: push-stack ( obj -- ) stack push ;
+: pop-stack ( -- obj ) stack pop ;
+: cut-out ( vector n -- vector' vector ) cut rest ;
+ERROR: cut-stack-error ;
+: cut-stack ( obj vector -- vector' vector )
+ tuck last-index [ cut-stack-error ] unless* cut-out swap ;
: <possessive-kleene-star> ( obj -- kleene ) possessive-kleene-star boa ;
: <reluctant-kleene-star> ( obj -- kleene ) reluctant-kleene-star boa ;
: <negation> ( obj -- negation ) negation boa ;
: <concatenation> ( seq -- concatenation )
- >vector get-reversed-regexp [ reverse ] when
- [ epsilon ] [ concatenation boa ] if-empty ;
+ >vector [ epsilon ] [ concatenation boa ] if-empty ;
: <alternation> ( seq -- alternation ) >vector alternation boa ;
: <capture-group> ( obj -- capture-group ) capture-group boa ;
: <kleene-star> ( obj -- kleene-star ) kleene-star boa ;
-: <constant> ( obj -- constant )
- dup Letter? get-case-insensitive and [
- [ ch>lower constant boa ]
- [ ch>upper constant boa ] bi 2array <alternation>
- ] [
- constant boa
- ] if ;
+: <constant> ( obj -- constant ) constant boa ;
: first|concatenation ( seq -- first/concatenation )
dup length 1 = [ first ] [ <concatenation> ] if ;
dup length 1 = [ first ] [ <alternation> ] if ;
: <character-class-range> ( from to -- obj )
- 2dup [ Letter? ] bi@ or get-case-insensitive and [
- [ [ ch>lower ] bi@ character-class-range boa ]
- [ [ ch>upper ] bi@ character-class-range boa ] 2bi
- 2array [ [ from>> ] [ to>> ] bi < ] filter
- [ unmatchable-class ] [ first|alternation ] if-empty
- ] [
- 2dup <
- [ character-class-range boa ] [ 2drop unmatchable-class ] if
- ] if ;
+ 2dup <
+ [ character-class-range boa ] [ 2drop unmatchable-class ] if ;
ERROR: unmatched-parentheses ;
-ERROR: bad-option ch ;
+ERROR: unknown-regexp-option option ;
-: option ( ch -- singleton )
+: ch>option ( ch -- singleton )
{
{ CHAR: i [ case-insensitive ] }
{ CHAR: d [ unix-lines ] }
{ CHAR: s [ dotall ] }
{ CHAR: u [ unicode-case ] }
{ CHAR: x [ comments ] }
- [ bad-option ]
+ [ unknown-regexp-option ]
+ } case ;
+
+: option>ch ( option -- string )
+ {
+ { case-insensitive [ CHAR: i ] }
+ { multiline [ CHAR: m ] }
+ { reversed-regexp [ CHAR: r ] }
+ { dotall [ CHAR: s ] }
+ [ unknown-regexp-option ]
} case ;
-: option-on ( option -- ) current-regexp get options>> conjoin ;
-: option-off ( option -- ) current-regexp get options>> delete-at ;
+: toggle-option ( ch ? -- )
+ [ ch>option ] dip option boa push-stack ;
-: toggle-option ( ch ? -- ) [ option ] dip [ option-on ] [ option-off ] if ;
: (parse-options) ( string ? -- ) [ toggle-option ] curry each ;
: parse-options ( string -- )
DEFER: (parse-regexp)
: nested-parse-regexp ( token ? -- )
[ push-stack (parse-regexp) pop-stack ] dip
- [ <negation> ] when pop-stack boa push-stack ;
+ [ <negation> ] when pop-stack new swap >>term push-stack ;
! non-capturing groups
: (parse-special-group) ( -- )
: handle-left-brace ( -- )
parse-repetition
- >r 2dup [ [ 0 < [ invalid-range ] when ] when* ] bi@ r>
+ [ 2dup [ [ 0 < [ invalid-range ] when ] when* ] bi@ ] dip
[
2dup and [ from-m-to-n ]
[ [ nip at-most-n ] [ at-least-n ] if* ] if
] [ drop 0 max exactly-n ] if ;
-SINGLETON: beginning-of-input
-SINGLETON: end-of-input
-
-: newlines ( -- obj1 obj2 obj3 )
- CHAR: \r <constant>
- CHAR: \n <constant>
- 2dup 2array <concatenation> ;
-
-: beginning-of-line ( -- obj )
- beginning-of-input newlines 4array <alternation> lookbehind boa ;
-
-: end-of-line ( -- obj )
- end-of-input newlines 4array <alternation> lookahead boa ;
-
-: handle-front-anchor ( -- )
- get-multiline beginning-of-line beginning-of-input ? push-stack ;
-
-: handle-back-anchor ( -- )
- get-multiline end-of-line end-of-input ? push-stack ;
+: handle-front-anchor ( -- ) beginning-of-line push-stack ;
+: handle-back-anchor ( -- ) end-of-line push-stack ;
ERROR: bad-character-class obj ;
ERROR: expected-posix-class ;
read1 CHAR: { = [ expected-posix-class ] unless
"}" read-until [ bad-character-class ] unless
{
- { "Lower" [ get-case-insensitive Letter-class letter-class ? ] }
- { "Upper" [ get-case-insensitive Letter-class LETTER-class ? ] }
+ { "Lower" [ letter-class ] }
+ { "Upper" [ LETTER-class ] }
{ "Alpha" [ Letter-class ] }
{ "ASCII" [ ascii-class ] }
{ "Digit" [ digit-class ] }
: parse-control-character ( -- n ) read1 ;
ERROR: bad-escaped-literals seq ;
-: parse-escaped-literals ( -- obj )
- "\\E" read-until [ bad-escaped-literals ] unless
+
+: parse-til-E ( -- obj )
+ "\\E" read-until [ bad-escaped-literals ] unless ;
+
+:: (parse-escaped-literals) ( quot: ( obj -- obj' ) -- obj )
+ parse-til-E
drop1
[ epsilon ] [
- [ <constant> ] V{ } map-as
+ [ quot call <constant> ] V{ } map-as
first|concatenation
- ] if-empty ;
+ ] if-empty ; inline
-ERROR: unrecognized-escape char ;
+: parse-escaped-literals ( -- obj )
+ [ ] (parse-escaped-literals) ;
+
+: lower-case-literals ( -- obj )
+ [ ch>lower ] (parse-escaped-literals) ;
+
+: upper-case-literals ( -- obj )
+ [ ch>upper ] (parse-escaped-literals) ;
: parse-escaped ( -- obj )
read1
{
- { CHAR: \ [ CHAR: \ <constant> ] }
- { CHAR: ^ [ CHAR: ^ <constant> ] }
- { CHAR: $ [ CHAR: $ <constant> ] }
- { CHAR: - [ CHAR: - <constant> ] }
- { CHAR: { [ CHAR: { <constant> ] }
- { CHAR: } [ CHAR: } <constant> ] }
- { CHAR: [ [ CHAR: [ <constant> ] }
- { CHAR: ] [ CHAR: ] <constant> ] }
- { CHAR: ( [ CHAR: ( <constant> ] }
- { CHAR: ) [ CHAR: ) <constant> ] }
- { CHAR: @ [ CHAR: @ <constant> ] }
- { CHAR: * [ CHAR: * <constant> ] }
- { CHAR: + [ CHAR: + <constant> ] }
- { CHAR: ? [ CHAR: ? <constant> ] }
- { CHAR: . [ CHAR: . <constant> ] }
- { CHAR: : [ CHAR: : <constant> ] }
{ CHAR: t [ CHAR: \t <constant> ] }
{ CHAR: n [ CHAR: \n <constant> ] }
{ CHAR: r [ CHAR: \r <constant> ] }
{ CHAR: a [ HEX: 7 <constant> ] }
{ CHAR: e [ HEX: 1b <constant> ] }
- { CHAR: d [ digit-class ] }
- { CHAR: D [ digit-class <negation> ] }
- { CHAR: s [ java-blank-class ] }
- { CHAR: S [ java-blank-class <negation> ] }
{ CHAR: w [ c-identifier-class ] }
{ CHAR: W [ c-identifier-class <negation> ] }
+ { CHAR: s [ java-blank-class ] }
+ { CHAR: S [ java-blank-class <negation> ] }
+ { CHAR: d [ digit-class ] }
+ { CHAR: D [ digit-class <negation> ] }
{ CHAR: p [ parse-posix-class ] }
{ CHAR: P [ parse-posix-class <negation> ] }
{ CHAR: 0 [ parse-octal <constant> ] }
{ CHAR: c [ parse-control-character ] }
- ! { CHAR: b [ handle-word-boundary ] }
- ! { CHAR: B [ handle-word-boundary <negation> ] }
+ { CHAR: Q [ parse-escaped-literals ] }
+
+ ! { CHAR: b [ word-boundary-class ] }
+ ! { CHAR: B [ word-boundary-class <negation> ] }
! { CHAR: A [ handle-beginning-of-input ] }
+ ! { CHAR: z [ handle-end-of-input ] }
+
+ ! { CHAR: Z [ handle-end-of-input ] } ! plus a final terminator
+
+ ! m//g mode
! { CHAR: G [ end of previous match ] }
- ! { CHAR: Z [ handle-end-of-input ] }
- ! { CHAR: z [ handle-end-of-input ] } ! except for terminator
+ ! Group capture
! { CHAR: 1 [ CHAR: 1 <constant> ] }
! { CHAR: 2 [ CHAR: 2 <constant> ] }
! { CHAR: 3 [ CHAR: 3 <constant> ] }
! { CHAR: 8 [ CHAR: 8 <constant> ] }
! { CHAR: 9 [ CHAR: 9 <constant> ] }
- { CHAR: Q [ parse-escaped-literals ] }
- [ unrecognized-escape ]
+ ! Perl extensions
+ ! can't do \l and \u because \u is already a 4-hex
+ { CHAR: L [ lower-case-literals ] }
+ { CHAR: U [ upper-case-literals ] }
+
+ [ <constant> ]
} case ;
: handle-escape ( -- ) parse-escaped push-stack ;
} case
[ (parse-character-class) ] when ;
+: push-constant ( ch -- ) <constant> push-stack ;
+
: parse-character-class-second ( -- )
read1 {
- { CHAR: [ [ CHAR: [ <constant> push-stack ] }
- { CHAR: ] [ CHAR: ] <constant> push-stack ] }
- { CHAR: - [ CHAR: - <constant> push-stack ] }
+ { CHAR: [ [ CHAR: [ push-constant ] }
+ { CHAR: ] [ CHAR: ] push-constant ] }
+ { CHAR: - [ CHAR: - push-constant ] }
[ push1 ]
} case ;
: parse-character-class-first ( -- )
read1 {
{ CHAR: ^ [ caret push-stack parse-character-class-second ] }
- { CHAR: [ [ CHAR: [ <constant> push-stack ] }
- { CHAR: ] [ CHAR: ] <constant> push-stack ] }
- { CHAR: - [ CHAR: - <constant> push-stack ] }
+ { CHAR: [ [ CHAR: [ push-constant ] }
+ { CHAR: ] [ CHAR: ] push-constant ] }
+ { CHAR: - [ CHAR: - push-constant ] }
[ push1 ]
} case ;
[ first|concatenation ] map first|alternation ;
: handle-right-parenthesis ( -- )
- stack dup [ parentheses-group "members" word-prop member? ] find-last -rot cut rest
+ stack dup [ parentheses-group "members" word-prop member? ] find-last
+ -rot cut rest
[ [ push ] keep current-regexp get (>>stack) ]
[ finish-regexp-parse push-stack ] bi* ;
{ CHAR: [ [ handle-left-bracket t ] }
{ CHAR: \ [ handle-escape t ] }
[
- dup CHAR: $ = peek1 f = and [
- drop
- handle-back-anchor f
- ] [
- <constant> push-stack t
- ] if
+ dup CHAR: $ = peek1 f = and
+ [ drop handle-back-anchor f ]
+ [ push-constant t ] if
]
} case ;
parse-regexp-beginning (parse-regexp)
] with-input-stream
] unless-empty
- current-regexp get
- stack finish-regexp-parse
- >>parse-tree drop
+ current-regexp get [ finish-regexp-parse ] change-stack
+ dup stack>> >>parse-tree drop
] with-variable ;
HELP: <regexp>
{ $values { "string" string } { "regexp" regexp } }
{ $description "Compiles a regular expression into a DFA and returns this object. Regular expressions only have to be compiled once and can then be used multiple times to match input strings." } ;
-
-HELP: <iregexp>
-{ $values { "string" string } { "regexp" regexp } }
-{ $description "Compiles a case-insensitive regular expression into a DFA and returns this object. Otherwise, exactly the same as " { $link <regexp> } } ;
-
-{ <regexp> <iregexp> } related-words
USING: regexp tools.test kernel sequences regexp.parser
-regexp.traversal eval ;
+regexp.traversal eval strings ;
IN: regexp-tests
+\ <regexp> must-infer
+\ matches? must-infer
+
[ f ] [ "b" "a*" <regexp> matches? ] unit-test
[ t ] [ "" "a*" <regexp> matches? ] unit-test
[ t ] [ "a" "a*" <regexp> matches? ] unit-test
[ f ] [ "" "." <regexp> matches? ] unit-test
[ t ] [ "a" "." <regexp> matches? ] unit-test
[ t ] [ "." "." <regexp> matches? ] unit-test
-! [ f ] [ "\n" "." <regexp> matches? ] unit-test
+
+! Dotall mode -- when on, . matches newlines.
+! Off by default.
+[ f ] [ "\n" "." <regexp> matches? ] unit-test
+[ t ] [ "\n" "(?s)." <regexp> matches? ] unit-test
+[ t ] [ "\n" R/ ./s matches? ] unit-test
+[ f ] [ "\n\n" "(?s).(?-s)." <regexp> matches? ] unit-test
[ f ] [ "" ".+" <regexp> matches? ] unit-test
[ t ] [ "a" ".+" <regexp> matches? ] unit-test
[ t ] [ "ab" ".+" <regexp> matches? ] unit-test
+[ t ] [ " " "[\\s]" <regexp> matches? ] unit-test
+[ f ] [ "a" "[\\s]" <regexp> matches? ] unit-test
+[ f ] [ " " "[\\S]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[\\S]" <regexp> matches? ] unit-test
+[ f ] [ " " "[\\w]" <regexp> matches? ] unit-test
+[ t ] [ "a" "[\\w]" <regexp> matches? ] unit-test
+[ t ] [ " " "[\\W]" <regexp> matches? ] unit-test
+[ f ] [ "a" "[\\W]" <regexp> matches? ] unit-test
+
+[ t ] [ "/" "\\/" <regexp> matches? ] unit-test
+
+[ t ] [ "a" R' a'i matches? ] unit-test
[ t ] [ "" "a|b*|c+|d?" <regexp> matches? ] unit-test
[ t ] [ "a" "a|b*|c+|d?" <regexp> matches? ] unit-test
[ f ] [ "ABC" "\\p{Lower}{3}" <regexp> matches? ] unit-test
[ t ] [ "ABC" "\\p{Upper}{3}" <regexp> matches? ] unit-test
[ f ] [ "abc" "\\p{Upper}{3}" <regexp> matches? ] unit-test
-!
[ f ] [ "abc" "[\\p{Upper}]{3}" <regexp> matches? ] unit-test
[ t ] [ "ABC" "[\\p{Upper}]{3}" <regexp> matches? ] unit-test
[ 3 ] [ "aaacb" "a*" <regexp> match-head ] unit-test
[ 2 ] [ "aaacb" "aa?" <regexp> match-head ] unit-test
-[ t ] [ "aaa" "AAA" <iregexp> matches? ] unit-test
-[ f ] [ "aax" "AAA" <iregexp> matches? ] unit-test
-[ t ] [ "aaa" "A*" <iregexp> matches? ] unit-test
-[ f ] [ "aaba" "A*" <iregexp> matches? ] unit-test
-[ t ] [ "b" "[AB]" <iregexp> matches? ] unit-test
-[ f ] [ "c" "[AB]" <iregexp> matches? ] unit-test
-[ t ] [ "c" "[A-Z]" <iregexp> matches? ] unit-test
-[ f ] [ "3" "[A-Z]" <iregexp> matches? ] unit-test
+[ t ] [ "aaa" R/ AAA/i matches? ] unit-test
+[ f ] [ "aax" R/ AAA/i matches? ] unit-test
+[ t ] [ "aaa" R/ A*/i matches? ] unit-test
+[ f ] [ "aaba" R/ A*/i matches? ] unit-test
+[ t ] [ "b" R/ [AB]/i matches? ] unit-test
+[ f ] [ "c" R/ [AB]/i matches? ] unit-test
+[ t ] [ "c" R/ [A-Z]/i matches? ] unit-test
+[ f ] [ "3" R/ [A-Z]/i matches? ] unit-test
[ t ] [ "a" "(?i)a" <regexp> matches? ] unit-test
[ t ] [ "a" "(?i)a" <regexp> matches? ] unit-test
[ t ] [ "A" "(?i)a" <regexp> matches? ] unit-test
[ t ] [ "A" "(?i)a" <regexp> matches? ] unit-test
-[ t ] [ "a" "(?-i)a" <iregexp> matches? ] unit-test
-[ t ] [ "a" "(?-i)a" <iregexp> matches? ] unit-test
-[ f ] [ "A" "(?-i)a" <iregexp> matches? ] unit-test
-[ f ] [ "A" "(?-i)a" <iregexp> matches? ] unit-test
+[ t ] [ "a" R/ (?-i)a/i matches? ] unit-test
+[ t ] [ "a" R/ (?-i)a/i matches? ] unit-test
+[ f ] [ "A" R/ (?-i)a/i matches? ] unit-test
+[ f ] [ "A" R/ (?-i)a/i matches? ] unit-test
[ f ] [ "A" "[a-z]" <regexp> matches? ] unit-test
-[ t ] [ "A" "[a-z]" <iregexp> matches? ] unit-test
+[ t ] [ "A" R/ [a-z]/i matches? ] unit-test
[ f ] [ "A" "\\p{Lower}" <regexp> matches? ] unit-test
-[ t ] [ "A" "\\p{Lower}" <iregexp> matches? ] unit-test
+[ t ] [ "A" R/ \p{Lower}/i matches? ] unit-test
-[ t ] [ "abc" <reversed> "abc" <rregexp> matches? ] unit-test
-[ t ] [ "abc" <reversed> "a[bB][cC]" <rregexp> matches? ] unit-test
-[ t ] [ "adcbe" "a(?r)(bcd)(?-r)e" <rregexp> matches? ] unit-test
+[ t ] [ "abc" <reversed> R/ abc/r matches? ] unit-test
+[ t ] [ "abc" <reversed> R/ a[bB][cC]/r matches? ] unit-test
+[ t ] [ "adcbe" R/ a(?r)(bcd)(?-r)e/ matches? ] unit-test
[ t ] [ "s@f" "[a-z.-]@[a-z]" <regexp> matches? ] unit-test
[ f ] [ "a" "[a-z.-]@[a-z]" <regexp> matches? ] unit-test
[ ] [ "(\\$[\\p{XDigit}]|[\\p{Digit}])" <regexp> drop ] unit-test
-! Comment
+! Comment inside a regular expression
[ t ] [ "ac" "a(?#boo)c" <regexp> matches? ] unit-test
+[ ] [ "USING: regexp kernel ; R' -{3}[+]{1,6}(?:!!)?\\s' drop" eval ] unit-test
+[ ] [ "USING: regexp kernel ; R' (ftp|http|https)://(\\w+:?\\w*@)?(\\S+)(:[0-9]+)?(/|/([\\w#!:.?+=&%@!\\-/]))?' drop" eval ] unit-test
-! [ "{Lower}" <regexp> ] [ invalid-range? ] must-fail-with
+[ ] [ "USING: regexp kernel ; R' \\*[^\s*][^*]*\\*' drop" eval ] unit-test
-! [ 1 ] [ "aaacb" "a+?" <regexp> match-head ] unit-test
-! [ 1 ] [ "aaacb" "aa??" <regexp> match-head ] unit-test
-! [ f ] [ "aaaab" "a++ab" <regexp> matches? ] unit-test
-! [ t ] [ "aaacb" "a++cb" <regexp> matches? ] unit-test
-! [ 3 ] [ "aacb" "aa?c" <regexp> match-head ] unit-test
-! [ 3 ] [ "aacb" "aa??c" <regexp> match-head ] unit-test
+[ "ab" ] [ "ab" "(a|ab)(bc)?" <regexp> first-match >string ] unit-test
+[ "abc" ] [ "abc" "(a|ab)(bc)?" <regexp> first-match >string ] unit-test
+
+[ "ab" ] [ "ab" "(ab|a)(bc)?" <regexp> first-match >string ] unit-test
+[ "abc" ] [ "abc" "(ab|a)(bc)?" <regexp> first-match >string ] unit-test
+
+[ "b" ] [ "aaaaaaaaaaaaaaaaaaaaaaab" "((a*)*b)*b" <regexp> first-match >string ] unit-test
+
+! [ t ] [ "a:b" ".+:?" <regexp> matches? ] unit-test
+! [ 1 ] [ "hello" ".+?" <regexp> match length ] unit-test
+
+[ { "1" "2" "3" "4" } ]
+[ "1ABC2DEF3GHI4" R/ [A-Z]+/ re-split [ >string ] map ] unit-test
+
+[ { "1" "2" "3" "4" } ]
+[ "1ABC2DEF3GHI4JK" R/ [A-Z]+/ re-split [ >string ] map ] unit-test
+
+[ { "ABC" "DEF" "GHI" } ]
+[ "1ABC2DEF3GHI4" R/ [A-Z]+/ all-matches [ >string ] map ] unit-test
+
+[ 3 ]
+[ "1ABC2DEF3GHI4" R/ [A-Z]+/ count-matches ] unit-test
+
+[ 0 ]
+[ "123" R/ [A-Z]+/ count-matches ] unit-test
+
+[ "1.2.3.4" ]
+[ "1ABC2DEF3GHI4JK" R/ [A-Z]+/ "." re-replace ] unit-test
+
+[ f ] [ "ab" "a(?!b)" <regexp> first-match ] unit-test
+[ "a" ] [ "ac" "a(?!b)" <regexp> first-match >string ] unit-test
! [ t ] [ "fxxbar" "(?!foo).{3}bar" <regexp> matches? ] unit-test
-! [ f ] [ "foobar" "(?!foo).{3}bar" <regexp> matches? ] unit-test
+[ f ] [ "foobar" "(?!foo).{3}bar" <regexp> matches? ] unit-test
+[ "a" ] [ "ab" "a(?=b)(?=b)" <regexp> first-match >string ] unit-test
+[ "a" ] [ "ba" "a(?<=b)(?<=b)" <regexp> first-match >string ] unit-test
+[ "a" ] [ "cab" "a(?=b)(?<=c)" <regexp> first-match >string ] unit-test
[ 3 ] [ "foobar" "foo(?=bar)" <regexp> match-head ] unit-test
[ f ] [ "foobxr" "foo(?=bar)" <regexp> match-head ] unit-test
+! Bug in parsing word
+[ t ] [ "a" R' a' matches? ] unit-test
+
+! Convert to lowercase until E
+[ f ] [ "AA" R/ \LAA\E/ matches? ] unit-test
+[ t ] [ "aa" R/ \LAA\E/ matches? ] unit-test
+
+! Convert to uppercase until E
+[ t ] [ "AA" R/ \Uaa\E/ matches? ] unit-test
+[ f ] [ "aa" R/ \Uaa\E/ matches? ] unit-test
+
+! [ "{Lower}" <regexp> ] [ invalid-range? ] must-fail-with
+
+! [ t ] [ "a" R/ ^a/ matches? ] unit-test
+! [ f ] [ "\na" R/ ^a/ matches? ] unit-test
+! [ f ] [ "\r\na" R/ ^a/ matches? ] unit-test
+! [ f ] [ "\ra" R/ ^a/ matches? ] unit-test
+
+! [ t ] [ "a" R/ a$/ matches? ] unit-test
+! [ f ] [ "a\n" R/ a$/ matches? ] unit-test
+! [ f ] [ "a\r" R/ a$/ matches? ] unit-test
+! [ f ] [ "a\r\n" R/ a$/ matches? ] unit-test
+
+! [ t ] [ "a" R/ a$|b$/ matches? ] unit-test
+! [ t ] [ "b" R/ a$|b$/ matches? ] unit-test
+! [ t ] [ "ab" R/ a$|b$/ matches? ] unit-test
+! [ t ] [ "ba" R/ ba$|b$/ matches? ] unit-test
+
+! [ t ] [ "a" R/ \Aa/ matches? ] unit-test
+! [ f ] [ "\na" R/ \Aaa/ matches? ] unit-test
+! [ f ] [ "\r\na" R/ \Aa/ matches? ] unit-test
+! [ f ] [ "\ra" R/ \Aa/ matches? ] unit-test
+
+! [ t ] [ "a" R/ \Aa/m matches? ] unit-test
+! [ f ] [ "\na" R/ \Aaa/m matches? ] unit-test
+! [ f ] [ "\r\na" R/ \Aa/m matches? ] unit-test
+! [ f ] [ "\ra" R/ \Aa/m matches? ] unit-test
+
+! [ t ] [ "\r\n\n\n\nam" R/ ^am/m matches? ] unit-test
+
+! [ t ] [ "a" R/ \Aa\z/m matches? ] unit-test
+! [ f ] [ "a\n" R/ \Aa\z/m matches? ] unit-test
+
+! [ t ] [ "a\r\n" R/ \Aa\Z/m matches? ] unit-test
+! [ t ] [ "a\n" R/ \Aa\Z/m matches? ] unit-test
+
+! [ t ] [ "a" R/ \Aa\Z/m matches? ] unit-test
+! [ f ] [ "\na" R/ \Aaa\Z/m matches? ] unit-test
+! [ f ] [ "\r\na" R/ \Aa\Z/m matches? ] unit-test
+! [ f ] [ "\ra" R/ \Aa\Z/m matches? ] unit-test
+
+! [ t ] [ "a" R/ ^a/m matches? ] unit-test
+! [ t ] [ "\na" R/ ^a/m matches? ] unit-test
+! [ t ] [ "\r\na" R/ ^a/m matches? ] unit-test
+! [ t ] [ "\ra" R/ ^a/m matches? ] unit-test
+
+! [ t ] [ "a" "a$" R/ a$/m matches? ] unit-test
+! [ t ] [ "a\n" "a$" R/ a$/m matches? ] unit-test
+! [ t ] [ "a\r" "a$" R/ a$/m matches? ] unit-test
+! [ t ] [ "a\r\n" "a$" R/ a$/m matches? ] unit-test
+
! [ f ] [ "foobxr" "foo\\z" <regexp> match-head ] unit-test
! [ 3 ] [ "foo" "foo\\z" <regexp> match-head ] unit-test
+! [ t ] [ "foo" "\\bfoo\\b" <regexp> matches? ] unit-test
+! [ t ] [ "afoob" "\\Bfoo\\B" <regexp> matches? ] unit-test
+! [ t ] [ "afoob" "\\bfoo\\b" <regexp> matches? ] unit-test
+! [ f ] [ "foo" "\\Bfoo\\B" <regexp> matches? ] unit-test
+
! [ 3 ] [ "foo bar" "foo\\b" <regexp> match-head ] unit-test
! [ f ] [ "fooxbar" "foo\\b" <regexp> matches? ] unit-test
! [ t ] [ "foo" "foo\\b" <regexp> matches? ] unit-test
! [ t ] [ "fooxbar" "foo\\Bxbar" <regexp> matches? ] unit-test
! [ f ] [ "foo" "foo\\Bbar" <regexp> matches? ] unit-test
-[ ] [ "USING: regexp kernel ; R' -{3}[+]{1,6}(?:!!)?\\s' drop" eval ] unit-test
-
-[ ] [ "USING: regexp kernel ; R' (ftp|http|https)://(\\w+:?\\w*@)?(\\S+)(:[0-9]+)?(/|/([\\w#!:.?+=&%@!\\-/]))?' drop" eval ] unit-test
-
-[ ] [ "USING: regexp kernel ; R' \\*[^\s*][^*]*\\*' drop" eval ] unit-test
-
-! Bug in parsing word
-! [ t ] [ "a" R' a' matches? ] unit-test
-
-! ((A)(B(C)))
-! 1. ((A)(B(C)))
-! 2. (A)
-! 3. (B(C))
-! 4. (C)
-
-! clear "a(?=b*)" <regexp> "ab" over match
-! clear "a(?=b*c)" <regexp> "abbbbbc" over match
-! clear "a(?=b*)" <regexp> "ab" over match
-
-! clear "^a" <regexp> "a" over match
-! clear "^a" <regexp> "\na" over match
-! clear "^a" <regexp> "\r\na" over match
-! clear "^a" <regexp> "\ra" over match
-
-! clear "a$" <regexp> "a" over match
-! clear "a$" <regexp> "a\n" over match
-! clear "a$" <regexp> "a\r" over match
-! clear "a$" <regexp> "a\r\n" over match
-
-! "(az)(?<=b)" <regexp> "baz" over first-match
-! "a(?<=b*)" <regexp> "cbaz" over first-match
-! "a(?<=b)" <regexp> "baz" over first-match
+! [ 1 ] [ "aaacb" "a+?" <regexp> match-head ] unit-test
+! [ 1 ] [ "aaacb" "aa??" <regexp> match-head ] unit-test
+! [ f ] [ "aaaab" "a++ab" <regexp> matches? ] unit-test
+! [ t ] [ "aaacb" "a++cb" <regexp> matches? ] unit-test
+! [ 3 ] [ "aacb" "aa?c" <regexp> match-head ] unit-test
+! [ 3 ] [ "aacb" "aa??c" <regexp> match-head ] unit-test
-! "a(?<!b)" <regexp> "baz" over first-match
-! "a(?<!b)" <regexp> "caz" over first-match
+! "ab" "a(?=b*)" <regexp> match
+! "abbbbbc" "a(?=b*c)" <regexp> match
+! "ab" "a(?=b*)" <regexp> match
-! "a(?=bcdefg)bcd" <regexp> "abcdefg" over first-match
-! "a(?#bcdefg)bcd" <regexp> "abcdefg" over first-match
-! "a(?:bcdefg)" <regexp> "abcdefg" over first-match
+! "baz" "(az)(?<=b)" <regexp> first-match
+! "cbaz" "a(?<=b*)" <regexp> first-match
+! "baz" "a(?<=b)" <regexp> first-match
-[ { 0 1 } ] [ "ac" "a(?!b)" <regexp> first-match ] unit-test
-[ f ] [ "ab" "a(?!b)" <regexp> first-match ] unit-test
+! "baz" "a(?<!b)" <regexp> first-match
+! "caz" "a(?<!b)" <regexp> first-match
-! "a(?<=b)" <regexp> "caba" over first-match
+! "abcdefg" "a(?=bcdefg)bcd" <regexp> first-match
+! "abcdefg" "a(?#bcdefg)bcd" <regexp> first-match
+! "abcdefg" "a(?:bcdefg)" <regexp> first-match
-[ { 0 1 } ] [ "ab" "a(?=b)(?=b)" <regexp> first-match ] unit-test
-[ { 1 2 } ] [ "ba" "a(?<=b)(?<=b)" <regexp> first-match ] unit-test
-[ { 1 2 } ] [ "cab" "a(?=b)(?<=c)" <regexp> first-match ] unit-test
+! "caba" "a(?<=b)" <regexp> first-match
! capture group 1: "aaaa" 2: ""
! "aaaa" "(a*)(a*)" <regexp> match*
! "aaaa" "(a*)(a+)" <regexp> match*
-
-[ { 0 2 } ] [ "ab" "(a|ab)(bc)?" <regexp> first-match ] unit-test
-[ { 0 3 } ] [ "abc" "(a|ab)(bc)?" <regexp> first-match ] unit-test
-
-[ { 0 2 } ] [ "ab" "(ab|a)(bc)?" <regexp> first-match ] unit-test
-[ { 0 3 } ] [ "abc" "(ab|a)(bc)?" <regexp> first-match ] unit-test
-
-[ { 23 24 } ] [ "aaaaaaaaaaaaaaaaaaaaaaab" "((a*)*b)*b" <regexp> first-match ] unit-test
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors combinators kernel math math.ranges sequences
-sets assocs prettyprint.backend make lexer namespaces parser
-arrays fry regexp.backend regexp.utils regexp.parser regexp.nfa
-regexp.dfa regexp.traversal regexp.transition-tables ;
+USING: accessors combinators kernel math sequences strings sets
+assocs prettyprint.backend prettyprint.custom make lexer
+namespaces parser arrays fry regexp.backend regexp.utils
+regexp.parser regexp.nfa regexp.dfa regexp.traversal
+regexp.transition-tables splitting sorting ;
IN: regexp
: default-regexp ( string -- regexp )
H{ } clone >>nfa-traversal-flags
H{ } clone >>dfa-traversal-flags
H{ } clone >>options
+ H{ } clone >>matchers
reset-regexp ;
: construct-regexp ( regexp -- regexp' )
[ ]
} cleave ;
-: match ( string regexp -- pair )
- <dfa-traverser> do-match return-match ;
+: (match) ( string regexp -- dfa-traverser )
+ <dfa-traverser> do-match ; inline
-: match* ( string regexp -- pair )
- <dfa-traverser> do-match [ return-match ] [ captured-groups>> ] bi ;
+: match ( string regexp -- slice/f )
+ (match) return-match ;
+
+: match* ( string regexp -- slice/f captured-groups )
+ (match) [ return-match ] [ captured-groups>> ] bi ;
: matches? ( string regexp -- ? )
dupd match
- [ [ length ] [ length>> 1- ] bi* = ] [ drop f ] if* ;
+ [ [ length ] bi@ = ] [ drop f ] if* ;
-: match-head ( string regexp -- end/f ) match [ length>> 1- ] [ f ] if* ;
+: match-head ( string regexp -- end/f ) match [ length ] [ f ] if* ;
: match-at ( string m regexp -- n/f finished? )
[
[ 3drop drop f f ] [ drop [ 1+ ] dip match-range ] if
] if ;
-: first-match ( string regexp -- pair/f )
- 0 swap match-range dup [ 2array ] [ 2drop f ] if ;
+: first-match ( string regexp -- slice/f )
+ dupd 0 swap match-range rot over [ <slice> ] [ 3drop f ] if ;
: re-cut ( string regexp -- end/f start )
dupd first-match
- [ [ second tail-slice ] [ first head ] 2bi ]
- [ "" like f swap ]
- if* ;
+ [ split1-slice swap ] [ "" like f swap ] if* ;
: re-split ( string regexp -- seq )
- [ dup ] swap '[ _ re-cut ] [ ] produce nip ;
+ [ dup length 0 > ] swap '[ _ re-cut ] [ ] produce nip ;
: re-replace ( string regexp replacement -- result )
[ re-split ] dip join ;
: next-match ( string regexp -- end/f match/f )
dupd first-match dup
- [ [ second tail-slice ] keep ]
- [ 2drop f f ]
- if ;
+ [ [ split1-slice nip ] keep ] [ 2drop f f ] if ;
: all-matches ( string regexp -- seq )
- [ dup ] swap '[ _ next-match ] [ ] produce nip ;
+ [ dup ] swap '[ _ next-match ] [ ] produce nip harvest ;
: count-matches ( string regexp -- n )
- all-matches length 1- ;
+ all-matches length ;
-: initial-option ( regexp option -- regexp' )
- over options>> conjoin ;
+<PRIVATE
-: <regexp> ( string -- regexp )
- default-regexp construct-regexp ;
+: find-regexp-syntax ( string -- prefix suffix )
+ {
+ { "R/ " "/" }
+ { "R! " "!" }
+ { "R\" " "\"" }
+ { "R# " "#" }
+ { "R' " "'" }
+ { "R( " ")" }
+ { "R@ " "@" }
+ { "R[ " "]" }
+ { "R` " "`" }
+ { "R{ " "}" }
+ { "R| " "|" }
+ } swap [ subseq? not nip ] curry assoc-find drop ;
-: <iregexp> ( string -- regexp )
- default-regexp
- case-insensitive initial-option
- construct-regexp ;
+: string>options ( string -- options )
+ [ ch>option dup ] H{ } map>assoc ;
+
+: options>string ( options -- string )
+ keys [ option>ch ] map natural-sort >string ;
-: <rregexp> ( string -- regexp )
- default-regexp
- reversed-regexp initial-option
+PRIVATE>
+
+: <optioned-regexp> ( string option-string -- regexp )
+ [ default-regexp ] [ string>options ] bi* >>options
construct-regexp ;
+: <regexp> ( string -- regexp ) "" <optioned-regexp> ;
+
+<PRIVATE
+
: parsing-regexp ( accum end -- accum )
lexer get dup skip-blank
[ [ index-from dup 1+ swap ] 2keep swapd subseq swap ] change-lexer-column
lexer get dup still-parsing-line?
[ (parse-token) ] [ drop f ] if
- "i" = [ <iregexp> ] [ <regexp> ] if parsed ;
+ <optioned-regexp> parsed ;
+
+PRIVATE>
: R! CHAR: ! parsing-regexp ; parsing
: R" CHAR: " parsing-regexp ; parsing
: R{ CHAR: } parsing-regexp ; parsing
: R| CHAR: | parsing-regexp ; parsing
-: find-regexp-syntax ( string -- prefix suffix )
- {
- { "R/ " "/" }
- { "R! " "!" }
- { "R\" " "\"" }
- { "R# " "#" }
- { "R' " "'" }
- { "R( " ")" }
- { "R@ " "@" }
- { "R[ " "]" }
- { "R` " "`" }
- { "R{ " "}" }
- { "R| " "|" }
- } swap [ subseq? not nip ] curry assoc-find drop ;
-
-: option? ( option regexp -- ? )
- options>> key? ;
-
-USE: multiline
-/*
M: regexp pprint*
[
[
- dup raw>>
- dup find-regexp-syntax swap % swap % %
- case-insensitive swap option? [ "i" % ] when
+ [ raw>> dup find-regexp-syntax swap % swap % % ]
+ [ options>> options>string % ] bi
] "" make
] keep present-text ;
-*/
: <literal-transition> ( from to obj -- transition )
literal-transition make-transition ;
+
: <class-transition> ( from to obj -- transition )
class-transition make-transition ;
+
: <default-transition> ( from to -- transition )
t default-transition make-transition ;
2dup [ to>> ] dip maybe-initialize-key
[ [ to>> ] [ obj>> ] [ from>> ] tri ] dip
2dup at* [ 2nip insert-at ]
- [ drop >r >r H{ } clone [ insert-at ] keep r> r> set-at ] if ;
+ [ drop [ H{ } clone [ insert-at ] keep ] 2dip set-at ] if ;
: add-transition ( transition transition-table -- )
transitions>> set-transition ;
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors assocs combinators kernel math math.ranges
+USING: accessors assocs combinators kernel math
quotations sequences regexp.parser regexp.classes fry arrays
combinators.short-circuit regexp.utils prettyprint regexp.nfa
shuffle ;
capture-group-index
last-state current-state
text
+ match-failed?
start-index current-index
matches ;
H{ } clone >>captured-groups ;
: final-state? ( dfa-traverser -- ? )
- [ current-state>> ] [ dfa-table>> final-states>> ] bi
- key? ;
+ [ current-state>> ]
+ [ dfa-table>> final-states>> ] bi key? ;
+
+: beginning-of-text? ( dfa-traverser -- ? )
+ current-index>> 0 <= ; inline
+
+: end-of-text? ( dfa-traverser -- ? )
+ [ current-index>> ] [ text>> length ] bi >= ; inline
: text-finished? ( dfa-traverser -- ? )
{
[ current-state>> empty? ]
- [ [ current-index>> ] [ text>> length ] bi >= ]
- ! [ current-index>> 0 < ]
+ [ end-of-text? ]
+ [ match-failed?>> ]
} 1|| ;
: save-final-state ( dfa-straverser -- )
dup save-final-state
] when text-finished? ;
+: previous-text-character ( dfa-traverser -- ch )
+ [ text>> ] [ current-index>> 1- ] bi nth ;
+
+: current-text-character ( dfa-traverser -- ch )
+ [ text>> ] [ current-index>> ] bi nth ;
+
+: next-text-character ( dfa-traverser -- ch )
+ [ text>> ] [ current-index>> 1+ ] bi nth ;
+
GENERIC: flag-action ( dfa-traverser flag -- )
+
+M: beginning-of-input flag-action ( dfa-traverser flag -- )
+ drop
+ dup beginning-of-text? [ t >>match-failed? ] unless drop ;
+
+M: end-of-input flag-action ( dfa-traverser flag -- )
+ drop
+ dup end-of-text? [ t >>match-failed? ] unless drop ;
+
+
+M: beginning-of-line flag-action ( dfa-traverser flag -- )
+ drop
+ dup {
+ [ beginning-of-text? ]
+ [ previous-text-character terminator-class class-member? ]
+ } 1|| [ t >>match-failed? ] unless drop ;
+
+M: end-of-line flag-action ( dfa-traverser flag -- )
+ drop
+ dup {
+ [ end-of-text? ]
+ [ next-text-character terminator-class class-member? ]
+ } 1|| [ t >>match-failed? ] unless drop ;
+
+
+M: word-boundary flag-action ( dfa-traverser flag -- )
+ drop
+ dup {
+ [ end-of-text? ]
+ [ current-text-character terminator-class class-member? ]
+ } 1|| [ t >>match-failed? ] unless drop ;
+
+
M: lookahead-on flag-action ( dfa-traverser flag -- )
drop
lookahead-counters>> 0 swap push ;
: increment-state ( dfa-traverser state -- dfa-traverser )
[
dup traverse-forward>>
- [ 1+ ] [ 1- ] ? change-current-index
+ [ [ 1+ ] change-current-index ]
+ [ [ 1- ] change-current-index ] if
dup current-state>> >>last-state
- ] dip
- first >>current-state ;
-
-: match-failed ( dfa-traverser -- dfa-traverser )
- V{ } clone >>matches ;
+ ] [ first ] bi* >>current-state ;
: match-literal ( transition from-state table -- to-state/f )
transitions>> at at ;
{ [ match-literal ] [ match-class ] [ match-default ] } 3|| ;
: setup-match ( match -- obj state dfa-table )
- {
- [ current-index>> ] [ text>> ]
- [ current-state>> ] [ dfa-table>> ]
- } cleave
- [ nth ] 2dip ;
+ [ [ current-index>> ] [ text>> ] bi nth ]
+ [ current-state>> ]
+ [ dfa-table>> ] tri ;
: do-match ( dfa-traverser -- dfa-traverser )
dup process-flags
[ increment-state do-match ] when*
] unless ;
-: return-match ( dfa-traverser -- interval/f )
+: return-match ( dfa-traverser -- slice/f )
dup matches>>
[ drop f ]
- [ [ start-index>> ] [ peek ] bi* 1 <range> ] if-empty ;
+ [
+ [ [ text>> ] [ start-index>> ] bi ]
+ [ peek ] bi* rot <slice>
+ ] if-empty ;
--- /dev/null
+USING: regexp.utils tools.test ;
+IN: regexp.utils.tests
+
+[ [ ] [ ] while-changes ] must-infer
math.ranges fry combinators.short-circuit vectors ;
IN: regexp.utils
-: (while-changes) ( obj quot pred pred-ret -- obj )
- ! quot: ( obj -- obj' )
- ! pred: ( obj -- <=> )
+: (while-changes) ( obj quot: ( obj -- obj' ) pred: ( obj -- <=> ) pred-ret -- obj )
[ [ dup slip ] dip pick over call ] dip dupd =
[ 3drop ] [ (while-changes) ] if ; inline recursive
: ?insert-at ( value key hash/f -- hash )
[ H{ } clone ] unless* [ insert-at ] keep ;
-: last-state ( regexp -- range ) stack>> peek first2 [a,b] ;
-: push1 ( obj -- ) input-stream get stream>> push ;
-: peek1 ( -- obj ) input-stream get stream>> [ f ] [ peek ] if-empty ;
-: pop3 ( seq -- obj1 obj2 obj3 ) [ pop ] [ pop ] [ pop ] tri spin ;
-: drop1 ( -- ) read1 drop ;
-
-: stack ( -- obj ) current-regexp get stack>> ;
-: change-whole-stack ( quot -- )
- current-regexp get
- [ stack>> swap call ] keep (>>stack) ; inline
-: push-stack ( obj -- ) stack push ;
-: pop-stack ( -- obj ) stack pop ;
-: cut-out ( vector n -- vector' vector ) cut rest ;
-ERROR: cut-stack-error ;
-: cut-stack ( obj vector -- vector' vector )
- tuck last-index [ cut-stack-error ] unless* cut-out swap ;
-
ERROR: bad-octal number ;
ERROR: bad-hex number ;
: check-octal ( octal -- octal ) dup 255 > [ bad-octal ] when ;
-USING: help.syntax help.markup ;
+USING: help.syntax help.markup kernel sequences ;
IN: sequences.deep
HELP: deep-each
-{ $values { "obj" "an object" } { "quot" "a quotation ( elt -- ) " } }
-{ $description "Execute a quotation on each nested element of an object and its children, in preorder." } ;
+{ $values { "obj" object } { "quot" { $quotation "( elt -- )" } } }
+{ $description "Execute a quotation on each nested element of an object and its children, in preorder." }
+{ $see-also each } ;
HELP: deep-map
-{ $values { "obj" "an object" } { "quot" "a quotation ( elt -- newelt )" } { "newobj" "the mapped object" } }
-{ $description "Execute a quotation on each nested element of an object and its children, in preorder. That is, the result of the execution of the quotation on the outer is used to map the inner elements." } ;
+{ $values { "obj" object } { "quot" { $quotation "( elt -- newelt )" } } { "newobj" "the mapped object" } }
+{ $description "Execute a quotation on each nested element of an object and its children, in preorder. That is, the result of the execution of the quotation on the outer is used to map the inner elements." }
+{ $see-also map } ;
HELP: deep-filter
-{ $values { "obj" "an object" } { "quot" "a quotation ( elt -- ? )" } { "seq" "a sequence" } }
-{ $description "Creates a sequence of sub-nodes in the object which satisfy the given quotation, in preorder. This includes the object itself, if it passes the quotation." } ;
+{ $values { "obj" object } { "quot" { $quotation "( elt -- ? )" } } { "seq" "a sequence" } }
+{ $description "Creates a sequence of sub-nodes in the object which satisfy the given quotation, in preorder. This includes the object itself, if it passes the quotation." }
+{ $see-also filter } ;
HELP: deep-find
-{ $values { "obj" "an object" } { "quot" "a quotation ( elt -- ? )" } { "elt" "an element" } }
-{ $description "Gets the first sub-node of the object, in preorder, which satisfies the quotation. If nothing satisifies it, it returns " { $link f } "." } ;
+{ $values { "obj" object } { "quot" { $quotation "( elt -- ? )" } } { "elt" "an element" } }
+{ $description "Gets the first sub-node of the object, in preorder, which satisfies the quotation. If nothing satisifies it, it returns " { $link f } "." }
+{ $see-also find } ;
HELP: deep-contains?
-{ $values { "obj" "an object" } { "quot" "a quotation ( elt -- ? )" } { "?" "a boolean" } }
-{ $description "Tests whether the given object or any subnode satisfies the given quotation." } ;
+{ $values { "obj" object } { "quot" { $quotation "( elt -- ? )" } } { "?" "a boolean" } }
+{ $description "Tests whether the given object or any subnode satisfies the given quotation." }
+{ $see-also contains? } ;
HELP: flatten
-{ $values { "obj" "an object" } { "seq" "a sequence" } }
+{ $values { "obj" object } { "seq" "a sequence" } }
{ $description "Creates a sequence of all of the leaf nodes (non-sequence nodes, but including strings and numbers) in the object." } ;
HELP: deep-change-each
-{ $values { "obj" "an object" } { "quot" "a quotation ( elt -- newelt )" } }
-{ $description "Modifies each sub-node of an object in place, in preorder." } ;
+{ $values { "obj" object } { "quot" { $quotation "( elt -- newelt )" } } }
+{ $description "Modifies each sub-node of an object in place, in preorder." }
+{ $see-also change-each } ;
+
+ARTICLE: "sequences.deep" "Deep sequence combinators"
+"The combinators in the " { $vocab-link "sequences.deep" } " vocabulary are variants of standard sequence combinators which traverse nested subsequences."
+{ $subsection deep-each }
+{ $subsection deep-map }
+{ $subsection deep-filter }
+{ $subsection deep-find }
+{ $subsection deep-contains? }
+{ $subsection deep-change-each }
+"A utility word to collapse nested subsequences:"
+{ $subsection flatten } ;
+
+ABOUT: "sequences.deep"
[ [ "hello" 3 4 swap ] ] [ [ { "hello" V{ 3 4 } } swap ] flatten ] unit-test
-[ "foo" t ] [ { { "foo" } "bar" } [ string? ] deep-find-from ] unit-test
+[ "foo" t ] [ { { "foo" } "bar" } [ string? ] (deep-find) ] unit-test
-[ f f ] [ { { "foo" } "bar" } [ number? ] deep-find-from ] unit-test
+[ f f ] [ { { "foo" } "bar" } [ number? ] (deep-find) ] unit-test
-[ { { "foo" } "bar" } t ] [ { { "foo" } "bar" } [ array? ] deep-find-from ] unit-test
+[ { { "foo" } "bar" } t ] [ { { "foo" } "bar" } [ array? ] (deep-find) ] unit-test
: change-something ( seq -- newseq )
dup array? [ "hi" suffix ] [ "hello" append ] if ;
[ [ deep-map ] curry map ] [ drop ] if ; inline recursive
: deep-filter ( obj quot: ( elt -- ? ) -- seq )
- over >r
- pusher >r deep-each r>
- r> dup branch? [ like ] [ drop ] if ; inline recursive
+ over [ pusher [ deep-each ] dip ] dip
+ dup branch? [ like ] [ drop ] if ; inline recursive
-: deep-find-from ( obj quot: ( elt -- ? ) -- elt ? )
+: (deep-find) ( obj quot: ( elt -- ? ) -- elt ? )
[ call ] 2keep rot [ drop t ] [
over branch? [
- f -rot [ >r nip r> deep-find-from ] curry find drop >boolean
+ f -rot [ [ nip ] dip (deep-find) ] curry find drop >boolean
] [ 2drop f f ] if
] if ; inline recursive
-: deep-find ( obj quot -- elt ) deep-find-from drop ; inline
+: deep-find ( obj quot -- elt ) (deep-find) drop ; inline
-: deep-contains? ( obj quot -- ? ) deep-find-from nip ; inline
+: deep-contains? ( obj quot -- ? ) (deep-find) nip ; inline
: deep-all? ( obj quot -- ? )
[ not ] compose deep-contains? not ; inline
: deep-change-each ( obj quot: ( elt -- elt' ) -- )
- over branch? [ [
- [ call ] keep over >r deep-change-each r>
- ] curry change-each ] [ 2drop ] if ; inline recursive
+ over branch? [
+ [ [ call ] keep over [ deep-change-each ] dip ] curry change-each
+ ] [ 2drop ] if ; inline recursive
: flatten ( obj -- seq )
[ branch? not ] deep-filter ;
<PRIVATE
-: iterate-seq >r dup length swap r> ; inline
+: iterate-seq [ dup length swap ] dip ; inline
: (map-next) ( i seq quot -- )
! this uses O(n) more bounds checks than is really necessary
- >r [ >r 1+ r> ?nth ] 2keep nth-unsafe r> call ; inline
+ [ [ [ 1+ ] dip ?nth ] 2keep nth-unsafe ] dip call ; inline
PRIVATE>
-: each-next ( seq quot -- )
- ! quot: next-elt elt --
+: each-next ( seq quot: ( next-elt elt -- ) -- )
iterate-seq [ (map-next) ] 2curry each-integer ; inline
-: map-next ( seq quot -- newseq )
- ! quot: next-elt elt -- newelt
- over dup length swap new-sequence >r
- iterate-seq [ (map-next) ] 2curry
- r> [ collect ] keep ; inline
+: map-next ( seq quot: ( next-elt elt -- newelt ) -- newseq )
+ over dup length swap new-sequence [
+ iterate-seq [ (map-next) ] 2curry
+ ] dip [ collect ] keep ; inline
! Copyright (C) 2006 Chris Double.
! See http://factorcode.org/license.txt for BSD license.
!
-USING: tools.test kernel serialize serialize.private io
-io.streams.byte-array math alien arrays byte-arrays bit-arrays
-float-arrays sequences math prettyprint parser classes
-math.constants io.encodings.binary random assocs ;
+USING: tools.test kernel serialize io io.streams.byte-array math
+alien arrays byte-arrays bit-arrays specialized-arrays.double
+sequences math prettyprint parser classes math.constants
+io.encodings.binary random assocs serialize.private ;
IN: serialize.tests
: test-serialize-cell
T{ serialize-test f "a" 2 }
B{ 50 13 55 64 1 }
?{ t f t f f t f }
- F{ 1.0 3.0 4.0 1.0 2.35 0.33 }
+ double-array{ 1.0 3.0 4.0 1.0 2.35 0.33 }
<< 1 [ 2 ] curry parsed >>
{ { "a" "bc" } { "de" "fg" } }
H{ { "a" "bc" } { "de" "fg" } }
[ 8 ] [ 5 6 7 8 3nip ] unit-test
[ 3 1 2 3 ] [ 1 2 3 tuckd ] unit-test
+[ 1 2 3 4 ] [ 3 4 1 2 2swap ] unit-test
IN: shuffle
-: 2swap ( x y z t -- z t x y ) rot >r rot r> ; inline
+: 2swap ( x y z t -- z t x y ) 2 2 mnswap ; inline
: nipd ( a b c -- b c ) rot drop ; inline
! Copyright (C) 2007 Elie CHAFTARI
! See http://factorcode.org/license.txt for BSD license.
-USING: combinators kernel prettyprint io io.timeouts
-sequences namespaces io.sockets continuations calendar
-io.encodings.ascii io.streams.duplex destructors ;
+USING: combinators kernel prettyprint io io.timeouts sequences
+namespaces io.sockets io.sockets.secure continuations calendar
+io.encodings.ascii io.streams.duplex destructors locals
+concurrency.promises threads accessors smtp.private
+io.unix.sockets.secure.debug ;
IN: smtp.server
! Mock SMTP server for testing purposes.
-! Usage: 4321 mock-smtp-server
! $ telnet 127.0.0.1 4321
! Trying 127.0.0.1...
! Connected to localhost.
SYMBOL: data-mode
: process ( -- )
- readln {
- { [ [ dup "HELO" head? ] keep "EHLO" head? or ] [
- "220 and..?\r\n" write flush t
- ] }
- { [ dup "QUIT" = ] [
- "bye\r\n" write flush f
- ] }
- { [ dup "MAIL FROM:" head? ] [
- "220 OK\r\n" write flush t
- ] }
- { [ dup "RCPT TO:" head? ] [
- "220 OK\r\n" write flush t
- ] }
- { [ dup "DATA" = ] [
- data-mode on
- "354 Enter message, ending with \".\" on a line by itself\r\n"
- write flush t
- ] }
- { [ dup "." = data-mode get and ] [
- data-mode off
- "220 OK\r\n" write flush t
- ] }
+ read-crlf {
+ {
+ [ dup [ "HELO" head? ] [ "EHLO" head? ] bi or ]
+ [ "220 and..?\r\n" write flush t ]
+ }
+ {
+ [ dup "STARTTLS" = ]
+ [
+ "220 2.0.0 Ready to start TLS\r\n" write flush
+ accept-secure-handshake t
+ ]
+ }
+ { [ dup "QUIT" = ] [ "220 bye\r\n" write flush f ] }
+ { [ dup "MAIL FROM:" head? ] [ "220 OK\r\n" write flush t ] }
+ { [ dup "RCPT TO:" head? ] [ "220 OK\r\n" write flush t ] }
+ {
+ [ dup "DATA" = ]
+ [
+ data-mode on
+ "354 Enter message, ending with \".\" on a line by itself\r\n"
+ write flush t
+ ]
+ }
+ {
+ [ dup "." = data-mode get and ]
+ [
+ data-mode off
+ "220 OK\r\n" write flush t
+ ]
+ }
{ [ data-mode get ] [ dup global [ print ] bind t ] }
- [
- "500 ERROR\r\n" write flush t
- ]
+ [ "500 ERROR\r\n" write flush t ]
} cond nip [ process ] when ;
-: mock-smtp-server ( port -- )
- "Starting SMTP server on port " write dup . flush
- "127.0.0.1" swap <inet4> ascii <server> [
- accept drop [
- 1 minutes timeouts
- "220 hello\r\n" write flush
- process
- global [ flush ] bind
- ] with-stream
- ] with-disposal ;
+:: mock-smtp-server ( promise -- )
+ #! Store the port we are running on in the promise.
+ [
+ [
+ "127.0.0.1" 0 <inet4> ascii <server> [
+ dup addr>> port>> promise fulfill
+ accept drop [
+ 1 minutes timeouts
+ "220 hello\r\n" write flush
+ process
+ global [ flush ] bind
+ ] with-stream
+ ] with-disposal
+ ] with-test-context
+ ] in-thread ;
IN: smtp
HELP: smtp-domain
-{ $description "The name of the machine that is sending the email. This variable will be filled in by the " { $link host-name } " word if not set by the user." } ;
+{ $var-description "The name of the machine that is sending the email. This variable will be filled in by the " { $link host-name } " word if not set by the user." } ;
HELP: smtp-server
-{ $description "Holds an " { $link inet } " object with the address of an SMTP server." } ;
+{ $var-description "Holds an " { $link inet } " object with the address of an SMTP server." } ;
+
+HELP: smtp-tls?
+{ $var-description "If set to true, secure socket communication will be established after connecting to the SMTP server. The server must support the " { $snippet "STARTTLS" } " command. Off by default." } ;
HELP: smtp-read-timeout
-{ $description "Holds an " { $link duration } " object that specifies how long to wait for a response from the SMTP server." } ;
+{ $var-description "Holds a " { $link duration } " object that specifies how long to wait for a response from the SMTP server." } ;
+
+HELP: smtp-auth
+{ $var-description "Holds either " { $link no-auth } " or an instance of " { $link plain-auth } ", specifying how to authenticate with the SMTP server. Set to " { $link no-auth } " by default." } ;
+
+HELP: no-auth
+{ $class-description "If the " { $link smtp-auth } " variable is set to this value, no authentication will be performed." } ;
+
+HELP: plain-auth
+{ $class-description "If the " { $link smtp-auth } " variable is set to this value, plain authentication will be performed, with the username and password stored in the " { $slot "username" } " and " { $slot "password" } " slots of the tuple sent to the server as plain-text." } ;
-HELP: esmtp?
-{ $description "Set true by default, determines whether the SMTP client is using the Extended SMTP protocol." } ;
+HELP: <plain-auth> ( username password -- plain-auth )
+{ $values { "username" string } { "password" string } { "plain-auth" plain-auth } }
+{ $description "Creates a new " { $link plain-auth } " instance." } ;
HELP: with-smtp-connection
{ $values { "quot" quotation } }
-{ $description "Connects to an SMTP server stored in " { $link smtp-server } " and calls the quotation." } ;
+{ $description "Connects to an SMTP server stored in " { $link smtp-server } " and calls the quotation." }
+{ $notes "This word is used to implement " { $link send-email } " and there is probably no reason to call it directly." } ;
+
+HELP: email
+{ $class-description "An e-mail. E-mails have the following slots:"
+ { $table
+ { { $slot "from" } "The sender of the e-mail. An e-mail address." }
+ { { $slot "to" } "The recipients of the e-mail. A sequence of e-mail addresses." }
+ { { $slot "cc" } "Carbon-copy. A sequence of e-mail addresses." }
+ { { $slot "bcc" } "Blind carbon-copy. A sequence of e-mail addresses." }
+ { { $slot "subject" } " The subject of the e-mail. A string." }
+ { { $slot "body" } " The body of the e-mail. A string." }
+ }
+"The " { $slot "from" } " and " { $slot "to" } " slots are required; the rest are optional."
+$nl
+"An e-mail address is a string in one of the following two formats:"
+{ $list
+ { $snippet "joe@groff.com" }
+ { $snippet "Joe Groff <joe@groff.com>" }
+} } ;
HELP: <email>
{ $values { "email" email } }
HELP: send-email
{ $values { "email" email } }
-{ $description "Sends an " { $link email } " object to an STMP server stored in the " { $link smtp-server } " variable. The required slots are " { $slot "from" } " and " { $slot "to" } "." }
+{ $description "Sends an e-mail." }
{ $examples
- { $unchecked-example "USING: accessors smtp ;"
+ { $code "USING: accessors smtp ;"
"<email>"
" \"groucho@marx.bros\" >>from"
" { \"chico@marx.bros\" \"harpo@marx.bros\" } >>to"
} ;
ARTICLE: "smtp" "SMTP client library"
-"Configuring SMTP:"
+"The " { $vocab-link "smtp" } " vocabulary sends e-mail via an SMTP server."
+$nl
+"This library is configured by a set of dynamically-scoped variables:"
{ $subsection smtp-server }
+{ $subsection smtp-tls? }
{ $subsection smtp-read-timeout }
{ $subsection smtp-domain }
-{ $subsection esmtp? }
+{ $subsection smtp-auth }
+"The latter is set to an instance of one of the following:"
+{ $subsection no-auth }
+{ $subsection plain-auth }
+"Constructing an e-mail:"
+{ $subsection email }
+{ $subsection <email> }
"Sending an email:"
{ $subsection send-email } ;
+
+ABOUT: "smtp"
-USING: smtp tools.test io.streams.string io.sockets threads
-smtp.server kernel sequences namespaces logging accessors
-assocs sorting smtp.private ;
+USING: smtp tools.test io.streams.string io.sockets
+io.sockets.secure threads smtp.server kernel sequences
+namespaces logging accessors assocs sorting smtp.private
+concurrency.promises system ;
IN: smtp.tests
+\ send-email must-infer
+
{ 0 0 } [ [ ] with-smtp-connection ] must-infer-as
[ "hello\nworld" validate-address ] must-fail
"hello\nworld" [ send-body ] with-string-writer
] unit-test
-[ "500 syntax error" check-response ] must-fail
+[ { "500 syntax error" } <response> check-response ]
+[ smtp-error? ] must-fail-with
-[ ] [ "220 success" check-response ] unit-test
+[ ] [ { "220 success" } <response> check-response ] unit-test
-[ "220 success" ] [
+[ T{ response f 220 { "220 success" } } ] [
"220 success" [ receive-response ] with-string-reader
] unit-test
-[ "220 the end" ] [
+[
+ T{ response f 220 {
+ "220-a multiline response"
+ "250-another line"
+ "220 the end"
+ } }
+] [
"220-a multiline response\r\n250-another line\r\n220 the end"
[ receive-response ] with-string-reader
] unit-test
[ from>> extract-email ] tri
] unit-test
-[ ] [ [ 4321 mock-smtp-server ] "SMTP server" spawn drop ] unit-test
+<promise> "p" set
-[ ] [ yield ] unit-test
+[ ] [ "p" get mock-smtp-server ] unit-test
[ ] [
- [
- "localhost" 4321 <inet> smtp-server set
+ <secure-config> f >>verify [
+ "localhost" "p" get ?promise <inet> smtp-server set
+ no-auth smtp-auth set
+ os unix? [ smtp-tls? on ] when
<email>
"Hi guys\nBye guys" >>body
} >>to
"Doug <erg@factorcode.org>" >>from
send-email
- ] with-scope
+ ] with-secure-context
] unit-test
-
-[ ] [ yield ] unit-test
! Copyright (C) 2007, 2008 Elie CHAFTARI, Dirk Vleugels,
! Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: arrays namespaces make io io.timeouts kernel logging
-io.sockets sequences combinators splitting assocs strings
-math.parser random system calendar io.encodings.ascii summary
-calendar.format accessors sets hashtables ;
+USING: arrays namespaces make io io.encodings.string
+io.encodings.utf8 io.timeouts io.sockets io.sockets.secure
+io.encodings.ascii kernel logging sequences combinators
+splitting assocs strings math.order math.parser random system
+calendar summary calendar.format accessors sets hashtables
+base64 debugger classes prettyprint ;
IN: smtp
SYMBOL: smtp-domain
-SYMBOL: smtp-server "localhost" 25 <inet> smtp-server set-global
-SYMBOL: smtp-read-timeout 1 minutes smtp-read-timeout set-global
-SYMBOL: esmtp? t esmtp? set-global
+
+SYMBOL: smtp-server
+"localhost" 25 <inet> smtp-server set-global
+
+SYMBOL: smtp-tls?
+
+SYMBOL: smtp-read-timeout
+1 minutes smtp-read-timeout set-global
+
+SINGLETON: no-auth
+
+TUPLE: plain-auth username password ;
+C: <plain-auth> plain-auth
+
+SYMBOL: smtp-auth
+no-auth smtp-auth set-global
LOG: log-smtp-connection NOTICE ( addrspec -- )
{ subject string }
{ body string } ;
-: <email> ( -- email ) email new ;
+: <email> ( -- email ) email new ; inline
<PRIVATE
+
: crlf ( -- ) "\r\n" write ;
+: read-crlf ( -- bytes )
+ "\r" read-until
+ [ CHAR: \r assert= read1 CHAR: \n assert= ] when* ;
+
: command ( string -- ) write crlf flush ;
-: helo ( -- )
- esmtp? get "EHLO " "HELO " ? host-name append command ;
+\ command DEBUG add-input-logging
+
+: helo ( -- ) "EHLO " host-name append command ;
+
+: start-tls ( -- ) "STARTTLS" command ;
ERROR: bad-email-address email ;
[ bad-email-address ] unless ;
: mail-from ( fromaddr -- )
- "MAIL FROM:<" swap validate-address ">" 3append command ;
+ validate-address
+ "MAIL FROM:<" ">" surround command ;
: rcpt-to ( to -- )
- "RCPT TO:<" swap validate-address ">" 3append command ;
+ validate-address
+ "RCPT TO:<" ">" surround command ;
: data ( -- )
"DATA" command ;
ERROR: message-contains-dot message ;
M: message-contains-dot summary ( obj -- string )
- drop
- "Message cannot contain . on a line by itself" ;
+ drop "Message cannot contain . on a line by itself" ;
: validate-message ( msg -- msg' )
"." over member?
LOG: smtp-response DEBUG
-ERROR: smtp-error message ;
+: multiline? ( response -- boolean )
+ 3 swap ?nth CHAR: - = ;
+
+: (receive-response) ( -- )
+ read-crlf
+ [ , ]
+ [ smtp-response ]
+ [ multiline? [ (receive-response) ] when ]
+ tri ;
+
+TUPLE: response code messages ;
+
+: <response> ( lines -- response )
+ [ first 3 head string>number ] keep response boa ;
+
+: receive-response ( -- response )
+ [ (receive-response) ] { } make <response> ;
+
+ERROR: smtp-error response ;
+
+M: smtp-error error.
+ "SMTP error (" write dup class pprint ")" print
+ response>> messages>> [ print ] each ;
+
ERROR: smtp-server-busy < smtp-error ;
ERROR: smtp-syntax-error < smtp-error ;
ERROR: smtp-command-not-implemented < smtp-error ;
ERROR: smtp-transaction-failed < smtp-error ;
: check-response ( response -- )
- dup smtp-response
- {
- { [ dup "bye" head? ] [ drop ] }
- { [ dup "220" head? ] [ drop ] }
- { [ dup "235" swap subseq? ] [ drop ] }
- { [ dup "250" head? ] [ drop ] }
- { [ dup "221" head? ] [ drop ] }
- { [ dup "354" head? ] [ drop ] }
- { [ dup "4" head? ] [ smtp-server-busy ] }
- { [ dup "500" head? ] [ smtp-syntax-error ] }
- { [ dup "501" head? ] [ smtp-command-not-implemented ] }
- { [ dup "50" head? ] [ smtp-syntax-error ] }
- { [ dup "53" head? ] [ smtp-bad-authentication ] }
- { [ dup "550" head? ] [ smtp-mailbox-unavailable ] }
- { [ dup "551" head? ] [ smtp-user-not-local ] }
- { [ dup "552" head? ] [ smtp-exceeded-storage-allocation ] }
- { [ dup "553" head? ] [ smtp-bad-mailbox-name ] }
- { [ dup "554" head? ] [ smtp-transaction-failed ] }
- [ smtp-error ]
+ dup code>> {
+ { [ dup { 220 235 250 221 354 } member? ] [ 2drop ] }
+ { [ dup 400 499 between? ] [ drop smtp-server-busy ] }
+ { [ dup 500 = ] [ drop smtp-syntax-error ] }
+ { [ dup 501 = ] [ drop smtp-command-not-implemented ] }
+ { [ dup 500 509 between? ] [ drop smtp-syntax-error ] }
+ { [ dup 530 539 between? ] [ drop smtp-bad-authentication ] }
+ { [ dup 550 = ] [ drop smtp-mailbox-unavailable ] }
+ { [ dup 551 = ] [ drop smtp-user-not-local ] }
+ { [ dup 552 = ] [ drop smtp-exceeded-storage-allocation ] }
+ { [ dup 553 = ] [ drop smtp-bad-mailbox-name ] }
+ { [ dup 554 = ] [ drop smtp-transaction-failed ] }
+ [ drop smtp-error ]
} cond ;
-: multiline? ( response -- boolean )
- 3 swap ?nth CHAR: - = ;
+: get-ok ( -- ) receive-response check-response ;
-: process-multiline ( multiline -- response )
- >r readln r> 2dup " " append head? [
- drop dup smtp-response
- ] [
- swap check-response process-multiline
- ] if ;
+GENERIC: send-auth ( auth -- )
-: receive-response ( -- response )
- readln
- dup multiline? [ 3 head process-multiline ] when ;
+M: no-auth send-auth drop ;
-: get-ok ( -- ) receive-response check-response ;
+: plain-auth-string ( username password -- string )
+ [ "\0" prepend ] bi@ append utf8 encode >base64 ;
+
+M: plain-auth send-auth
+ [ username>> ] [ password>> ] bi plain-auth-string
+ "AUTH PLAIN " prepend command get-ok ;
+
+: auth ( -- ) smtp-auth get send-auth ;
ERROR: invalid-header-string string ;
"<" %
64 random-bits #
"-" %
- millis #
+ micros #
"@" %
smtp-domain get [ host-name ] unless* %
">" %
: extract-email ( recepient -- email )
! This could be much smarter.
- " " last-split1 swap or "<" ?head drop ">" ?tail drop ;
+ " " split1-last swap or "<" ?head drop ">" ?tail drop ;
: email>headers ( email -- hashtable )
[
: (send-email) ( headers email -- )
[
+ get-ok
helo get-ok
+ smtp-tls? get [ start-tls get-ok send-secure-handshake ] when
+ auth
dup from>> extract-email mail-from get-ok
dup to>> [ extract-email rcpt-to get-ok ] each
dup cc>> [ extract-email rcpt-to get-ok ] each
body>> send-body get-ok
quit get-ok
] with-smtp-connection ;
+
PRIVATE>
: send-email ( email -- )
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.alien
+
+<< "void*" define-array >>
\ No newline at end of file
--- /dev/null
+Slava Pestov
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.bool
+
+<< "bool" define-array >>
\ No newline at end of file
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.char
+
+<< "char" define-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.alien specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.alien
+
+<< "void*" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.bool specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.bool
+
+<< "bool" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.char specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.char
+
+<< "char" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: help.markup help.syntax byte-arrays alien ;
+IN: specialized-arrays.direct
+
+ARTICLE: "specialized-arrays.direct" "Direct-mapped specialized arrays"
+"The " { $vocab-link "specialized-arrays.direct" } " vocabulary implements fixed-length sequence types for storing machine values in unmanaged C memory."
+$nl
+"For each primitive C type " { $snippet "T" } ", a set of words are defined:"
+{ $table
+ { { $snippet "direct-T-array" } { "The class of direct arrays with elements of type " { $snippet "T" } } }
+ { { $snippet "<direct-T-array>" } { "Constructor for arrays with elements of type " { $snippet "T" } "; stack effect " { $snippet "( alien len -- array )" } } }
+}
+"Each direct array has a " { $slot "underlying" } " slot holding an " { $link simple-alien } " pointer to the raw data. This data can be passed to C functions."
+$nl
+"The primitive C types for which direct arrays exist:"
+{ $list
+ { $snippet "char" }
+ { $snippet "uchar" }
+ { $snippet "short" }
+ { $snippet "ushort" }
+ { $snippet "int" }
+ { $snippet "uint" }
+ { $snippet "long" }
+ { $snippet "ulong" }
+ { $snippet "longlong" }
+ { $snippet "ulonglong" }
+ { $snippet "float" }
+ { $snippet "double" }
+ { $snippet "void*" }
+ { $snippet "bool" }
+}
+"Direct arrays are generated with a functor in the " { $vocab-link "specialized-arrays.direct.functor" } " vocabulary." ;
+
+ABOUT: "specialized-arrays.direct"
--- /dev/null
+IN: specialized-arrays.direct.tests
+USING: specialized-arrays.direct.ushort tools.test
+specialized-arrays.ushort alien.syntax sequences ;
+
+[ ushort-array{ 0 0 0 } ] [
+ 3 ALIEN: 123 100 <direct-ushort-array> new-sequence
+] unit-test
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+IN: specialized-arrays.direct
--- /dev/null
+USING: specialized-arrays.double specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.double
+
+<< "double" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.float specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.float
+
+<< "float" define-direct-array >>
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: functors sequences sequences.private kernel words classes
+math alien alien.c-types byte-arrays accessors
+specialized-arrays ;
+IN: specialized-arrays.direct.functor
+
+FUNCTOR: define-direct-array ( T -- )
+
+A' IS ${T}-array
+>A' IS >${T}-array
+<A'> IS <${A'}>
+
+A DEFINES direct-${T}-array
+<A> DEFINES <${A}>
+
+NTH [ T dup c-getter array-accessor ]
+SET-NTH [ T dup c-setter array-accessor ]
+
+WHERE
+
+TUPLE: A
+{ underlying c-ptr read-only }
+{ length fixnum read-only } ;
+
+: <A> ( alien len -- direct-array ) A boa ; inline
+M: A length length>> ;
+M: A nth-unsafe underlying>> NTH call ;
+M: A set-nth-unsafe underlying>> SET-NTH call ;
+M: A like drop dup A instance? [ >A' execute ] unless ;
+M: A new-sequence drop <A'> execute ;
+
+INSTANCE: A sequence
+
+;FUNCTOR
--- /dev/null
+USING: specialized-arrays.int specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.int
+
+<< "int" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.long specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.long
+
+<< "long" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.longlong specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.longlong
+
+<< "longlong" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.short specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.short
+
+<< "short" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.uchar specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.uchar
+
+<< "uchar" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.uint specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.uint
+
+<< "uint" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.ulong specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.ulong
+
+<< "ulong" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.ulonglong specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.ulonglong
+
+<< "ulonglong" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-arrays.ushort specialized-arrays.direct.functor ;
+IN: specialized-arrays.direct.ushort
+
+<< "ushort" define-direct-array >>
\ No newline at end of file
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.double
+
+<< "double" define-array >>
+
+! Specializer hints. These should really be generalized, and placed
+! somewhere else
+USING: hints math.vectors arrays kernel math accessors sequences ;
+
+HINTS: <double-array> { 2 } { 3 } ;
+
+HINTS: (double-array) { 2 } { 3 } ;
+
+HINTS: vneg { array } { double-array } ;
+HINTS: v*n { array object } { double-array float } ;
+HINTS: n*v { array object } { float double-array } ;
+HINTS: v/n { array object } { double-array float } ;
+HINTS: n/v { object array } { float double-array } ;
+HINTS: v+ { array array } { double-array double-array } ;
+HINTS: v- { array array } { double-array double-array } ;
+HINTS: v* { array array } { double-array double-array } ;
+HINTS: v/ { array array } { double-array double-array } ;
+HINTS: vmax { array array } { double-array double-array } ;
+HINTS: vmin { array array } { double-array double-array } ;
+HINTS: v. { array array } { double-array double-array } ;
+HINTS: norm-sq { array } { double-array } ;
+HINTS: norm { array } { double-array } ;
+HINTS: normalize { array } { double-array } ;
+HINTS: distance { array array } { double-array double-array } ;
+
+! Type functions
+USING: words classes.algebra compiler.tree.propagation.info
+math.intervals ;
+
+{ v+ v- v* v/ vmax vmin } [
+ [
+ [ class>> double-array class<= ] both?
+ double-array object ? <class-info>
+ ] "outputs" set-word-prop
+] each
+
+{ n*v n/v } [
+ [
+ nip class>> double-array class<= double-array object ? <class-info>
+ ] "outputs" set-word-prop
+] each
+
+{ v*n v/n } [
+ [
+ drop class>> double-array class<= double-array object ? <class-info>
+ ] "outputs" set-word-prop
+] each
+
+{ vneg normalize } [
+ [
+ class>> double-array class<= double-array object ? <class-info>
+ ] "outputs" set-word-prop
+] each
+
+\ norm-sq [
+ class>> double-array class<= [ float 0. 1/0. [a,b] <class/interval-info> ] [ object-info ] if
+] "outputs" set-word-prop
+
+\ v. [
+ [ class>> double-array class<= ] both?
+ float object ? <class-info>
+] "outputs" set-word-prop
+
+\ distance [
+ [ class>> double-array class<= ] both?
+ [ float 0. 1/0. [a,b] <class/interval-info> ] [ object-info ] if
+] "outputs" set-word-prop
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.float
+
+<< "float" define-array >>
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: functors sequences sequences.private prettyprint.custom
+kernel words classes math parser alien.c-types byte-arrays
+accessors summary ;
+IN: specialized-arrays.functor
+
+ERROR: bad-byte-array-length byte-array type ;
+
+M: bad-byte-array-length summary
+ drop "Byte array length doesn't divide type width" ;
+
+: (c-array) ( n c-type -- array )
+ heap-size * (byte-array) ; inline
+
+FUNCTOR: define-array ( T -- )
+
+A DEFINES ${T}-array
+<A> DEFINES <${A}>
+(A) DEFINES (${A})
+>A DEFINES >${A}
+byte-array>A DEFINES byte-array>${A}
+A{ DEFINES ${A}{
+
+NTH [ T dup c-getter array-accessor ]
+SET-NTH [ T dup c-setter array-accessor ]
+
+WHERE
+
+TUPLE: A
+{ length array-capacity read-only }
+{ underlying byte-array read-only } ;
+
+: <A> ( n -- specialized-array ) dup T <c-array> A boa ; inline
+
+: (A) ( n -- specialized-array ) dup T (c-array) A boa ; inline
+
+: byte-array>A ( byte-array -- specialized-array )
+ dup length T heap-size /mod 0 = [ drop T bad-byte-array-length ] unless
+ swap A boa ; inline
+
+M: A clone [ length>> ] [ underlying>> clone ] bi A boa ;
+
+M: A length length>> ;
+
+M: A nth-unsafe underlying>> NTH call ;
+
+M: A set-nth-unsafe underlying>> SET-NTH call ;
+
+: >A ( seq -- specialized-array ) A new clone-like ; inline
+
+M: A like drop dup A instance? [ >A execute ] unless ;
+
+M: A new-sequence drop (A) execute ;
+
+M: A equal? over A instance? [ sequence= ] [ 2drop f ] if ;
+
+M: A resize
+ [ drop ] [
+ [ T heap-size * ] [ underlying>> ] bi*
+ resize-byte-array
+ ] 2bi
+ A boa ;
+
+M: A byte-length underlying>> length ;
+
+M: A pprint-delims drop A{ \ } ;
+
+M: A >pprint-sequence ;
+
+M: A pprint* pprint-object ;
+
+: A{ \ } [ >A execute ] parse-literal ; parsing
+
+INSTANCE: A sequence
+
+;FUNCTOR
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.int
+
+<< "int" define-array >>
\ No newline at end of file
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.long
+
+<< "long" define-array >>
\ No newline at end of file
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.longlong
+
+<< "longlong" define-array >>
\ No newline at end of file
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.short
+
+<< "short" define-array >>
\ No newline at end of file
--- /dev/null
+USING: help.markup help.syntax byte-arrays ;
+IN: specialized-arrays
+
+ARTICLE: "specialized-arrays" "Specialized arrays"
+"The " { $vocab-link "specialized-arrays" } " vocabulary implements fixed-length sequence types for storing machine values in a space-efficient manner without boxing."
+$nl
+"For each primitive C type " { $snippet "T" } ", a set of words are defined in the vocabulary named " { $snippet "specialized-arrays.T" } ":"
+{ $table
+ { { $snippet "T-array" } { "The class of arrays with elements of type " { $snippet "T" } } }
+ { { $snippet "<T-array>" } { "Constructor for arrays with elements of type " { $snippet "T" } "; stack effect " { $snippet "( len -- array )" } } }
+ { { $snippet ">T-array" } { "Converts a sequence into a specialized array of type " { $snippet "T" } "; stack effect " { $snippet "( seq -- array )" } } }
+ { { $snippet "byte-array>T-array" } { "Converts a byte array into a specialized array by interpreting the bytes in as machine-specific values. Code which uses this word is unportable" } }
+ { { $snippet "T-array{" } { "Literal syntax, consists of a series of values terminated by " { $snippet "}" } } }
+}
+"Each specialized array has a " { $slot "underlying" } " slot holding a " { $link byte-array } " with the raw data. This data can be passed to C functions."
+$nl
+"The primitive C types for which specialized arrays exist:"
+{ $list
+ { $snippet "char" }
+ { $snippet "uchar" }
+ { $snippet "short" }
+ { $snippet "ushort" }
+ { $snippet "int" }
+ { $snippet "uint" }
+ { $snippet "long" }
+ { $snippet "ulong" }
+ { $snippet "longlong" }
+ { $snippet "ulonglong" }
+ { $snippet "float" }
+ { $snippet "double" }
+ { $snippet "void*" }
+ { $snippet "bool" }
+}
+"Note that " { $vocab-link "specialized-arrays.bool" } " behaves like a C " { $snippet "bool[]" } " array, and each element takes up 8 bits of space. For a more space-efficient boolean array, see " { $link "bit-arrays" } "."
+$nl
+"Specialized arrays are generated with a functor in the " { $vocab-link "specialized-arrays.functor" } " vocabulary."
+$nl
+"The " { $vocab-link "specialized-vectors" } " vocabulary provides resizable versions of the above." ;
+
+ABOUT: "specialized-arrays"
--- /dev/null
+IN: specialized-arrays.tests
+USING: tools.test specialized-arrays sequences
+specialized-arrays.int specialized-arrays.bool
+specialized-arrays.ushort alien.c-types accessors kernel ;
+
+[ t ] [ { 1 2 3 } >int-array int-array? ] unit-test
+
+[ t ] [ int-array{ 1 2 3 } int-array? ] unit-test
+
+[ 2 ] [ int-array{ 1 2 3 } second ] unit-test
+
+[ t ] [ { t f t } >bool-array underlying>> { 1 0 1 } >int-array underlying>> = ] unit-test
+
+[ ushort-array{ 1234 } ] [
+ little-endian? B{ 210 4 } B{ 4 210 } ? byte-array>ushort-array
+] unit-test
+
+[ B{ 210 4 1 } byte-array>ushort-array ] must-fail
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+IN: specialized-arrays
--- /dev/null
+Arrays of unboxed primitive C types
--- /dev/null
+collections
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.uchar
+
+<< "uchar" define-array >>
\ No newline at end of file
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.uint
+
+<< "uint" define-array >>
\ No newline at end of file
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.ulong
+
+<< "ulong" define-array >>
\ No newline at end of file
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.ulonglong
+
+<< "ulonglong" define-array >>
\ No newline at end of file
--- /dev/null
+USE: specialized-arrays.functor
+IN: specialized-arrays.ushort
+
+<< "ushort" define-array >>
\ No newline at end of file
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.alien ;
+IN: specialized-vectors.alien
+
+<< "void*" define-vector >>
\ No newline at end of file
--- /dev/null
+Slava Pestov
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.bool ;
+IN: specialized-vectors.bool
+
+<< "bool" define-vector >>
\ No newline at end of file
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.char ;
+IN: specialized-vectors.char
+
+<< "char" define-vector >>
\ No newline at end of file
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.double ;
+IN: specialized-vectors.double
+
+<< "double" define-vector >>
\ No newline at end of file
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.float ;
+IN: specialized-vectors.float
+
+<< "float" define-vector >>
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: functors sequences sequences.private growable
+prettyprint.custom kernel words classes math parser ;
+IN: specialized-vectors.functor
+
+FUNCTOR: define-vector ( T -- )
+
+A IS ${T}-array
+<A> IS <${A}>
+
+V DEFINES ${T}-vector
+<V> DEFINES <${V}>
+>V DEFINES >${V}
+V{ DEFINES ${V}{
+
+WHERE
+
+TUPLE: V { underlying A } { length array-capacity } ;
+
+: <V> <A> execute 0 V boa ; inline
+
+M: V like
+ drop dup V instance? [
+ dup A instance? [ dup length V boa ] [ >V execute ] if
+ ] unless ;
+
+M: V new-sequence drop [ <A> execute ] [ >fixnum ] bi V boa ;
+
+M: A new-resizable drop <V> execute ;
+
+M: V equal? over V instance? [ sequence= ] [ 2drop f ] if ;
+
+: >V V new clone-like ; inline
+
+M: V pprint-delims drop V{ \ } ;
+
+M: V >pprint-sequence ;
+
+M: V pprint* pprint-object ;
+
+: V{ \ } [ >V execute ] parse-literal ; parsing
+
+INSTANCE: V growable
+
+;FUNCTOR
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.int ;
+IN: specialized-vectors.int
+
+<< "int" define-vector >>
\ No newline at end of file
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.long ;
+IN: specialized-vectors.long
+
+<< "long" define-vector >>
\ No newline at end of file
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.longlong ;
+IN: specialized-vectors.longlong
+
+<< "longlong" define-vector >>
\ No newline at end of file
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.short ;
+IN: specialized-vectors.short
+
+<< "short" define-vector >>
\ No newline at end of file
--- /dev/null
+USING: help.markup help.syntax byte-vectors ;
+IN: specialized-vectors
+
+ARTICLE: "specialized-vectors" "Specialized vectors"
+"The " { $vocab-link "specialized-vectors" } " vocabulary implements resizable sequence types for storing machine values in a space-efficient manner without boxing."
+$nl
+"For each primitive C type " { $snippet "T" } ", a set of words are defined:"
+{ $table
+ { { $snippet "T-vector" } { "The class of vectors with elements of type " { $snippet "T" } } }
+ { { $snippet "<T-vector>" } { "Constructor for vectors with elements of type " { $snippet "T" } "; stack effect " { $snippet "( len -- vector )" } } }
+ { { $snippet ">T-vector" } { "Converts a sequence into a specialized vector of type " { $snippet "T" } "; stack effect " { $snippet "( seq -- vector )" } } }
+ { { $snippet "T-vector{" } { "Literal syntax, consists of a series of values terminated by " { $snippet "}" } } }
+}
+"The primitive C types for which specialized vectors exist:"
+{ $list
+ { $snippet "char" }
+ { $snippet "uchar" }
+ { $snippet "short" }
+ { $snippet "ushort" }
+ { $snippet "int" }
+ { $snippet "uint" }
+ { $snippet "long" }
+ { $snippet "ulong" }
+ { $snippet "longlong" }
+ { $snippet "ulonglong" }
+ { $snippet "float" }
+ { $snippet "double" }
+ { $snippet "void*" }
+ { $snippet "bool" }
+}
+"Specialized vectors are generated with a functor in the " { $vocab-link "specialized-vectors.functor" } " vocabulary."
+$nl
+"The " { $vocab-link "specialized-arrays" } " vocabulary provides fixed-length versions of the above." ;
+
+ABOUT: "specialized-vectors"
--- /dev/null
+IN: specialized-vectors.tests
+USING: specialized-vectors.double tools.test kernel sequences ;
+
+[ 3 ] [ double-vector{ 1 2 } 3 over push length ] unit-test
+
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+IN: specialized-vectors
--- /dev/null
+Vectors of unboxed primitive C types
--- /dev/null
+collections
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.uchar ;
+IN: specialized-vectors.uchar
+
+<< "uchar" define-vector >>
\ No newline at end of file
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.uint ;
+IN: specialized-vectors.uint
+
+<< "uint" define-vector >>
\ No newline at end of file
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.ulong ;
+IN: specialized-vectors.ulong
+
+<< "ulong" define-vector >>
\ No newline at end of file
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.ulonglong ;
+IN: specialized-vectors.ulonglong
+
+<< "ulonglong" define-vector >>
\ No newline at end of file
--- /dev/null
+USING: specialized-vectors.functor specialized-arrays.ushort ;
+IN: specialized-vectors.ushort
+
+<< "ushort" define-vector >>
\ No newline at end of file
IN: stack-checker.backend.tests
[ ] [
- V{ } clone meta-d set
- V{ } clone meta-r set
+ V{ } clone \ meta-d set
+ V{ } clone \ meta-r set
+ V{ } clone \ literals set
0 d-in set
] unit-test
[ 0 ] [ 0 ensure-d length ] unit-test
[ 2 ] [ 2 ensure-d length ] unit-test
-[ 2 ] [ meta-d get length ] unit-test
+[ 2 ] [ meta-d length ] unit-test
[ 3 ] [ 3 ensure-d length ] unit-test
-[ 3 ] [ meta-d get length ] unit-test
+[ 3 ] [ meta-d length ] unit-test
[ 1 ] [ 1 ensure-d length ] unit-test
-[ 3 ] [ meta-d get length ] unit-test
+[ 3 ] [ meta-d length ] unit-test
[ ] [ 1 consume-d drop ] unit-test
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: fry arrays generic io io.streams.string kernel math
-namespaces parser prettyprint sequences strings vectors words
-quotations effects classes continuations debugger assocs
-combinators compiler.errors accessors math.order definitions
-sets generic.standard.engines.tuple stack-checker.state
-stack-checker.visitor stack-checker.errors
-stack-checker.values stack-checker.recursive-state ;
+namespaces parser sequences strings vectors words quotations
+effects classes continuations assocs combinators
+compiler.errors accessors math.order definitions sets
+generic.standard.engines.tuple hints stack-checker.state
+stack-checker.visitor stack-checker.errors stack-checker.values
+stack-checker.recursive-state ;
IN: stack-checker.backend
-: push-d ( obj -- ) meta-d get push ;
+: push-d ( obj -- ) meta-d push ;
: pop-d ( -- obj )
- meta-d get [
+ meta-d [
<value> dup 1array #introduce, d-in inc
] [ pop ] if-empty ;
[ <value> ] replicate ;
: ensure-d ( n -- values )
- meta-d get 2dup length > [
+ meta-d 2dup length > [
2dup
[ nip >array ] [ length - make-values ] [ nip delete-all ] 2tri
- [ length d-in +@ ] [ #introduce, ] [ meta-d get push-all ] tri
- meta-d get push-all
+ [ length d-in +@ ] [ #introduce, ] [ meta-d push-all ] tri
+ meta-d push-all
] when swap tail* ;
: shorten-by ( n seq -- )
[ length swap - ] keep shorten ; inline
: consume-d ( n -- seq )
- [ ensure-d ] [ meta-d get shorten-by ] bi ;
+ [ ensure-d ] [ meta-d shorten-by ] bi ;
-: output-d ( values -- ) meta-d get push-all ;
+: output-d ( values -- ) meta-d push-all ;
: produce-d ( n -- values )
- make-values dup meta-d get push-all ;
+ make-values dup meta-d push-all ;
-: push-r ( obj -- ) meta-r get push ;
+: push-r ( obj -- ) meta-r push ;
-: pop-r ( -- obj )
- meta-r get dup empty?
+: pop-r ( -- obj )
+ meta-r dup empty?
[ too-many-r> inference-error ] [ pop ] if ;
: consume-r ( n -- seq )
- meta-r get 2dup length >
+ meta-r 2dup length >
[ too-many-r> inference-error ] when
[ swap tail* ] [ shorten-by ] 2bi ;
-: output-r ( seq -- ) meta-r get push-all ;
+: output-r ( seq -- ) meta-r push-all ;
+
+: push-literal ( obj -- )
+ literals get push ;
: pop-literal ( -- rstate obj )
- pop-d
- [ 1array #drop, ]
- [ literal [ recursion>> ] [ value>> ] bi ] bi ;
+ literals get [
+ pop-d
+ [ 1array #drop, ]
+ [ literal [ recursion>> ] [ value>> ] bi ] bi
+ ] [ pop recursive-state get swap ] if-empty ;
-GENERIC: apply-object ( obj -- )
+: literals-available? ( n -- literals ? )
+ literals get 2dup length <=
+ [ [ swap tail* ] [ shorten-by ] 2bi t ] [ 2drop f f ] if ;
-: push-literal ( obj -- )
- dup <literal> make-known [ nip push-d ] [ #push, ] 2bi ;
+GENERIC: apply-object ( obj -- )
M: wrapper apply-object
wrapped>>
M: object apply-object push-literal ;
: terminate ( -- )
- terminated? on meta-d get clone meta-r get clone #terminate, ;
+ terminated? on meta-d clone meta-r clone #terminate, ;
+
+: check->r ( -- )
+ meta-r empty? [ \ too-many->r inference-error ] unless ;
: infer-quot-here ( quot -- )
- [ apply-object terminated? get not ] all? drop ;
+ meta-r [
+ V{ } clone \ meta-r set
+ [ apply-object terminated? get not ] all?
+ [ commit-literals check->r ] [ literals get delete-all ] if
+ ] dip \ meta-r set ;
: infer-quot ( quot rstate -- )
recursive-state get [
] if ;
: infer->r ( n -- )
- consume-d dup copy-values [ #>r, ] [ nip output-r ] 2bi ;
+ consume-d dup copy-values [ nip output-r ] [ #>r, ] 2bi ;
: infer-r> ( n -- )
- consume-r dup copy-values [ #r>, ] [ nip output-d ] 2bi ;
+ consume-r dup copy-values [ nip output-d ] [ #r>, ] 2bi ;
: undo-infer ( -- )
recorded get [ f "inferred-effect" set-word-prop ] each ;
] 2bi ; inline
: infer-word-def ( word -- )
- [ def>> ] [ add-recursive-state ] bi infer-quot ;
-
-: check->r ( -- )
- meta-r get empty? terminated? get or
- [ \ too-many->r inference-error ] unless ;
+ [ specialized-def ] [ add-recursive-state ] bi infer-quot ;
: end-infer ( -- )
- check->r
- meta-d get clone #return, ;
+ meta-d clone #return, ;
: effect-required? ( word -- ? )
{
{ [ dup inline? ] [ drop f ] }
{ [ dup deferred? ] [ drop f ] }
{ [ dup crossref? not ] [ drop f ] }
- [ def>> [ [ word? ] [ primitive? not ] bi and ] contains? ]
+ [ def>> [ word? ] contains? ]
} cond ;
: ?missing-effect ( word -- )
branch-variable ;
: datastack-phi ( seq -- phi-in phi-out )
- [ d-in branch-variable ] [ meta-d active-variable ] bi
+ [ d-in branch-variable ] [ \ meta-d active-variable ] bi
unify-branches
- [ d-in set ] [ ] [ dup >vector meta-d set ] tri* ;
+ [ d-in set ] [ ] [ dup >vector \ meta-d set ] tri* ;
: terminated-phi ( seq -- terminated )
terminated? branch-variable ;
tri ;
: copy-inference ( -- )
- meta-d [ clone ] change
- V{ } clone meta-r set
+ \ meta-d [ clone ] change
+ literals [ clone ] change
d-in [ ] change ;
-: infer-branch ( literal -- namespace )
+GENERIC: infer-branch ( literal -- namespace )
+
+M: literal infer-branch
[
copy-inference
nest-visitor
[ value>> quotation set ] [ infer-literal-quot ] bi
- check->r
- ] H{ } make-assoc ; inline
+ ] H{ } make-assoc ;
+
+M: callable infer-branch
+ [
+ copy-inference
+ nest-visitor
+ [ quotation set ] [ infer-quot-here ] bi
+ ] H{ } make-assoc ;
: infer-branches ( branches -- input children data )
[ pop-d ] dip
[ first2 #if, ] dip compute-phi-function ;
: infer-if ( -- )
- 2 consume-d
- dup [ known [ curried? ] [ composed? ] bi or ] contains? [
- output-d
- [ rot [ drop call ] [ nip call ] if ]
- infer-quot-here
+ 2 literals-available? [
+ (infer-if)
] [
- [ #drop, ] [ [ literal ] map (infer-if) ] bi
+ drop 2 consume-d
+ dup [ known [ curried? ] [ composed? ] bi or ] contains? [
+ output-d
+ [ rot [ drop call ] [ nip call ] if ]
+ infer-quot-here
+ ] [
+ [ #drop, ] [ [ literal ] map (infer-if) ] bi
+ ] if
] if ;
: infer-dispatch ( -- )
- pop-literal nip [ <literal> ] map
- infer-branches
+ pop-literal nip infer-branches
[ #dispatch, ] dip compute-phi-function ;
{ $subsection inconsistent-recursive-call-error }
"Retain stack usage errors:"
{ $subsection too-many->r }
-{ $subsection too-many-r> }
-"See " { $link "shuffle-words" } " for retain stack usage conventions. This error can only occur if your code calls " { $link >r } " and " { $link r> } " directly. The " { $link dip } " combinator is safer to use because there is no way to leave the retain stack in an unbalanced state." ;
+{ $subsection too-many-r> } ;
ABOUT: "inference-errors"
! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel generic sequences prettyprint io words arrays
-summary effects debugger assocs accessors namespaces
-compiler.errors stack-checker.values
+USING: kernel generic sequences io words arrays summary effects
+assocs accessors namespaces compiler.errors stack-checker.values
stack-checker.recursive-state ;
IN: stack-checker.errors
M: inference-error compiler-error-type type>> ;
-M: inference-error error-help error>> error-help ;
-
: (inference-error) ( ... class type -- * )
- >r boa r>
+ [ boa ] dip
recursive-state get word>>
\ inference-error boa throw ; inline
: inference-warning ( ... class -- * )
+warning+ (inference-error) ; inline
-M: inference-error error.
- [ word>> [ "In word: " write . ] when* ] [ error>> error. ] bi ;
-
TUPLE: literal-expected ;
-M: literal-expected summary
- drop "Literal value expected" ;
-
M: object (literal) \ literal-expected inference-warning ;
TUPLE: unbalanced-branches-error branches quots ;
: unbalanced-branches-error ( branches quots -- * )
\ unbalanced-branches-error inference-error ;
-M: unbalanced-branches-error error.
- "Unbalanced branches:" print
- [ quots>> ] [ branches>> [ length <effect> ] { } assoc>map ] bi zip
- [ [ first pprint-short bl ] [ second effect>string print ] bi ] each ;
-
TUPLE: too-many->r ;
-M: too-many->r summary
- drop
- "Quotation pushes elements on retain stack without popping them" ;
-
TUPLE: too-many-r> ;
-M: too-many-r> summary
- drop
- "Quotation pops retain stack elements which it did not push" ;
-
TUPLE: missing-effect word ;
-M: missing-effect error.
- "The word " write
- word>> pprint
- " must declare a stack effect" print ;
-
TUPLE: effect-error word inferred declared ;
: effect-error ( word inferred declared -- * )
\ effect-error inference-error ;
-M: effect-error error.
- "Stack effects of the word " write
- [ word>> pprint " do not match." print ]
- [ "Inferred: " write inferred>> . ]
- [ "Declared: " write declared>> . ] tri ;
-
TUPLE: recursive-quotation-error quot ;
-M: recursive-quotation-error error.
- "The quotation " write
- quot>> pprint
- " calls itself." print
- "Stack effect inference is undecidable when quotation-level recursion is permitted." print ;
-
TUPLE: undeclared-recursion-error word ;
-M: undeclared-recursion-error error.
- "The inline recursive word " write
- word>> pprint
- " must be declared recursive" print ;
-
TUPLE: diverging-recursion-error word ;
-M: diverging-recursion-error error.
- "The recursive word " write
- word>> pprint
- " digs arbitrarily deep into the stack" print ;
-
TUPLE: unbalanced-recursion-error word height ;
-M: unbalanced-recursion-error error.
- "The recursive word " write
- word>> pprint
- " leaves with the stack having the wrong height" print ;
-
TUPLE: inconsistent-recursive-call-error word ;
-M: inconsistent-recursive-call-error error.
- "The recursive word " write
- word>> pprint
- " calls itself with a different set of quotation parameters than were input" print ;
+TUPLE: unknown-primitive-error ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel prettyprint io debugger
+sequences assocs stack-checker.errors summary effects ;
+IN: stack-checker.errors.prettyprint
+
+M: inference-error error-help error>> error-help ;
+
+M: inference-error error.
+ [ word>> [ "In word: " write . ] when* ] [ error>> error. ] bi ;
+
+M: literal-expected summary
+ drop "Literal value expected" ;
+
+M: unbalanced-branches-error error.
+ "Unbalanced branches:" print
+ [ quots>> ] [ branches>> [ length <effect> ] { } assoc>map ] bi zip
+ [ [ first pprint-short bl ] [ second effect>string print ] bi ] each ;
+
+M: too-many->r summary
+ drop
+ "Quotation pushes elements on retain stack without popping them" ;
+
+M: too-many-r> summary
+ drop
+ "Quotation pops retain stack elements which it did not push" ;
+
+M: missing-effect error.
+ "The word " write
+ word>> pprint
+ " must declare a stack effect" print ;
+
+M: effect-error error.
+ "Stack effects of the word " write
+ [ word>> pprint " do not match." print ]
+ [ "Inferred: " write inferred>> . ]
+ [ "Declared: " write declared>> . ] tri ;
+
+M: recursive-quotation-error error.
+ "The quotation " write
+ quot>> pprint
+ " calls itself." print
+ "Stack effect inference is undecidable when quotation-level recursion is permitted." print ;
+
+M: undeclared-recursion-error error.
+ "The inline recursive word " write
+ word>> pprint
+ " must be declared recursive" print ;
+
+M: diverging-recursion-error error.
+ "The recursive word " write
+ word>> pprint
+ " digs arbitrarily deep into the stack" print ;
+
+M: unbalanced-recursion-error error.
+ "The recursive word " write
+ word>> pprint
+ " leaves with the stack having the wrong height" print ;
+
+M: inconsistent-recursive-call-error error.
+ "The recursive word " write
+ word>> pprint
+ " calls itself with a different set of quotation parameters than were input" print ;
+
+M: unknown-primitive-error error.
+ drop
+ "Cannot determine stack effect statically" print ;
! See http://factorcode.org/license.txt for BSD license.
USING: fry namespaces assocs kernel sequences words accessors
definitions math math.order effects classes arrays combinators
-vectors arrays
+vectors arrays hints
stack-checker.state
stack-checker.errors
stack-checker.values
! having to handle recursive inline words.
: infer-inline-word-def ( word label -- )
- [ drop def>> ] [ add-inline-word ] 2bi infer-quot ;
+ [ drop specialized-def ] [ add-inline-word ] 2bi infer-quot ;
TUPLE: inline-recursive < identity-tuple
id
: prepare-stack ( word -- )
required-stack-effect in>>
[ length ensure-d drop ] [
- meta-d get clone enter-in set
- meta-d get swap make-copies enter-out set
+ meta-d clone enter-in set
+ meta-d swap make-copies enter-out set
] bi ;
: emit-enter-recursive ( label -- )
enter-out get >>enter-out
enter-in get enter-out get #enter-recursive,
- enter-out get >vector meta-d set ;
+ enter-out get >vector \ meta-d set ;
: entry-stack-height ( label -- stack )
enter-out>> length ;
: end-recursive-word ( word label -- )
[ check-return ]
- [ meta-d get dup copy-values dup meta-d set #return-recursive, ]
+ [ meta-d dup copy-values dup \ meta-d set #return-recursive, ]
bi ;
: recursive-word-inputs ( label -- n )
[ nip ]
2tri
- check->r
-
dup recursive-word-inputs
- meta-d get
+ meta-d
stack-visitor get
terminated? get
] with-scope ;
swap word>> required-stack-effect in>> length tail* ;
: call-site-stack ( label -- stack )
- meta-d get trim-stack ;
+ meta-d trim-stack ;
: trimmed-enter-out ( label -- stack )
dup enter-out>> trim-stack ;
: adjust-stack-effect ( effect -- effect' )
[ in>> ] [ out>> ] bi
- meta-d get length pick length [-]
+ meta-d length pick length [-]
object <repetition> '[ _ prepend ] bi@
<effect> ;
] [ drop undeclared-recursion-error inference-error ] if ;
: inline-word ( word -- )
+ commit-literals
[ inlined-dependency depends-on ]
[
dup inline-recursive-label [
hashtables hashtables.private io io.backend io.files
io.files.private io.streams.c kernel kernel.private math
math.private memory namespaces namespaces.private parser
-prettyprint quotations quotations.private sbufs sbufs.private
+quotations quotations.private sbufs sbufs.private
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 locals.backend locals.private words.private
+combinators locals locals.backend locals.types words.private
quotations.private stack-checker.values
stack-checker.alien
stack-checker.state
GENERIC: infer-call* ( value known -- )
-: infer-call ( value -- ) dup known infer-call* ;
+: (infer-call) ( value -- ) dup known infer-call* ;
+
+: infer-call ( -- ) pop-d (infer-call) ;
M: literal infer-call*
[ 1array #drop, ] [ infer-literal-quot ] bi* ;
[ uncurry ] infer-quot-here
[ quot>> known pop-d [ set-known ] keep ]
[ obj>> known pop-d [ set-known ] keep ] bi
- push-d infer-call ;
+ push-d (infer-call) ;
M: composed infer-call*
swap push-d
[ quot2>> known pop-d [ set-known ] keep ]
[ quot1>> known pop-d [ set-known ] keep ] bi
push-d push-d
- 1 infer->r pop-d infer-call
- terminated? get [ 1 infer-r> pop-d infer-call ] unless ;
+ 1 infer->r infer-call
+ terminated? get [ 1 infer-r> infer-call ] unless ;
M: object infer-call*
\ literal-expected inference-warning ;
+: infer-slip ( -- )
+ 1 infer->r infer-call 1 infer-r> ;
+
+: infer-2slip ( -- )
+ 2 infer->r infer-call 2 infer-r> ;
+
+: infer-3slip ( -- )
+ 3 infer->r infer-call 3 infer-r> ;
+
+: infer-dip ( -- )
+ literals get
+ [ \ dip def>> infer-quot-here ]
+ [ pop 1 infer->r infer-quot-here 1 infer-r> ]
+ if-empty ;
+
+: infer-2dip ( -- )
+ literals get
+ [ \ 2dip def>> infer-quot-here ]
+ [ pop 2 infer->r infer-quot-here 2 infer-r> ]
+ if-empty ;
+
+: infer-3dip ( -- )
+ literals get
+ [ \ 3dip def>> infer-quot-here ]
+ [ pop 3 infer->r infer-quot-here 3 infer-r> ]
+ if-empty ;
+
: infer-curry ( -- )
2 consume-d
dup first2 <curried> make-known
: infer-load-locals ( -- )
pop-literal nip
- consume-d dup reverse copy-values dup output-r
- [ [ f f ] dip ] [ reverse swap zip ] 2bi #shuffle, ;
+ consume-d dup copy-values dup output-r
+ [ [ f f ] dip ] [ swap zip ] 2bi #shuffle, ;
: infer-get-local ( -- )
- [let* | n [ pop-literal nip ]
+ [let* | n [ pop-literal nip 1 swap - ]
in-r [ n consume-r ]
out-d [ in-r first copy-value 1array ]
out-r [ in-r copy-values ] |
{ \ >r [ 1 infer->r ] }
{ \ r> [ 1 infer-r> ] }
{ \ declare [ infer-declare ] }
- { \ call [ pop-d infer-call ] }
- { \ (call) [ pop-d infer-call ] }
+ { \ call [ infer-call ] }
+ { \ (call) [ infer-call ] }
+ { \ slip [ infer-slip ] }
+ { \ 2slip [ infer-2slip ] }
+ { \ 3slip [ infer-3slip ] }
+ { \ dip [ infer-dip ] }
+ { \ 2dip [ infer-2dip ] }
+ { \ 3dip [ infer-3dip ] }
{ \ curry [ infer-curry ] }
{ \ compose [ infer-compose ] }
{ \ execute [ infer-execute ] }
{ \ load-locals [ infer-load-locals ] }
{ \ get-local [ infer-get-local ] }
{ \ drop-locals [ infer-drop-locals ] }
- { \ do-primitive [ \ do-primitive cannot-infer-effect ] }
+ { \ do-primitive [ unknown-primitive-error inference-warning ] }
{ \ alien-invoke [ infer-alien-invoke ] }
{ \ alien-indirect [ infer-alien-indirect ] }
{ \ alien-callback [ infer-alien-callback ] }
: infer-local-writer ( word -- )
(( value -- )) apply-word/effect ;
+: infer-local-word ( word -- )
+ "local-word-def" word-prop infer-quot-here ;
+
{
- >r r> declare call (call) curry compose execute (execute) if
-dispatch <tuple-boa> (throw) load-locals get-local drop-locals
-do-primitive alien-invoke alien-indirect alien-callback
+ >r r> declare call (call) slip 2slip 3slip dip 2dip 3dip
+ curry compose execute (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 }
{ [ dup local? ] [ infer-local-reader ] }
{ [ dup local-reader? ] [ infer-local-reader ] }
{ [ dup local-writer? ] [ infer-local-writer ] }
+ { [ dup local-word? ] [ infer-local-word ] }
{ [ dup recursive-word? ] [ call-recursive-word ] }
[ dup infer-word apply-word/effect ]
} cond ;
\ <complex> { real real } { complex } define-primitive
\ <complex> make-foldable
+\ both-fixnums? { object object } { object } define-primitive
+
\ fixnum+ { fixnum fixnum } { integer } define-primitive
\ fixnum+ make-foldable
\ code-room { } { integer integer integer integer } define-primitive
\ code-room make-flushable
-\ millis { } { integer } define-primitive
-\ millis make-flushable
+\ micros { } { integer } define-primitive
+\ micros make-flushable
\ tag { object } { fixnum } define-primitive
\ tag make-foldable
\ <byte-array> { integer } { byte-array } define-primitive
\ <byte-array> make-flushable
+\ (byte-array) { integer } { byte-array } define-primitive
+\ (byte-array) make-flushable
+
\ <displaced-alien> { integer c-ptr } { c-ptr } define-primitive
\ <displaced-alien> make-flushable
\ string-nth { fixnum string } { fixnum } define-primitive
\ string-nth make-flushable
-\ set-string-nth { fixnum fixnum string } { } define-primitive
+\ set-string-nth-slow { fixnum fixnum string } { } define-primitive
+\ set-string-nth-fast { fixnum fixnum string } { } define-primitive
\ resize-array { integer array } { array } define-primitive
\ resize-array make-flushable
\ modify-code-heap { array object } { } define-primitive
\ unimplemented { } { } define-primitive
+
+\ gc-reset { } { } define-primitive
+
+\ gc-stats { } { array } define-primitive
+
+\ jit-compile { quotation } { } define-primitive
dup "A" throw [ bogus-error ] [ drop ] if ; inline recursive
[ bogus-error ] must-infer
+
+[ [ clear ] infer. ] [ inference-error? ] must-fail-with
: forget-effects ( -- )
forget-errors
- all-words [ f "inferred-effect" set-word-prop ] each ;
+ all-words [
+ dup subwords [ f "inferred-effect" set-word-prop ] each
+ f "inferred-effect" set-word-prop
+ ] each ;
! See http://factorcode.org/license.txt for BSD license.
USING: assocs arrays namespaces sequences kernel definitions
math effects accessors words fry classes.algebra
-compiler.units ;
+compiler.units stack-checker.values stack-checker.visitor ;
IN: stack-checker.state
! Did the current control-flow path throw an error?
! Number of inputs current word expects from the stack
SYMBOL: d-in
+DEFER: commit-literals
+
! Compile-time data stack
-SYMBOL: meta-d
+: meta-d ( -- stack ) commit-literals \ meta-d get ;
! Compile-time retain stack
-SYMBOL: meta-r
+: meta-r ( -- stack ) \ meta-r get ;
+
+! Uncommitted literals. This is a form of local dead-code
+! elimination; the goal is to reduce the number of IR nodes
+! which get constructed. Technically it is redundant since
+! we do global DCE later, but it speeds up compile time.
+SYMBOL: literals
+
+: (push-literal) ( obj -- )
+ dup <literal> make-known
+ [ nip \ meta-d get push ] [ #push, ] 2bi ;
+
+: commit-literals ( -- )
+ literals get [
+ [ [ (push-literal) ] each ] [ delete-all ] bi
+ ] unless-empty ;
-: current-stack-height ( -- n ) meta-d get length d-in get - ;
+: current-stack-height ( -- n ) meta-d length d-in get - ;
: current-effect ( -- effect )
d-in get
- meta-d get length <effect>
+ meta-d length <effect>
terminated? get >>terminated? ;
: init-inference ( -- )
terminated? off
- V{ } clone meta-d set
- V{ } clone meta-r set
+ V{ } clone \ meta-d set
+ V{ } clone literals set
0 d-in set ;
! Words that the current quotation depends on
rot with-datastack first2
dup [
[
- [ drop ] [
- [ length meta-d get '[ _ pop* ] times ]
- [ #drop, ]
- bi
- ] bi*
+ [ drop ]
+ [ [ length meta-d shorten-by ] [ #drop, ] bi ] bi*
] 2dip
swap infer-quot
] [
\ spread [ spread>quot ] 1 define-transform
\ (call-next-method) [
- [ [ inlined-dependency depends-on ] bi@ ] [ next-method-quot ] 2bi
-] 2 define-transform
+ [
+ [ "method-class" word-prop ]
+ [ "method-generic" word-prop ] bi
+ [ inlined-dependency depends-on ] bi@
+ ] [
+ [ next-method-quot ]
+ [ '[ _ no-next-method ] ] bi or
+ ] bi
+] 1 define-transform
! Constructors
\ boa [
\r
: expect ( ch -- )\r
get-char 2dup = [ 2drop ] [\r
- >r 1string r> 1string expected\r
+ [ 1string ] bi@ expected\r
] if next ;\r
\r
: expect-string ( string -- )\r
swap [ init-parser call ] with-input-stream ; inline\r
\r
: string-parse ( input quot -- )\r
- >r <string-reader> r> state-parse ; inline\r
+ [ <string-reader> ] dip state-parse ; inline\r
--- /dev/null
+Slava Pestov
--- /dev/null
+IN: struct-arrays
+USING: help.markup help.syntax alien strings math ;
+
+HELP: struct-array
+{ $class-description "The class of C struct and union arrays."
+$nl
+"The " { $slot "underlying" } " slot holds a " { $link c-ptr } " with the raw data. This pointer can be passed to C functions." } ;
+
+HELP: <struct-array>
+{ $values { "length" integer } { "c-type" string } { "struct-array" struct-array } }
+{ $description "Creates a new array for holding values of the specified C type." } ;
+
+HELP: <direct-struct-array>
+{ $values { "alien" c-ptr } { "length" integer } { "c-type" string } { "struct-array" struct-array } }
+{ $description "Creates a new array for holding values of the specified C type, backed by the memory at " { $snippet "alien" } "." } ;
+
+ARTICLE: "struct-arrays" "C struct and union arrays"
+"The " { $vocab-link "struct-arrays" } " vocabulary implements arrays specialized for holding C struct and union values."
+{ $subsection struct-array }
+{ $subsection <struct-array> }
+{ $subsection <direct-struct-array> } ;
+
+ABOUT: "struct-arrays"
--- /dev/null
+IN: struct-arrays.tests
+USING: struct-arrays tools.test kernel math sequences
+alien.syntax alien.c-types destructors libc accessors ;
+
+C-STRUCT: test-struct
+{ "int" "x" }
+{ "int" "y" } ;
+
+: make-point ( x y -- struct )
+ "test-struct" <c-object>
+ [ set-test-struct-y ] keep
+ [ set-test-struct-x ] keep ;
+
+[ 5/4 ] [
+ 2 "test-struct" <struct-array>
+ 1 2 make-point over set-first
+ 3 4 make-point over set-second
+ 0 [ [ test-struct-x ] [ test-struct-y ] bi / + ] reduce
+] unit-test
+
+[ 5/4 ] [
+ [
+ 2 "test-struct" malloc-struct-array
+ dup underlying>> &free drop
+ 1 2 make-point over set-first
+ 3 4 make-point over set-second
+ 0 [ [ test-struct-x ] [ test-struct-y ] bi / + ] reduce
+ ] with-destructors
+] unit-test
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien alien.c-types byte-arrays kernel libc
+math sequences sequences.private ;
+IN: struct-arrays
+
+TUPLE: struct-array
+{ underlying c-ptr read-only }
+{ length array-capacity read-only }
+{ element-size array-capacity read-only } ;
+
+M: struct-array length length>> ;
+
+M: struct-array nth-unsafe
+ [ element-size>> * ] [ underlying>> ] bi <displaced-alien> ;
+
+M: struct-array set-nth-unsafe
+ [ nth-unsafe swap ] [ element-size>> ] bi memcpy ;
+
+M: struct-array new-sequence
+ element-size>> [ * <byte-array> ] 2keep struct-array boa ; inline
+
+: <struct-array> ( length c-type -- struct-array )
+ heap-size [ * <byte-array> ] 2keep struct-array boa ; inline
+
+ERROR: bad-byte-array-length byte-array ;
+
+: byte-array>struct-array ( byte-array c-type -- struct-array )
+ heap-size [
+ [ dup length ] dip /mod 0 =
+ [ drop bad-byte-array-length ] unless
+ ] keep struct-array boa ; inline
+
+: <direct-struct-array> ( alien length c-type -- struct-array )
+ struct-array boa ; inline
+
+: malloc-struct-array ( length c-type -- struct-array )
+ heap-size [ calloc ] 2keep <direct-struct-array> ;
+
+INSTANCE: struct-array sequence
--- /dev/null
+Arrays of C structs and unions
--- /dev/null
+collections
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors classes sequences splitting kernel namespaces
-make words math math.parser io.styles prettyprint assocs ;
+USING: accessors classes sequences kernel namespaces
+make words math math.parser assocs ;
IN: summary
GENERIC: summary ( object -- string )
M: object summary object-summary ;
-M: input summary
- [
- "Input: " %
- string>> "\n" split1 swap %
- "..." "" ? %
- ] "" make ;
-
-M: word summary synopsis ;
-
M: sequence summary
[
dup class name>> %
[
{ "content" "summary" } any-tag-named
dup children>> [ string? not ] contains?
- [ children>> [ write-chunk ] with-string-writer ]
+ [ children>> [ write-xml-chunk ] with-string-writer ]
[ children>string ] if >>description
]
[
USING: help.markup help.syntax kernel kernel.private io
threads.private continuations init quotations strings
-assocs heaps boxes namespaces deques ;
+assocs heaps boxes namespaces deques dlists ;
IN: threads
ARTICLE: "threads-start/stop" "Starting and stopping threads"
{ $notes "In most cases, user code should call " { $link spawn } " instead, however for control over the error handler quotation, threads can be created with " { $link <thread> } " then passed to " { $link (spawn) } "." } ;
HELP: run-queue
-{ $values { "queue" deque } }
+{ $values { "dlist" dlist } }
{ $var-description "Global variable holding the queue of runnable threads. Calls to " { $link yield } " switch to the thread which has been in the queue for the longest period of time."
$nl
"By convention, threads are queued with " { $link push-front }
{ $description "Adds a thread to the end of the run queue together with an object to pass to the thread. The thread must have previously been suspended by a call to " { $link suspend } "; the object is returned from the " { $link suspend } " call." } ;
HELP: sleep-queue
+{ $values { "heap" min-heap } }
{ $var-description "A " { $link min-heap } " storing the queue of sleeping threads." } ;
HELP: sleep-time
-{ $values { "ms/f" "a non-negative integer or " { $link f } } }
+{ $values { "us/f" "a non-negative integer or " { $link f } } }
{ $description "Outputs the time until the next sleeping thread is scheduled to wake up, which could be zero if there are threads in the run queue, or threads which need to wake up right now. If there are no runnable or sleeping threads, outputs " { $link f } "." } ;
HELP: stop
USING: arrays hashtables heaps kernel kernel.private math
namespaces sequences vectors continuations continuations.private
dlists assocs system combinators init boxes accessors
-math.order deques strings quotations ;
+math.order deques strings quotations fry ;
IN: threads
SYMBOL: initial-thread
: tchange ( key quot -- )
tnamespace swap change-at ; inline
-: threads 64 getenv ;
+: threads ( -- assoc ) 64 getenv ;
: thread ( id -- thread ) threads at ;
: <thread> ( quot name -- thread )
\ thread new-thread ;
-: run-queue 65 getenv ;
+: run-queue ( -- dlist ) 65 getenv ;
-: sleep-queue 66 getenv ;
+: sleep-queue ( -- heap ) 66 getenv ;
: resume ( thread -- )
f >>state
f >>state
check-registered 2array run-queue push-front ;
-: sleep-time ( -- ms/f )
+: sleep-time ( -- us/f )
{
{ [ run-queue deque-empty? not ] [ 0 ] }
{ [ sleep-queue heap-empty? ] [ f ] }
- [ sleep-queue heap-peek nip millis [-] ]
+ [ sleep-queue heap-peek nip micros [-] ]
} cond ;
DEFER: stop
<PRIVATE
: schedule-sleep ( thread dt -- )
- >r check-registered dup r> sleep-queue heap-push*
+ [ check-registered dup ] dip sleep-queue heap-push*
>>sleep-entry drop ;
: expire-sleep? ( heap -- ? )
dup heap-empty?
- [ drop f ] [ heap-peek nip millis <= ] if ;
+ [ drop f ] [ heap-peek nip micros <= ] if ;
: expire-sleep ( thread -- )
f >>sleep-entry resume ;
: suspend ( quot state -- obj )
[
- >r
- >r self swap call
- r> self (>>state)
- r> self continuation>> >box
+ [ [ self swap call ] dip self (>>state) ] dip
+ self continuation>> >box
next
] callcc1 2nip ; inline
GENERIC: sleep-until ( time/f -- )
M: integer sleep-until
- [ schedule-sleep ] curry "sleep" suspend drop ;
+ '[ _ schedule-sleep ] "sleep" suspend drop ;
M: f sleep-until
drop [ drop ] "interrupt" suspend drop ;
GENERIC: sleep ( dt -- )
M: real sleep
- millis + >integer sleep-until ;
+ micros + >integer sleep-until ;
: interrupt ( thread -- )
dup state>> [
<thread> [ (spawn) ] keep ;
: spawn-server ( quot name -- thread )
- >r [ loop ] curry r> spawn ;
+ [ '[ _ loop ] ] dip spawn ;
: in-thread ( quot -- )
- >r datastack r>
- [ >r set-datastack r> call ] 2curry
+ [ datastack ] dip
+ '[ _ set-datastack _ call ]
"Thread" spawn drop ;
GENERIC: error-in-thread ( error thread -- )
ARTICLE: "tools.annotations" "Word annotations"
"The word annotation feature modifies word definitions to add debugging code. You can restore the old definition by calling " { $link reset } " on the word in question."
+$nl
+"Printing messages when a word is called or returns:"
{ $subsection watch }
+{ $subsection watch-vars }
+"Starting the walker when a word is called:"
{ $subsection breakpoint }
{ $subsection breakpoint-if }
+"Timing words:"
+{ $subsection reset-word-timing }
+{ $subsection add-timing }
+{ $subsection word-timing. }
"All of the above words are implemented using a single combinator which applies a quotation to a word definition to yield a new definition:"
{ $subsection annotate } ;
{ "seq" sequence } }
{ $description "Makes a sequence of the inputs to a word by counting the number of inputs in the stack effect and saving that many items from the datastack." } ;
+HELP: add-timing
+{ $values { "word" word } }
+{ $description "Adds timing code to a word, which records its total running time, including that of words it calls, on every invocation." }
+{ $see-also "timing" "profiling" } ;
+
+HELP: reset-word-timing
+{ $description "Resets the word timing table." } ;
+
+HELP: word-timing.
+{ $description "Prints the word timing table." } ;
-USING: tools.test tools.annotations math parser eval
+USING: tools.test tools.annotations tools.time math parser eval
io.streams.string kernel ;
IN: tools.annotations.tests
! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel words parser io summary quotations
-sequences prettyprint continuations effects definitions
-compiler.units namespaces assocs tools.walker generic
-inspector fry ;
+USING: accessors kernel math sorting words parser io summary
+quotations sequences prettyprint continuations effects
+definitions compiler.units namespaces assocs tools.walker
+tools.time generic inspector fry ;
IN: tools.annotations
GENERIC: reset ( word -- )
f "unannotated-def" set-word-prop
] [ drop ] if ;
+ERROR: cannot-annotate-twice word ;
+
: annotate ( word quot -- )
over "unannotated-def" word-prop [
- "Cannot annotate a word twice" throw
+ over cannot-annotate-twice
] when
[
over dup def>> "unannotated-def" set-word-prop
- >r dup def>> r> call define
+ [ dup def>> ] dip call define
] with-compilation-unit ; inline
: word-inputs ( word -- seq )
stack-effect [
- >r datastack r> in>> length tail*
+ [ datastack ] dip in>> length tail*
] [
datastack
] if* ;
word-inputs stack.
"\\--" print flush ;
-: leaving ( str -- )
- "/-- Leaving: " write dup .
+: word-outputs ( word -- seq )
stack-effect [
- >r datastack r> out>> length tail* stack.
+ [ datastack ] dip out>> length tail*
] [
- .s
- ] if* "\\--" print flush ;
+ datastack
+ ] if* ;
+
+: leaving ( str -- )
+ "/-- Leaving: " write dup .
+ word-outputs stack.
+ "\\--" print flush ;
-: (watch) ( word def -- def ) over '[ _ entering @ _ leaving ] ;
+: (watch) ( word def -- def )
+ over '[ _ entering @ _ leaving ] ;
: watch ( word -- )
dup [ (watch) ] annotate ;
-: (watch-vars) ( quot word vars -- newquot )
- rot
+: (watch-vars) ( word vars quot -- newquot )
'[
- "--- Entering: " write _ .
+ "--- Entering: " write _ .
"--- Variable values:" print _ [ dup get ] H{ } map>assoc describe
@
] ;
: watch-vars ( word vars -- )
- dupd [ (watch-vars) ] 2curry annotate ;
+ dupd '[ [ _ _ ] dip (watch-vars) ] annotate ;
GENERIC# annotate-methods 1 ( word quot -- )
M: generic annotate-methods
- >r "methods" word-prop values r> [ annotate ] curry each ;
+ [ "methods" word-prop values ] dip [ annotate ] curry each ;
M: word annotate-methods
annotate ;
[ add-breakpoint ] annotate-methods ;
: breakpoint-if ( word quot -- )
- [ [ [ break ] when ] rot 3append ] curry annotate-methods ;
+ '[ [ _ [ [ break ] when ] ] dip 3append ] annotate-methods ;
+
+SYMBOL: word-timing
+
+word-timing global [ H{ } clone or ] change-at
+
+: reset-word-timing ( -- )
+ word-timing get clear-assoc ;
+
+: (add-timing) ( def word -- def' )
+ '[ _ benchmark _ word-timing get at+ ] ;
+
+: add-timing ( word -- )
+ dup '[ _ (add-timing) ] annotate ;
+
+: word-timing. ( -- )
+ word-timing get
+ >alist [ 1000000 /f ] assoc-map sort-values
+ simple-table. ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays cocoa.messages cocoa.runtime combinators
+prettyprint ;
+IN: tools.cocoa
+
+: method. ( method -- )
+ {
+ [ method_getName sel_getName ]
+ [ method-return-type ]
+ [ method-arg-types ]
+ [ method_getImplementation ]
+ } cleave 4array . ;
+
+: methods. ( class -- )
+ [ method. ] each-method-in-class ;
--- /dev/null
+unportable
{
{ [ over zero? ] [ 2drop 10 ] }
{ [ 2dup length 1- number= ] [ 2drop 4 ] }
- { [ 2dup >r 1- r> nth Letter? not ] [ 2drop 10 ] }
- { [ 2dup >r 1+ r> nth Letter? not ] [ 2drop 4 ] }
+ { [ 2dup [ 1- ] dip nth Letter? not ] [ 2drop 10 ] }
+ { [ 2dup [ 1+ ] dip nth Letter? not ] [ 2drop 4 ] }
[ 2drop 1 ]
} cond ;
over empty? [
nip [ first ] map
] [
- >r >lower r> [ completion ] with map
+ [ >lower ] dip [ completion ] with map
rank-completions
] if ;
: string-completions ( short strs -- seq )
- [ dup ] { } map>assoc completions ;
+ dup zip completions ;
: limited-completions ( short candidates -- seq )
- completions dup length 1000 > [ drop f ] when ;
+ [ completions ] [ drop ] 2bi
+ 2dup [ length 50 > ] [ empty? ] bi* and
+ [ 2drop f ] [ drop 50 short head ] if ;
continuations math definitions mirrors splitting parser classes
summary layouts vocabs.loader prettyprint.config prettyprint
debugger io.streams.c io.files io.backend quotations io.launcher
-words.private tools.deploy.config bootstrap.image
-io.encodings.utf8 destructors accessors ;
+words.private tools.deploy.config tools.deploy.config.editor
+bootstrap.image io.encodings.utf8 destructors accessors ;
IN: tools.deploy.backend
: copy-vm ( executable bundle-name extension -- vm )
: staging-command-line ( profile -- flags )
[
+ "-staging" ,
+
dup empty? [
"-i=" my-boot-image-name append ,
] [
dup staging-image-name exists?
[ drop ] [ make-staging-image ] if ;
+: make-deploy-config ( vocab -- file )
+ [ deploy-config unparse-use ]
+ [ "deploy-config-" prepend temp-file ] bi
+ [ utf8 set-file-contents ] keep ;
+
: deploy-command-line ( image vocab config -- flags )
[
bootstrap-profile ?make-staging-image
"-run=tools.deploy.shaker" ,
- "-deploy-vocab=" prepend ,
+ [ "-deploy-vocab=" prepend , ]
+ [ make-deploy-config "-deploy-config=" prepend , ] bi
"-output-image=" prepend ,
kernel math ;
IN: tools.deploy.config
-ARTICLE: "deploy-config" "Deployment configuration"
-"The deployment configuration is a key/value mapping stored in the " { $snippet "deploy.factor" } " file in the vocabulary's directory. If this file does not exist, the default deployment configuration is used:"
-{ $subsection default-config }
-"The deployment configuration can be read and written with a pair of words:"
-{ $subsection deploy-config }
-{ $subsection set-deploy-config }
-"A utility word is provided to load the configuration, change a flag, and store it back to disk:"
-{ $subsection set-deploy-flag }
-"The " { $link "ui.tools.deploy" } " provides a graphical way of editing the configuration." ;
-
ARTICLE: "deploy-flags" "Deployment flags"
"There are two sets of deployment flags. The first set controls the major subsystems which are to be included in the deployment image:"
{ $subsection deploy-math? }
{ $subsection deploy-word-props? }
{ $subsection deploy-c-types? } ;
-ARTICLE: "prepare-deploy" "Preparing to deploy an application"
-"In order to deploy an application as a stand-alone image, the application's vocabulary must first be given a " { $link POSTPONE: MAIN: } " hook. Then, a " { $emphasis "deployment configuration" } " must be created."
-{ $subsection "deploy-config" }
-{ $subsection "deploy-flags" } ;
-
-ABOUT: "prepare-deploy"
+ABOUT: "deploy-flags"
HELP: deploy-name
{ $description "Deploy setting. The name of the executable."
HELP: default-config
{ $values { "vocab" "a vocabulary specifier" } { "assoc" assoc } }
{ $description "Outputs the default deployment configuration for a vocabulary." } ;
-
-HELP: deploy-config
-{ $values { "vocab" "a vocabulary specifier" } { "assoc" assoc } }
-{ $description "Loads a vocabulary's deployment configuration from the " { $snippet "deploy.factor" } " file in the vocabulary's directory. If the file does not exist, the " { $link default-config } " is output." } ;
-
-HELP: set-deploy-config
-{ $values { "assoc" assoc } { "vocab" "a vocabulary specifier" } }
-{ $description "Stores a vocabulary's deployment configuration to the " { $snippet "deploy.factor" } " file in the vocabulary's directory." } ;
-
-HELP: set-deploy-flag
-{ $values { "value" object } { "key" object } { "vocab" "a vocabulary specifier" } }
-{ $description "Modifies an entry in a vocabulary's deployment configuration on disk." } ;
! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: vocabs.loader io.files io kernel sequences assocs
-splitting parser prettyprint namespaces math vocabs
-hashtables tools.vocabs ;
+USING: io.files io kernel sequences assocs splitting parser
+namespaces math vocabs hashtables ;
IN: tools.deploy.config
SYMBOL: deploy-name
! default value for deploy.macosx
{ "stop-after-last-window?" t }
} assoc-union ;
-
-: deploy-config-path ( vocab -- string )
- vocab-dir "deploy.factor" append-path ;
-
-: deploy-config ( vocab -- assoc )
- dup default-config swap
- dup deploy-config-path vocab-file-contents
- parse-fresh [ first assoc-union ] unless-empty ;
-
-: set-deploy-config ( assoc vocab -- )
- >r unparse-use string-lines r>
- dup deploy-config-path set-vocab-file-contents ;
-
-: set-deploy-flag ( value key vocab -- )
- [ deploy-config [ set-at ] keep ] keep set-deploy-config ;
--- /dev/null
+USING: assocs help.markup help.syntax kernel
+tools.deploy.config ;
+IN: tools.deploy.config.editor
+
+ARTICLE: "deploy-config" "Deployment configuration"
+"The deployment configuration is a key/value mapping stored in the " { $snippet "deploy.factor" } " file in the vocabulary's directory. If this file does not exist, the default deployment configuration is used:"
+{ $subsection default-config }
+"The deployment configuration can be read and written with a pair of words:"
+{ $subsection deploy-config }
+{ $subsection set-deploy-config }
+"A utility word is provided to load the configuration, change a flag, and store it back to disk:"
+{ $subsection set-deploy-flag }
+"The " { $link "ui.tools.deploy" } " provides a graphical way of editing the configuration." ;
+
+HELP: deploy-config
+{ $values { "vocab" "a vocabulary specifier" } { "assoc" assoc } }
+{ $description "Loads a vocabulary's deployment configuration from the " { $snippet "deploy.factor" } " file in the vocabulary's directory. If the file does not exist, the " { $link default-config } " is output." } ;
+
+HELP: set-deploy-config
+{ $values { "assoc" assoc } { "vocab" "a vocabulary specifier" } }
+{ $description "Stores a vocabulary's deployment configuration to the " { $snippet "deploy.factor" } " file in the vocabulary's directory." } ;
+
+HELP: set-deploy-flag
+{ $values { "value" object } { "key" object } { "vocab" "a vocabulary specifier" } }
+{ $description "Modifies an entry in a vocabulary's deployment configuration on disk." } ;
+
+ABOUT: "deploy-config"
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: assocs io.files kernel parser prettyprint sequences
+splitting tools.deploy.config tools.vocabs vocabs.loader ;
+IN: tools.deploy.config.editor
+
+: deploy-config-path ( vocab -- string )
+ vocab-dir "deploy.factor" append-path ;
+
+: deploy-config ( vocab -- assoc )
+ dup default-config swap
+ dup deploy-config-path vocab-file-contents
+ parse-fresh [ first assoc-union ] unless-empty ;
+
+: set-deploy-config ( assoc vocab -- )
+ [ unparse-use string-lines ] dip
+ dup deploy-config-path set-vocab-file-contents ;
+
+: set-deploy-flag ( value key vocab -- )
+ [ deploy-config [ set-at ] keep ] keep set-deploy-config ;
kernel ;
IN: tools.deploy
+ARTICLE: "prepare-deploy" "Preparing to deploy an application"
+"In order to deploy an application as a stand-alone image, the application's vocabulary must first be given a " { $link POSTPONE: MAIN: } " hook. Then, a " { $emphasis "deployment configuration" } " must be created."
+{ $subsection "deploy-config" }
+{ $subsection "deploy-flags" } ;
+
ARTICLE: "tools.deploy" "Application deployment"
"The stand-alone application deployment tool compiles a vocabulary down to a native executable which runs the vocabulary's " { $link POSTPONE: MAIN: } " hook. Deployed executables do not depend on Factor being installed, and do not expose any source code, and thus are suitable for delivering commercial end-user applications."
$nl
IN: tools.deploy.tests\r
USING: tools.test system io.files kernel tools.deploy.config\r
-tools.deploy.backend math sequences io.launcher arrays\r
-namespaces continuations layouts accessors io.encodings.ascii\r
-urls math.parser ;\r
+tools.deploy.config.editor tools.deploy.backend math sequences\r
+io.launcher arrays namespaces continuations layouts accessors\r
+io.encodings.ascii urls math.parser ;\r
\r
: shake-and-bake ( vocab -- )\r
[ "test.image" temp-file delete-file ] ignore-errors\r
"resource:" [\r
- >r vm\r
- "test.image" temp-file\r
- r> dup deploy-config make-deploy-image\r
+ [ vm "test.image" temp-file ] dip\r
+ dup deploy-config make-deploy-image\r
] with-directory ;\r
\r
: small-enough? ( n -- ? )\r
- >r "test.image" temp-file file-info size>> r> cell 4 / * <= ;\r
+ [ "test.image" temp-file file-info size>> ] [ cell 4 / * ] bi* <= ;\r
\r
-[ ] [ "hello-world" shake-and-bake ] unit-test\r
+[ t ] [ "hello-world" shake-and-bake 500000 small-enough? ] unit-test\r
\r
-[ t ] [ 500000 small-enough? ] unit-test\r
+[ t ] [ "sudoku" shake-and-bake 800000 small-enough? ] unit-test\r
\r
-[ ] [ "sudoku" shake-and-bake ] unit-test\r
-\r
-[ t ] [ 800000 small-enough? ] unit-test\r
-\r
-[ ] [ "hello-ui" shake-and-bake ] unit-test\r
-\r
-[ t ] [ 1300000 small-enough? ] unit-test\r
+[ t ] [ "hello-ui" shake-and-bake 1300000 small-enough? ] unit-test\r
\r
[ "staging.math-compiler-threads-ui-strip.image" ] [\r
"hello-ui" deploy-config\r
[ bootstrap-profile staging-image-name file-name ] bind\r
] unit-test\r
\r
-[ ] [ "maze" shake-and-bake ] unit-test\r
-\r
-[ t ] [ 1200000 small-enough? ] unit-test\r
+[ t ] [ "maze" shake-and-bake 1200000 small-enough? ] unit-test\r
\r
-[ ] [ "tetris" shake-and-bake ] unit-test\r
+[ t ] [ "tetris" shake-and-bake 1500000 small-enough? ] unit-test\r
\r
-[ t ] [ 1500000 small-enough? ] unit-test\r
+[ t ] [ "bunny" shake-and-bake 2500000 small-enough? ] unit-test\r
\r
-[ ] [ "bunny" shake-and-bake ] unit-test\r
-\r
-[ t ] [ 2500000 small-enough? ] unit-test\r
+os macosx? [\r
+ [ t ] [ "webkit-demo" shake-and-bake 500000 small-enough? ] unit-test\r
+] when\r
\r
: run-temp-image ( -- )\r
vm\r
"tools.deploy.test.6" shake-and-bake\r
run-temp-image\r
] unit-test\r
+\r
+[ ] [\r
+ "tools.deploy.test.7" shake-and-bake\r
+ run-temp-image\r
+] unit-test\r
+\r
+[ ] [\r
+ "tools.deploy.test.8" shake-and-bake\r
+ run-temp-image\r
+] unit-test\r
! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: io io.files kernel namespaces make sequences
-system tools.deploy.backend tools.deploy.config assocs
-hashtables prettyprint io.unix.backend cocoa io.encodings.utf8
-io.backend cocoa.application cocoa.classes cocoa.plists
-qualified combinators ;
+USING: io io.files kernel namespaces make sequences system
+tools.deploy.backend tools.deploy.config
+tools.deploy.config.editor assocs hashtables prettyprint
+io.unix.backend cocoa io.encodings.utf8 io.backend
+cocoa.application cocoa.classes cocoa.plists qualified
+combinators ;
IN: tools.deploy.macosx
: bundle-dir ( -- dir )
--- /dev/null
+USING: words ;
+IN: generic
+
+: next-method-quot ( method -- quot ) "next-method-quot" word-prop ;
! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors qualified io.backend io.streams.c init fry
-namespaces make assocs kernel parser lexer strings.parser
-tools.deploy.config vocabs sequences words words.private memory
-kernel.private continuations io prettyprint vocabs.loader
-debugger system strings sets vectors quotations byte-arrays
-sorting compiler.units definitions ;
+namespaces make assocs kernel parser lexer strings.parser vocabs
+sequences words words.private memory kernel.private
+continuations io vocabs.loader system strings sets
+vectors quotations byte-arrays sorting compiler.units
+definitions generic generic.standard tools.deploy.config ;
QUALIFIED: bootstrap.stage2
QUALIFIED: classes
QUALIFIED: command-line
QUALIFIED: definitions
QUALIFIED: init
QUALIFIED: layouts
-QUALIFIED: listener
-QUALIFIED: prettyprint.config
QUALIFIED: source-files
QUALIFIED: vocabs
IN: tools.deploy.shaker
: strip-init-hooks ( -- )
"Stripping startup hooks" show
- "cpu.x86" init-hooks get delete-at
- "command-line" init-hooks get delete-at
- "libc" init-hooks get delete-at
- "system" init-hooks get delete-at
+ { "cpu.x86" "command-line" "libc" "system" "environment" }
+ [ init-hooks get delete-at ] each
deploy-threads? get [
"threads" init-hooks get delete-at
] unless
] when ;
: strip-debugger ( -- )
- strip-debugger? [
+ strip-debugger? "debugger" vocab and [
"Stripping debugger" show
"resource:basis/tools/deploy/shaker/strip-debugger.factor"
run-file
>alist f like
] change-props drop
] each
- ] [
- "Remaining word properties:\n" show
- [ props>> keys ] gather unparse show
] [
H{ } clone '[
[ [ _ [ ] cache ] map ] change-props drop
] each
- ] tri ;
+ ] bi ;
: stripped-word-props ( -- seq )
[
- strip-dictionary? deploy-compiler? get and [
- {
- "combination"
- "members"
- "methods"
- } %
- ] when
-
strip-dictionary? [
{
"alias"
"boa-check"
"cannot-infer"
"coercer"
+ "combination"
"compiled-effect"
"compiled-generic-uses"
"compiled-uses"
"default-method"
"default-output-classes"
"derived-from"
+ "ebnf-parser"
"engines"
"forgotten"
"identities"
"local-writer?"
"local?"
"macro"
+ "members"
"memo-quot"
+ "methods"
"mixin"
"method-class"
"method-generic"
strip-word-names? [ dup strip-word-names ] when
2drop ;
+: strip-default-methods ( -- )
+ strip-debugger? [
+ "Stripping default methods" show
+ [
+ [ generic? ] instances
+ [ "No method" throw ] define-temp
+ dup t "default" set-word-prop
+ '[
+ [ _ "default-method" set-word-prop ] [ make-generic ] bi
+ ] each
+ ] with-compilation-unit
+ ] when ;
+
: strip-vocab-globals ( except names -- words )
[ child-vocabs [ words ] map concat ] map concat swap diff ;
: stripped-globals ( -- seq )
[
- "callbacks" "alien.compiler" lookup ,
-
"inspector-hook" "inspector" lookup ,
{
- bootstrap.stage2:bootstrap-time
continuations:error
continuations:error-continuation
continuations:error-thread
continuations:restarts
- listener:error-hook
init:init-hooks
source-files:source-files
input-stream
"tools"
"io.launcher"
"random"
+ "compiler"
+ "stack-checker"
+ "bootstrap"
+ "listener"
} strip-vocab-globals %
strip-dictionary? [
{
gensym
name>char-hook
+ classes:next-method-quot-cache
classes:class-and-cache
classes:class-not-cache
classes:class-or-cache
layouts:tag-numbers
layouts:type-numbers
lexer-factory
- listener:listener-hook
+ print-use-hook
root-cache
vocab-roots
vocabs:dictionary
} %
{ } { "math.partial-dispatch" } strip-vocab-globals %
-
- "peg-cache" "peg" lookup ,
+
+ { } { "peg" } strip-vocab-globals %
] when
strip-prettyprint? [
- {
- prettyprint.config:margin
- prettyprint.config:string-limit?
- prettyprint.config:boa-tuples?
- prettyprint.config:tab-size
- } %
+ { } { "prettyprint.config" } strip-vocab-globals %
] when
strip-debugger? [
"ui-error-hook" "ui.gadgets.worlds" lookup ,
] when
- "<value>" "stack-checker.state" lookup [ , ] when*
-
"windows-messages" "windows.messages" lookup [ , ] when*
-
] { } make ;
: strip-globals ( stripped-globals -- )
'[ drop _ member? not ] assoc-filter
[ drop string? not ] assoc-filter ! strip CLI args
sift-assoc
- dup keys unparse show
21 setenv
] [ drop ] if ;
] with-compilation-unit
] unless ;
-: compress ( pred string -- )
+: compress ( pred post-process string -- )
"Compressing " prepend show
- instances
- dup H{ } clone [ [ ] cache ] curry map
+ [ instances dup H{ } clone [ [ ] cache ] curry map ] dip call
become ; inline
: compress-byte-arrays ( -- )
- [ byte-array? ] "byte arrays" compress ;
+ [ byte-array? ] [ ] "byte arrays" compress ;
+
+: remain-compiled ( old new -- old new )
+ #! Quotations which were formerly compiled must remain
+ #! compiled.
+ 2dup [
+ 2dup [ compiled>> ] [ compiled>> not ] bi* and
+ [ nip jit-compile ] [ 2drop ] if
+ ] 2each ;
: compress-quotations ( -- )
- [ quotation? ] "quotations" compress ;
+ [ quotation? ] [ remain-compiled ] "quotations" compress ;
: compress-strings ( -- )
- [ string? ] "strings" compress ;
+ [ string? ] [ ] "strings" compress ;
+
+: compress-wrappers ( -- )
+ [ wrapper? ] [ ] "wrappers" compress ;
: finish-deploy ( final-image -- )
"Finishing up" show
- >r { } set-datastack r>
+ [ { } set-datastack ] dip
{ } set-retainstack
V{ } set-namestack
V{ } set-catchstack
init-hooks get values concat %
,
strip-io? [ \ flush , ] unless
- ] [ ] make "Boot quotation: " show dup unparse show
+ ] [ ] make
set-boot-quot ;
: init-stripper ( -- )
t "quiet" set-global
f output-stream set-global ;
+: compute-next-methods ( -- )
+ [ standard-generic? ] instances [
+ "methods" word-prop [
+ nip
+ dup next-method-quot "next-method-quot" set-word-prop
+ ] assoc-each
+ ] each
+ "resource:basis/tools/deploy/shaker/next-methods.factor" run-file ;
+
: strip ( -- )
init-stripper
+ strip-default-methods
strip-libc
strip-cocoa
strip-debugger
+ compute-next-methods
strip-init-hooks
strip-c-io
f 5 setenv ! we can't use the Factor debugger or Factor I/O anymore
deploy-vocab get vocab-main set-boot-quot*
- stripped-word-props >r
+ stripped-word-props
stripped-globals strip-globals
- r> strip-words
compress-byte-arrays
compress-quotations
compress-strings
- H{ } clone classes:next-method-quot-cache set-global ;
+ compress-wrappers
+ strip-words ;
: (deploy) ( final-image vocab config -- )
#! Does the actual work of a deployment in the slave
deploy-vocab get require
strip
finish-deploy
- ] [
- print-error flush 1 exit
- ] recover
+ ] [ error-continuation get call>> callstack>array die 1 exit ] recover
] bind ;
: do-deploy ( -- )
"output-image" get
"deploy-vocab" get
"Deploying " write dup write "..." print
- dup deploy-config dup .
+ "deploy-config" get parse-file first
(deploy) ;
MAIN: do-deploy
global [
"stop-after-last-window?" "ui" lookup set
- "ui.cocoa" vocab [
- [ "MiniFactor.nib" load-nib ]
- "cocoa-init-hook" "ui.cocoa" lookup set-global
- ] when
-
! Only keeps those methods that we actually call
sent-messages get super-sent-messages get assoc-union
objc-methods [ assoc-intersect pool-values ] change
USING: compiler.units words vocabs kernel threads.private ;
IN: debugger
-: print-error ( error -- ) die drop ;
+: consume ( error -- )
+ #! We don't want DCE to drop the error before the die call!
+ drop ;
-: error. ( error -- ) die drop ;
+: print-error ( error -- ) die consume ;
+
+: error. ( error -- ) die consume ;
"threads" vocab [
[
IN: tools.deploy.test.1\r
USING: threads ;\r
\r
-: deploy-test-1 ( -- ) 1000 sleep ;\r
+: deploy-test-1 ( -- ) 1000000 sleep ;\r
\r
MAIN: deploy-test-1\r
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel math namespaces ;
+IN: tools.deploy.test.7
+
+SYMBOL: my-var
+
+GENERIC: my-generic ( x -- b )
+
+M: integer my-generic sq ;
+
+M: fixnum my-generic call-next-method my-var get call ;
+
+: test-7 ( -- )
+ [ 1 + ] my-var set-global
+ 12 my-generic 145 assert= ;
+
+MAIN: test-7
--- /dev/null
+USING: tools.deploy.config ;
+H{
+ { deploy-threads? t }
+ { deploy-word-props? f }
+ { deploy-ui? f }
+ { deploy-io 2 }
+ { deploy-math? t }
+ { "stop-after-last-window?" t }
+ { deploy-compiler? t }
+ { deploy-unicode? f }
+ { deploy-c-types? f }
+ { deploy-reflection 1 }
+ { deploy-word-defs? f }
+ { deploy-name "tools.deploy.test.7" }
+}
--- /dev/null
+USING: kernel ;
+IN: tools.deploy.test.8
+
+: literal-merge-test-1 ( -- x ) H{ { "lil" "wayne" } } ;
+: literal-merge-test-2 ( -- x ) H{ { "lil" "wayne" } } ;
+
+: literal-merge-test ( -- )
+ literal-merge-test-1
+ literal-merge-test-2 eq? t assert= ;
+
+MAIN: literal-merge-test
--- /dev/null
+USING: tools.deploy.config ;
+H{
+ { deploy-name "tools.deploy.test.8" }
+ { deploy-c-types? f }
+ { deploy-word-props? f }
+ { deploy-ui? f }
+ { deploy-reflection 1 }
+ { deploy-compiler? f }
+ { deploy-unicode? f }
+ { deploy-io 1 }
+ { deploy-word-defs? f }
+ { deploy-threads? f }
+ { "stop-after-last-window?" t }
+ { deploy-math? f }
+}
! Copyright (C) 2008 James Cash
! See http://factorcode.org/license.txt for BSD license.
USING: io io.files io.backend kernel namespaces make sequences
-system tools.deploy.backend tools.deploy.config assocs
-hashtables prettyprint ;
+system tools.deploy.backend tools.deploy.config
+tools.deploy.config.editor assocs hashtables prettyprint ;
IN: tools.deploy.unix
: create-app-dir ( vocab bundle-name -- vm )
! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: io io.files kernel namespaces sequences system
-tools.deploy.backend tools.deploy.config assocs hashtables
-prettyprint combinators windows.shell32 windows.user32 ;
+tools.deploy.backend tools.deploy.config
+tools.deploy.config.editor assocs hashtables prettyprint
+combinators windows.shell32 windows.user32 ;
IN: tools.deploy.windows
: copy-dll ( bundle-name -- )
\r
HELP: disassemble\r
{ $values { "obj" "a word or a pair of addresses" } }\r
-{ $description "Disassembles either a compiled word definition or an arbitrary memory range (in the case " { $snippet "obj" } " is a pair of integers) by attaching " { $snippet "gdb" } " to the Factor VM and capturing the output." }\r
-{ $notes "In some cases the Factor compiler emits data inline with code, which can confuse " { $snippet "gdb" } ". This occurs in words which call " { $link dispatch } ", where the jump table addresses are compiled inline. Also on the ARM architecture, various pointers are often compiled inline, and the preceeding instruction jumps over the inline pinter." } ;\r
+{ $description "Disassembles either a compiled word definition or an arbitrary memory range (in the case " { $snippet "obj" } " is a pair of integers)." }\r
+{ $notes "In some cases the Factor compiler emits data inline with code, which can confuse the disassembler. This occurs in words which call " { $link dispatch } ", where the jump table addresses are compiled inline." } ;\r
\r
ARTICLE: "tools.disassembler" "Disassembling words"\r
-"The " { $vocab-link "tools.disassembler" } " vocabulary integrates Factor with the GNU debugger (" { $snippet "gdb" } ") for viewing the assembly code generated by the compiler. It can be used on both Unix and Windows as long as a working copy of " { $snippet "gdb" } " is installed and available in the " { $snippet "PATH" } "."\r
+"The " { $vocab-link "tools.disassembler" } " vocabulary provides support for disassembling compiled word definitions. It uses the " { $snippet "libudis86" } " library on x86-32 and x86-64, and " { $snippet "gdb" } " on PowerPC."\r
{ $subsection disassemble } ;\r
\r
ABOUT: "tools.disassembler"\r
IN: tools.disassembler.tests\r
-USING: math classes.tuple prettyprint.backend tools.disassembler\r
-tools.test strings ;\r
+USING: math classes.tuple prettyprint.custom \r
+tools.disassembler tools.test strings ;\r
\r
[ ] [ \ + disassemble ] unit-test\r
[ ] [ { string pprint* } disassemble ] unit-test\r
-! Copyright (C) 2008 Slava Pestov, Jorge Acereda Macia.
+! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: io.files io words alien kernel math.parser alien.syntax
-io.launcher system assocs arrays sequences namespaces make
-qualified system math compiler.codegen.fixup
-io.encodings.ascii accessors generic tr ;
+USING: tr arrays sequences io words generic system combinators
+vocabs.loader ;
IN: tools.disassembler
-: in-file ( -- path ) "gdb-in.txt" temp-file ;
+GENERIC: disassemble ( obj -- )
-: out-file ( -- path ) "gdb-out.txt" temp-file ;
+SYMBOL: disassembler-backend
-GENERIC: make-disassemble-cmd ( obj -- )
+HOOK: disassemble* disassembler-backend ( from to -- lines )
-M: word make-disassemble-cmd
- word-xt code-format - 2array make-disassemble-cmd ;
-
-M: pair make-disassemble-cmd
- in-file ascii [
- "attach " write
- current-process-handle number>string print
- "disassemble " write
- [ number>string write bl ] each
- ] with-file-writer ;
-
-M: method-spec make-disassemble-cmd
- first2 method make-disassemble-cmd ;
+TR: tabs>spaces "\t" "\s" ;
-: gdb-binary ( -- string ) "gdb" ;
+M: pair disassemble first2 disassemble* [ tabs>spaces print ] each ;
-: run-gdb ( -- lines )
- <process>
- +closed+ >>stdin
- out-file >>stdout
- [ gdb-binary , "-x" , in-file , "-batch" , ] { } make >>command
- try-process
- out-file ascii file-lines ;
+M: word disassemble word-xt 2array disassemble ;
-TR: tabs>spaces "\t" "\s" ;
+M: method-spec disassemble first2 method disassemble ;
-: disassemble ( obj -- )
- make-disassemble-cmd run-gdb
- [ tabs>spaces ] map [ print ] each ;
+cpu {
+ { x86.32 [ "tools.disassembler.udis" ] }
+ { x86.64 [ "tools.disassembler.udis" ] }
+ { ppc [ "tools.disassembler.gdb" ] }
+} case require
--- /dev/null
+! Copyright (C) 2008 Slava Pestov, Jorge Acereda Macia.
+! See http://factorcode.org/license.txt for BSD license.
+USING: io.files io words alien kernel math.parser alien.syntax
+io.launcher system assocs arrays sequences namespaces make
+qualified system math io.encodings.ascii accessors
+tools.disassembler ;
+IN: tools.disassembler.gdb
+
+SINGLETON: gdb-disassembler
+
+: in-file ( -- path ) "gdb-in.txt" temp-file ;
+
+: out-file ( -- path ) "gdb-out.txt" temp-file ;
+
+: make-disassemble-cmd ( from to -- )
+ in-file ascii [
+ "attach " write
+ current-process-handle number>string print
+ "disassemble " write
+ [ number>string write bl ] bi@
+ ] with-file-writer ;
+
+: gdb-binary ( -- string ) "gdb" ;
+
+: run-gdb ( -- lines )
+ <process>
+ +closed+ >>stdin
+ out-file >>stdout
+ [ gdb-binary , "-x" , in-file , "-batch" , ] { } make >>command
+ try-process
+ out-file ascii file-lines ;
+
+M: gdb-disassembler disassemble*
+ make-disassemble-cmd run-gdb ;
+
+gdb-disassembler disassembler-backend set-global
--- /dev/null
+unportable
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2008 Slava Pestov, Jorge Acereda Macia.
+! See http://factorcode.org/license.txt for BSD license.
+USING: tools.disassembler namespaces combinators
+alien alien.syntax alien.c-types lexer parser kernel
+sequences layouts math math.parser system make fry arrays ;
+IN: tools.disassembler.udis
+
+<<
+"libudis86" {
+ { [ os macosx? ] [ "libudis86.0.dylib" ] }
+ { [ os unix? ] [ "libudis86.so.0" ] }
+ { [ os winnt? ] [ "libudis86.dll" ] }
+} cond "cdecl" add-library
+>>
+
+LIBRARY: libudis86
+
+TYPEDEF: char[592] ud
+
+FUNCTION: void ud_translate_intel ( ud* u ) ;
+FUNCTION: void ud_translate_att ( ud* u ) ;
+
+: UD_SYN_INTEL &: ud_translate_intel ; inline
+: UD_SYN_ATT &: ud_translate_att ; inline
+: UD_EOI -1 ; inline
+: UD_INP_CACHE_SZ 32 ; inline
+: UD_VENDOR_AMD 0 ; inline
+: UD_VENDOR_INTEL 1 ; inline
+
+FUNCTION: void ud_init ( ud* u ) ;
+FUNCTION: void ud_set_mode ( ud* u, uint8_t mode ) ;
+FUNCTION: void ud_set_pc ( ud* u, ulonglong pc ) ;
+FUNCTION: void ud_set_input_buffer ( ud* u, uint8_t* offset, size_t size ) ;
+FUNCTION: void ud_set_vendor ( ud* u, uint vendor ) ;
+FUNCTION: void ud_set_syntax ( ud* u, void* syntax ) ;
+FUNCTION: void ud_input_skip ( ud* u, size_t size ) ;
+FUNCTION: int ud_input_end ( ud* u ) ;
+FUNCTION: uint ud_decode ( ud* u ) ;
+FUNCTION: uint ud_disassemble ( ud* u ) ;
+FUNCTION: char* ud_insn_asm ( ud* u ) ;
+FUNCTION: void* ud_insn_ptr ( ud* u ) ;
+FUNCTION: ulonglong ud_insn_off ( ud* u ) ;
+FUNCTION: char* ud_insn_hex ( ud* u ) ;
+FUNCTION: uint ud_insn_len ( ud* u ) ;
+FUNCTION: char* ud_lookup_mnemonic ( int c ) ;
+
+: <ud> ( -- ud )
+ "ud" <c-object>
+ dup ud_init
+ dup cell-bits ud_set_mode
+ dup UD_SYN_INTEL ud_set_syntax ;
+
+SINGLETON: udis-disassembler
+
+: buf/len ( from to -- buf len ) [ drop <alien> ] [ swap - ] 2bi ;
+
+: format-disassembly ( lines -- lines' )
+ dup [ second length ] map supremum
+ '[
+ [
+ [ first >hex cell 2 * CHAR: 0 pad-left % ": " % ]
+ [ second _ CHAR: \s pad-right % " " % ]
+ [ third % ]
+ tri
+ ] "" make
+ ] map ;
+
+: (disassemble) ( ud -- lines )
+ [
+ dup '[
+ _ ud_disassemble 0 =
+ [ f ] [
+ _
+ [ ud_insn_off ]
+ [ ud_insn_hex ]
+ [ ud_insn_asm ]
+ tri 3array , t
+ ] if
+ ] loop
+ ] { } make ;
+
+M: udis-disassembler disassemble* ( from to -- buffer )
+ [ <ud> ] 2dip {
+ [ drop ud_set_pc ]
+ [ buf/len ud_set_input_buffer ]
+ [ 2drop (disassemble) format-disassembly ]
+ } 3cleave ;
+
+udis-disassembler disassembler-backend set-global
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax io.streams.string strings ;
+IN: tools.files
+
+HELP: directory.
+{ $values
+ { "path" "a pathname string" }
+}
+{ $description "Prints information about all files in a directory to the output stream in a cross-platform way similar to the Unix " { $snippet "ls" } " command." } ;
+
+ARTICLE: "tools.files" "Files tools"
+"The " { $vocab-link "tools.files" } " vocabulary implements directory files and file-systems listing in a cross-platform way." $nl
+"Listing a directory:"
+{ $subsection directory. } ;
+
+ABOUT: "tools.files"
--- /dev/null
+! Copyright (C) 2008 Your name.
+! See http://factorcode.org/license.txt for BSD license.
+USING: tools.test tools.files strings kernel ;
+IN: tools.files.tests
+
+\ directory. must-infer
+
+[ ] [ "" directory. ] unit-test
+
+[ ] [ file-systems. ] unit-test
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays combinators io io.files kernel
+math.parser sequences system vocabs.loader calendar math
+symbols fry prettyprint ;
+IN: tools.files
+
+<PRIVATE
+
+: ls-time ( timestamp -- string )
+ [ hour>> ] [ minute>> ] bi
+ [ number>string 2 CHAR: 0 pad-left ] bi@ ":" glue ;
+
+: ls-timestamp ( timestamp -- string )
+ [ month>> month-abbreviation ]
+ [ day>> number>string 2 CHAR: \s pad-left ]
+ [
+ dup year>> dup now year>> =
+ [ drop ls-time ] [ nip number>string ] if
+ 5 CHAR: \s pad-left
+ ] tri 3array " " join ;
+
+: read>string ( ? -- string ) "r" "-" ? ; inline
+
+: write>string ( ? -- string ) "w" "-" ? ; inline
+
+: execute>string ( ? -- string ) "x" "-" ? ; inline
+
+HOOK: (directory.) os ( path -- lines )
+
+PRIVATE>
+
+: directory. ( path -- )
+ [ (directory.) ] with-directory-files [ print ] each ;
+
+SYMBOLS: device-name mount-point type
+available-space free-space used-space total-space
+percent-used percent-free ;
+
+: percent ( real -- integer ) 100 * >integer ; inline
+
+: file-system-spec ( file-system-info obj -- str )
+ {
+ { device-name [ device-name>> [ "" ] unless* ] }
+ { mount-point [ mount-point>> [ "" ] unless* ] }
+ { type [ type>> [ "" ] unless* ] }
+ { available-space [ available-space>> [ 0 ] unless* ] }
+ { free-space [ free-space>> [ 0 ] unless* ] }
+ { used-space [ used-space>> [ 0 ] unless* ] }
+ { total-space [ total-space>> [ 0 ] unless* ] }
+ { percent-used [
+ [ used-space>> ] [ total-space>> ] bi
+ [ [ 0 ] unless* ] bi@ dup 0 =
+ [ 2drop 0 ] [ / percent ] if
+ ] }
+ } case ;
+
+: file-systems-info ( spec -- seq )
+ file-systems swap '[ _ [ file-system-spec ] with map ] map ;
+
+: print-file-systems ( spec -- )
+ [ file-systems-info ]
+ [ [ unparse ] map ] bi prefix simple-table. ;
+
+: file-systems. ( -- )
+ { device-name free-space used-space total-space percent-used mount-point }
+ print-file-systems ;
+
+{
+ { [ os unix? ] [ "tools.files.unix" ] }
+ { [ os windows? ] [ "tools.files.windows" ] }
+} cond require
--- /dev/null
+unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors combinators kernel system unicode.case
+io.unix.files tools.files generalizations strings
+arrays sequences io.files math.parser unix.groups unix.users
+tools.files.private unix.stat math ;
+IN: tools.files.unix
+
+<PRIVATE
+
+: unix-execute>string ( str bools -- str' )
+ swap {
+ { { t t } [ >lower ] }
+ { { t f } [ >upper ] }
+ { { f t } [ drop "x" ] }
+ [ 2drop "-" ]
+ } case ;
+
+: permissions-string ( permissions -- str )
+ {
+ [ type>> file-type>ch 1string ]
+ [ user-read? read>string ]
+ [ user-write? write>string ]
+ [ [ uid? ] [ user-execute? ] bi 2array "s" unix-execute>string ]
+ [ group-read? read>string ]
+ [ group-write? write>string ]
+ [ [ gid? ] [ group-execute? ] bi 2array "s" unix-execute>string ]
+ [ other-read? read>string ]
+ [ other-write? write>string ]
+ [ [ sticky? ] [ other-execute? ] bi 2array "t" unix-execute>string ]
+ } cleave 10 narray concat ;
+
+: mode>symbol ( mode -- ch )
+ S_IFMT bitand
+ {
+ { [ dup S_IFDIR = ] [ drop "/" ] }
+ { [ dup S_IFIFO = ] [ drop "|" ] }
+ { [ dup any-execute? ] [ drop "*" ] }
+ { [ dup S_IFLNK = ] [ drop "@" ] }
+ { [ dup S_IFWHT = ] [ drop "%" ] }
+ { [ dup S_IFSOCK = ] [ drop "=" ] }
+ { [ t ] [ drop "" ] }
+ } cond ;
+
+M: unix (directory.) ( path -- lines )
+ [ [
+ [
+ dup file-info
+ {
+ [ permissions-string ]
+ [ nlink>> number>string 3 CHAR: \s pad-left ]
+ ! [ uid>> ]
+ ! [ gid>> ]
+ [ size>> number>string 15 CHAR: \s pad-left ]
+ [ modified>> ls-timestamp ]
+ } cleave 4 narray swap suffix " " join
+ ] map
+ ] with-group-cache ] with-user-cache ;
+
+PRIVATE>
--- /dev/null
+Doug Coleman
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors calendar.format combinators io.files
+kernel math.parser sequences splitting system tools.files
+generalizations tools.files.private ;
+IN: tools.files.windows
+
+<PRIVATE
+
+: directory-or-size ( file-info -- str )
+ dup directory? [
+ drop "<DIR>" 20 CHAR: \s pad-right
+ ] [
+ size>> number>string 20 CHAR: \s pad-left
+ ] if ;
+
+M: windows (directory.) ( entries -- lines )
+ [
+ dup file-info {
+ [ modified>> timestamp>ymdhms ]
+ [ directory-or-size ]
+ } cleave 2 narray swap suffix " " join
+ ] map ;
+
+PRIVATE>
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: help.markup help.syntax kernel sequences strings ;
+USING: help.markup help.syntax kernel sequences byte-arrays
+strings ;
IN: tools.hexdump
HELP: hexdump.
-{ $values { "seq" sequence } }
+{ $values { "byte-array" byte-array } }
{ $description "Converts a sequence to its hexadecimal and ASCII representation sixteen characters at a time and writes it to standard out." } ;
HELP: hexdump
-{ $values { "seq" sequence } { "str" string } }
+{ $values { "byte-array" byte-array } { "str" string } }
{ $description "Converts a sequence to its hexadecimal and ASCII representation sixteen characters at a time. Lines are separated by a newline character." }
{ $see-also hexdump. } ;
-USING: tools.hexdump kernel sequences tools.test ;
+USING: tools.hexdump kernel sequences tools.test byte-arrays ;
IN: tools.hexdump.tests
-[ t ] [ "" hexdump "Length: 0, 0h\n" = ] unit-test
-[ t ] [ "abcdefghijklmnopqrstuvwxyz" hexdump "Length: 26, 1ah\n00000000h: 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 abcdefghijklmnop\n00000010h: 71 72 73 74 75 76 77 78 79 7a qrstuvwxyz\n" = ] unit-test
+[ t ] [ B{ } hexdump "Length: 0, 0h\n" = ] unit-test
+[ t ] [ "abcdefghijklmnopqrstuvwxyz" >byte-array hexdump "Length: 26, 1ah\n00000000h: 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 abcdefghijklmnop\n00000010h: 71 72 73 74 75 76 77 78 79 7a qrstuvwxyz\n" = ] unit-test
-[ t ] [ 256 [ ] map hexdump "Length: 256, 100h\n00000000h: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................\n00000010h: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ................\n00000020h: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f !\"#$%&'()*+,-./\n00000030h: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?\n00000040h: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO\n00000050h: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\\]^_\n00000060h: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno\n00000070h: 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~.\n00000080h: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f ................\n00000090h: 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f ................\n000000a0h: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af ................\n000000b0h: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf ................\n000000c0h: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf ................\n000000d0h: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df ................\n000000e0h: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef ................\n000000f0h: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff ................\n" = ] unit-test
+[ t ] [ 256 [ ] B{ } map-as hexdump "Length: 256, 100h\n00000000h: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................\n00000010h: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ................\n00000020h: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f !\"#$%&'()*+,-./\n00000030h: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?\n00000040h: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO\n00000050h: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\\]^_\n00000060h: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno\n00000070h: 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~.\n00000080h: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f ................\n00000090h: 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f ................\n000000a0h: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af ................\n000000b0h: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf ................\n000000c0h: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf ................\n000000d0h: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df ................\n000000e0h: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef ................\n000000f0h: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff ................\n" = ] unit-test
[
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays io io.streams.string kernel math math.parser
-namespaces sequences splitting grouping strings ascii ;
+namespaces sequences splitting grouping strings ascii byte-arrays ;
IN: tools.hexdump
<PRIVATE
PRIVATE>
-: hexdump. ( seq -- )
+GENERIC: hexdump. ( byte-array -- )
+
+M: byte-array hexdump.
[ length write-header ]
[ 16 <sliced-groups> [ write-hex-line ] each-index ] bi ;
-: hexdump ( seq -- str )
+: hexdump ( byte-array -- str )
[ hexdump. ] with-string-writer ;
-Prints formatted hex dump of an arbitrary sequence
+Prints the formatted hex dump of a byte-array
USING: kernel sequences vectors arrays generic assocs io math
namespaces parser prettyprint strings io.styles vectors words
system sorting splitting grouping math.parser classes memory
-combinators ;
+combinators fry ;
IN: tools.memory
<PRIVATE
: write-size ( n -- )
number>string
- dup length 4 > [ 3 cut* "," swap 3append ] when
+ dup length 4 > [ 3 cut* "," glue ] when
" KB" append write-cell ;
: write-total/used/free ( free total str -- )
[ "Largest free block:" write-labelled-size ]
} spread ;
-: heap-stat-step ( counts sizes obj -- )
- [ dup size swap class rot at+ ] keep
- 1 swap class rot at+ ;
+: heap-stat-step ( obj counts sizes -- )
+ [ over ] dip
+ [ [ class ] dip inc-at ]
+ [ [ [ size ] [ class ] bi ] dip at+ ] 2bi* ;
PRIVATE>
: heap-stats ( -- counts sizes )
H{ } clone H{ } clone
- [ >r 2dup r> heap-stat-step ] each-object ;
+ 2dup '[ _ _ heap-stat-step ] each-object ;
: heap-stats. ( -- )
heap-stats dup keys natural-sort standard-table-style [
[ ] [ [ 10 [ gc ] times ] profile ] unit-test
-[ ] [ [ 1000 sleep ] profile ] unit-test
+[ ] [ [ 1000000 sleep ] profile ] unit-test
[ ] [ profile. ] unit-test
: counter. ( obj n -- )
[
- >r [ (profile.) ] with-cell r>
+ [ [ (profile.) ] with-cell ] dip
[ number>string write ] with-cell
] with-row ;
<PRIVATE
-: root? ( string -- ? ) vocab-roots get member? ;
+: root? ( string -- ? ) vocab-roots get member? ;
-: length-changes? ( seq quot -- ? )
- dupd call [ length ] bi@ = not ; inline
+: contains-dot? ( string -- ? ) ".." swap subseq? ;
-: check-vocab-name ( string -- string )
- dup [ [ CHAR: . = ] trim ] length-changes?
- [ vocab-name-contains-dot ] when
-
- ".." over subseq? [ vocab-name-contains-dot ] when
+: contains-separator? ( string -- ? ) [ path-separator? ] contains? ;
- dup [ path-separator? ] contains?
- [ vocab-name-contains-separator ] when ;
+: check-vocab-name ( string -- string )
+ dup contains-dot? [ vocab-name-contains-dot ] when
+ dup contains-separator? [ vocab-name-contains-separator ] when ;
: check-root ( string -- string )
- check-vocab-name
- dup "resource:" head? [ "resource:" prepend ] unless
dup root? [ not-a-vocab-root ] unless ;
: directory-exists ( path -- )
{ $description "Runs unit tests for all loaded vocabularies." } ;
HELP: run-all-tests
-{ $values { "prefix" "a vocabulary name" } { "failures" "an association list of unit test failures" } }
+{ $values { "failures" "an association list of unit test failures" } }
{ $description "Runs unit tests for all loaded vocabularies and outputs unit test failures as documented in " { $link "tools.test.failure" } "." } ;
HELP: test-failures.
--- /dev/null
+IN: tools.test.tests
+USING: tools.test ;
+
+\ test-all must-infer
USING: accessors namespaces arrays prettyprint sequences kernel
vectors quotations words parser assocs combinators continuations
debugger io io.styles io.files vocabs vocabs.loader source-files
-compiler.units summary stack-checker effects tools.vocabs ;
+compiler.units summary stack-checker effects tools.vocabs fry ;
IN: tools.test
SYMBOL: failures
] if ;
: unit-test ( output input -- )
- [ 2array ] 2keep [
- { } swap with-datastack swap >array assert=
- ] 2curry (unit-test) ;
+ [ 2array ] 2keep '[
+ _ { } _ with-datastack swap >array assert=
+ ] (unit-test) ;
: short-effect ( effect -- pair )
[ in>> length ] [ out>> length ] bi 2array ;
: must-infer-as ( effect quot -- )
- >r 1quotation r> [ infer short-effect ] curry unit-test ;
+ [ 1quotation ] dip '[ _ infer short-effect ] unit-test ;
: must-infer ( word/quot -- )
dup word? [ 1quotation ] when
- [ infer drop ] curry [ ] swap unit-test ;
+ '[ _ infer drop ] [ ] swap unit-test ;
: must-fail-with ( quot pred -- )
- >r [ f ] compose r>
- [ recover ] 2curry
- [ t ] swap unit-test ;
+ [ '[ @ f ] ] dip '[ _ _ recover ] [ t ] swap unit-test ;
: must-fail ( quot -- )
[ drop t ] must-fail-with ;
: (run-test) ( vocab -- )
- dup vocab-source-loaded? [
+ dup vocab source-loaded?>> [
vocab-tests [ run-file ] each
] [ drop ] if ;
: test ( prefix -- )
run-tests test-failures. ;
-: run-all-tests ( prefix -- failures )
+: run-all-tests ( -- failures )
"" run-tests ;
: test-all ( -- )
] with-cell\r
[\r
sleep-entry>> [\r
- key>> millis [-] number>string write\r
- " ms" write\r
+ key>> micros [-] number>string write\r
+ " us" write\r
] when*\r
] with-cell ;\r
\r
"A lower-level word puts timings on the stack, intead of printing:"
{ $subsection benchmark }
"You can also read the system clock and garbage collection statistics directly:"
-{ $subsection millis }
+{ $subsection micros }
{ $subsection gc-stats }
{ $see-also "profiling" } ;
HELP: benchmark
{ $values { "quot" "a quotation" }
- { "runtime" "an integer denoting milliseconds" } }
+ { "runtime" "the runtime in microseconds" } }
{ $description "Runs a quotation, measuring the total wall clock time." }
{ $notes "A nicer word for interactive use is " { $link time } "." } ;
{ $values { "quot" "a quotation" } }
{ $description "Runs a quotation and then prints the total run time and some garbage collection statistics." } ;
-{ benchmark millis time } related-words
+{ benchmark micros time } related-words
IN: tools.time
: benchmark ( quot -- runtime )
- millis >r call millis r> - ; inline
+ micros [ call micros ] dip - ; inline
: time. ( data -- )
unclip
- "==== RUNNING TIME" print nl pprint " ms" print nl
+ "==== RUNNING TIME" print nl 1000000 /f pprint " seconds" print nl
4 cut*
"==== GARBAGE COLLECTION" print nl
[
6 group
{
"GC count:"
- "Cumulative GC time (ms):"
- "Longest GC pause (ms):"
- "Average GC pause (ms):"
+ "Cumulative GC time (us):"
+ "Longest GC pause (us):"
+ "Average GC pause (us):"
"Objects copied:"
"Bytes copied:"
} prefix
[
nl
{
- "Total GC time (ms):"
+ "Total GC time (us):"
"Cards scanned:"
"Decks scanned:"
"Code heap literal scans:"
] bi* ;
: time ( quot -- )
- gc-reset millis >r call gc-stats millis r> - prefix time. ; inline
+ gc-reset micros [ call gc-stats micros ] dip - prefix time. ; inline
Slava Pestov
+Eduardo Cavazos
USING: help.markup help.syntax io strings ;
IN: tools.vocabs.browser
+ARTICLE: "vocab-tags" "Vocabulary tags"
+{ $all-tags } ;
+
+ARTICLE: "vocab-authors" "Vocabulary authors"
+{ $all-authors } ;
+
ARTICLE: "vocab-index" "Vocabulary index"
-{ $tags }
-{ $authors }
+{ $subsection "vocab-tags" }
+{ $subsection "vocab-authors" }
{ $describe-vocab "" } ;
+
+HELP: words.
+{ $values { "vocab" "a vocabulary name" } }
+{ $description "Printings a listing of all the words in a vocabulary, categorized by type." } ;
! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel combinators vocabs vocabs.loader
-tools.vocabs io io.files io.styles help.markup help.stylesheet
-sequences assocs help.topics namespaces prettyprint words
-sorting definitions arrays summary sets generic ;
+USING: accessors arrays assocs classes classes.builtin
+classes.intersection classes.mixin classes.predicate
+classes.singleton classes.tuple classes.union combinators
+definitions effects fry generic help help.markup
+help.stylesheet help.topics io io.files io.styles kernel macros
+make namespaces prettyprint sequences sets sorting summary
+tools.vocabs vocabs vocabs.loader words ;
IN: tools.vocabs.browser
: vocab-status-string ( vocab -- string )
: vocab. ( vocab -- )
[
- dup [ write-status ] with-cell
- dup [ ($link) ] with-cell
- [ vocab-summary write ] with-cell
+ [ [ write-status ] with-cell ]
+ [ [ ($link) ] with-cell ]
+ [ [ vocab-summary write ] with-cell ] tri
] with-row ;
: vocab-headings. ( -- )
[ "Children from " prepend ] [ "Children" ] if*
$heading ;
-: vocabs. ( assoc -- )
+: $vocabs ( assoc -- )
[
- [
- drop
- ] [
- swap root-heading.
- standard-table-style [
- vocab-headings. [ vocab. ] each
- ] ($grid)
+ [ drop ] [
+ [ root-heading. ]
+ [
+ standard-table-style [
+ vocab-headings. [ vocab. ] each
+ ] ($grid)
+ ] bi*
] if-empty
] assoc-each ;
-: describe-summary ( vocab -- )
- vocab-summary [
- "Summary" $heading print-element
- ] when* ;
-
TUPLE: vocab-tag name ;
INSTANCE: vocab-tag topic
C: <vocab-tag> vocab-tag
-: tags. ( seq -- ) [ <vocab-tag> ] map $links ;
-
-: describe-tags ( vocab -- )
- vocab-tags f like [
- "Tags" $heading tags.
- ] when* ;
+: $tags ( seq -- ) [ <vocab-tag> ] map $links ;
TUPLE: vocab-author name ;
C: <vocab-author> vocab-author
-: authors. ( seq -- ) [ <vocab-author> ] map $links ;
-
-: describe-authors ( vocab -- )
- vocab-authors f like [
- "Authors" $heading authors.
- ] when* ;
+: $authors ( seq -- ) [ <vocab-author> ] map $links ;
: describe-help ( vocab -- )
- vocab-help [
- "Documentation" $heading ($link)
- ] when* ;
+ [
+ dup vocab-help
+ [ "Documentation" $heading ($link) ]
+ [ "Summary" $heading vocab-summary print-element ]
+ ?if
+ ] unless-empty ;
: describe-children ( vocab -- )
- vocab-name all-child-vocabs vocabs. ;
+ vocab-name all-child-vocabs $vocabs ;
: describe-files ( vocab -- )
vocab-files [ <pathname> ] map [
] with-nesting
] with-style
] ($block)
- ] when* ;
+ ] unless-empty ;
-: describe-words ( vocab -- )
- words [
- "Words" $heading
- natural-sort $links
+: describe-tuple-classes ( classes -- )
+ [
+ "Tuple classes" $subheading
+ [
+ [ <$link> ]
+ [ superclass <$link> ]
+ [ "slots" word-prop [ name>> ] map " " join \ $snippet swap 2array ]
+ tri 3array
+ ] map
+ { { $strong "Class" } { $strong "Superclass" } { $strong "Slots" } } prefix
+ $table
+ ] unless-empty ;
+
+: describe-predicate-classes ( classes -- )
+ [
+ "Predicate classes" $subheading
+ [
+ [ <$link> ]
+ [ superclass <$link> ]
+ bi 2array
+ ] map
+ { { $strong "Class" } { $strong "Superclass" } } prefix
+ $table
+ ] unless-empty ;
+
+: (describe-classes) ( classes heading -- )
+ '[
+ _ $subheading
+ [ <$link> 1array ] map $table
+ ] unless-empty ;
+
+: describe-builtin-classes ( classes -- )
+ "Builtin classes" (describe-classes) ;
+
+: describe-singleton-classes ( classes -- )
+ "Singleton classes" (describe-classes) ;
+
+: describe-mixin-classes ( classes -- )
+ "Mixin classes" (describe-classes) ;
+
+: describe-union-classes ( classes -- )
+ "Union classes" (describe-classes) ;
+
+: describe-intersection-classes ( classes -- )
+ "Intersection classes" (describe-classes) ;
+
+: describe-classes ( classes -- )
+ [ builtin-class? ] partition
+ [ tuple-class? ] partition
+ [ singleton-class? ] partition
+ [ predicate-class? ] partition
+ [ mixin-class? ] partition
+ [ union-class? ] partition
+ [ intersection-class? ] filter
+ {
+ [ describe-builtin-classes ]
+ [ describe-tuple-classes ]
+ [ describe-singleton-classes ]
+ [ describe-predicate-classes ]
+ [ describe-mixin-classes ]
+ [ describe-union-classes ]
+ [ describe-intersection-classes ]
+ } spread ;
+
+: word-syntax ( word -- string/f )
+ \ $syntax swap word-help elements dup length 1 =
+ [ first second ] [ drop f ] if ;
+
+: describe-parsing ( words -- )
+ [
+ "Parsing words" $subheading
+ [
+ [ <$link> ]
+ [ word-syntax dup [ \ $snippet swap 2array ] when ]
+ bi 2array
+ ] map
+ { { $strong "Word" } { $strong "Syntax" } } prefix
+ $table
] unless-empty ;
-: vocab-xref ( vocab quot -- vocabs )
- >r dup vocab-name swap words [ generic? not ] filter r> map
- [ [ word? ] filter [ vocabulary>> ] map ] gather natural-sort
- remove sift ; inline
+: (describe-words) ( words heading -- )
+ '[
+ _ $subheading
+ [
+ [ <$link> ]
+ [ stack-effect dup [ effect>string \ $snippet swap 2array ] when ]
+ bi 2array
+ ] map
+ { { $strong "Word" } { $strong "Stack effect" } } prefix
+ $table
+ ] unless-empty ;
+
+: describe-generics ( words -- )
+ "Generic words" (describe-words) ;
+
+: describe-macros ( words -- )
+ "Macro words" (describe-words) ;
-: vocab-uses ( vocab -- vocabs ) [ uses ] vocab-xref ;
+: describe-primitives ( words -- )
+ "Primitives" (describe-words) ;
-: vocab-usage ( vocab -- vocabs ) [ usage ] vocab-xref ;
+: describe-compounds ( words -- )
+ "Ordinary words" (describe-words) ;
-: describe-uses ( vocab -- )
- vocab-uses [
- "Uses" $heading
- $vocab-links
+: describe-predicates ( words -- )
+ "Class predicate words" (describe-words) ;
+
+: describe-symbols ( words -- )
+ [
+ "Symbol words" $subheading
+ [ <$link> 1array ] map $table
] unless-empty ;
-: describe-usage ( vocab -- )
- vocab-usage [
- "Used by" $heading
- $vocab-links
+: describe-words ( vocab -- )
+ words [
+ "Words" $heading
+
+ natural-sort
+ [ [ class? ] filter describe-classes ]
+ [
+ [ [ class? ] [ symbol? ] bi and not ] filter
+ [ parsing-word? ] partition
+ [ generic? ] partition
+ [ macro? ] partition
+ [ symbol? ] partition
+ [ primitive? ] partition
+ [ predicate? ] partition swap
+ {
+ [ describe-parsing ]
+ [ describe-generics ]
+ [ describe-macros ]
+ [ describe-symbols ]
+ [ describe-primitives ]
+ [ describe-compounds ]
+ [ describe-predicates ]
+ } spread
+ ] bi
] unless-empty ;
+: words. ( vocab -- )
+ last-element off
+ vocab-name describe-words ;
+
+: describe-metadata ( vocab -- )
+ [
+ [ vocab-tags [ "Tags:" swap \ $tags prefix 2array , ] unless-empty ]
+ [ vocab-authors [ "Authors:" swap \ $authors prefix 2array , ] unless-empty ]
+ bi
+ ] { } make
+ [ "Meta-data" $heading $table ] unless-empty ;
+
: $describe-vocab ( element -- )
- first
- dup describe-children
- dup find-vocab-root [
- dup describe-summary
- dup describe-tags
- dup describe-authors
- dup describe-files
- ] when
- dup vocab [
- dup describe-help
- dup describe-words
- dup describe-uses
- dup describe-usage
- ] when drop ;
+ first {
+ [ describe-help ]
+ [ describe-metadata ]
+ [ describe-words ]
+ [ describe-files ]
+ [ describe-children ]
+ } cleave ;
: keyed-vocabs ( str quot -- seq )
all-vocabs [
- swap >r
- [ >r 2dup r> swap call member? ] filter
- r> swap
+ swap [
+ [ [ 2dup ] dip swap call member? ] filter
+ ] dip swap
] assoc-map 2nip ; inline
: tagged ( tag -- assoc )
[ vocab-authors ] keyed-vocabs ;
: $tagged-vocabs ( element -- )
- first tagged vocabs. ;
+ first tagged $vocabs ;
: $authored-vocabs ( element -- )
- first authored vocabs. ;
+ first authored $vocabs ;
-: $tags ( element -- )
- drop "Tags" $heading all-tags tags. ;
+: $all-tags ( element -- )
+ drop "Tags" $heading all-tags $tags ;
-: $authors ( element -- )
- drop "Authors" $heading all-authors authors. ;
+: $all-authors ( element -- )
+ drop "Authors" $heading all-authors $authors ;
INSTANCE: vocab topic
M: vocab-tag >link ;
M: vocab-tag article-title
- name>> "Vocabularies tagged ``" swap "''" 3append ;
+ name>> "Vocabularies tagged ``" "''" surround ;
M: vocab-tag article-name name>> ;
[ monitor-thread ] "Vocabulary monitor" spawn drop ;\r
\r
[\r
- "-no-monitors" cli-args member? [\r
- start-monitor-thread\r
- ] unless\r
+ "-no-monitors" (command-line) member?\r
+ [ start-monitor-thread ] unless\r
] "tools.vocabs.monitor" add-init-hook\r
vocabs.loader vocabs sequences namespaces make math.parser\r
arrays hashtables assocs memoize summary sorting splitting\r
combinators source-files debugger continuations compiler.errors\r
-init checksums checksums.crc32 sets accessors ;\r
+init checksums checksums.crc32 sets accessors generic\r
+definitions words ;\r
IN: tools.vocabs\r
\r
+: vocab-xref ( vocab quot -- vocabs )\r
+ [ [ vocab-name ] [ words [ generic? not ] filter ] bi ] dip map\r
+ [\r
+ [ [ word? ] [ generic? not ] bi and ] filter [\r
+ dup method-body?\r
+ [ "method-generic" word-prop ] when\r
+ vocabulary>>\r
+ ] map\r
+ ] gather natural-sort remove sift ; inline\r
+\r
+: vocabs. ( seq -- )\r
+ [ dup >vocab-link write-object nl ] each ;\r
+\r
+: vocab-uses ( vocab -- vocabs ) [ uses ] vocab-xref ;\r
+\r
+: vocab-uses. ( vocab -- ) vocab-uses vocabs. ;\r
+\r
+: vocab-usage ( vocab -- vocabs ) [ usage ] vocab-xref ;\r
+\r
+: vocab-usage. ( vocab -- ) vocab-usage vocabs. ;\r
+\r
: vocab-tests-file ( vocab -- path )\r
dup "-tests.factor" vocab-dir+ vocab-append-path dup\r
[ dup exists? [ drop f ] unless ] [ drop f ] if ;\r
[\r
[\r
[ modified-sources ]\r
- [ vocab-source-loaded? ]\r
+ [ vocab source-loaded?>> ]\r
[ vocab-source-path ]\r
tri (to-refresh)\r
] [\r
[ modified-docs ]\r
- [ vocab-docs-loaded? ]\r
+ [ vocab docs-loaded?>> ]\r
[ vocab-docs-path ]\r
tri (to-refresh)\r
] bi\r
: do-refresh ( modified-sources modified-docs unchanged -- )\r
unchanged-vocabs\r
[\r
- [ [ f swap set-vocab-source-loaded? ] each ]\r
- [ [ f swap set-vocab-docs-loaded? ] each ] bi*\r
+ [ [ vocab f >>source-loaded? drop ] each ]\r
+ [ [ vocab f >>docs-loaded? drop ] each ] bi*\r
]\r
[\r
append prune\r
M: vocab-link summary vocab-summary ;\r
\r
: set-vocab-summary ( string vocab -- )\r
- >r 1array r>\r
+ [ 1array ] dip\r
dup vocab-summary-path\r
set-vocab-file-contents ;\r
\r
vocab-dir append-path dup exists?\r
[ subdirs ] [ drop { } ] if\r
] keep [\r
- swap [ "." swap 3append ] with map\r
+ swap [ "." glue ] with map\r
] unless-empty ;\r
\r
: vocabs-in-dir ( root name -- )\r
] unit-test
[ { "Yo" 2 } ] [
- [ 2 >r "Yo" r> ] test-walker
+ [ 2 [ "Yo" ] dip ] test-walker
+] unit-test
+
+[ { "Yo" 2 3 } ] [
+ [ 2 [ "Yo" ] dip 3 ] test-walker
] unit-test
[ { 2 } ] [
sequences math namespaces.private continuations.private
concurrency.messaging quotations kernel.private words
sequences.private assocs models models.filter arrays accessors
-generic generic.standard definitions make ;
+generic generic.standard definitions make sbufs ;
IN: tools.walker
SYMBOL: show-walker-hook ! ( status continuation thread -- )
: (step-into-quot) ( quot -- ) add-breakpoint call ;
+: (step-into-dip) ( quot -- ) add-breakpoint dip ;
+
+: (step-into-2dip) ( quot -- ) add-breakpoint 2dip ;
+
+: (step-into-3dip) ( quot -- ) add-breakpoint 3dip ;
+
: (step-into-if) ( true false ? -- ) ? (step-into-quot) ;
: (step-into-dispatch) ( array n -- ) nth (step-into-quot) ;
: (step-into-continuation) ( -- )
continuation callstack >>call break ;
-: (step-into-call-next-method) ( class generic -- )
+: (step-into-call-next-method) ( method -- )
next-method-quot (step-into-quot) ;
! Messages sent to walker thread
: change-frame ( continuation quot -- continuation' )
#! Applies quot to innermost call frame of the
#! continuation.
- >r clone r> [
- >r clone r>
+ [ clone ] dip [
+ [ clone ] dip
[
- >r
- [ innermost-frame-scan 1+ ]
- [ innermost-frame-quot ] bi
- r> call
+ [
+ [ innermost-frame-scan 1+ ]
+ [ innermost-frame-quot ] bi
+ ] dip call
]
[ drop set-innermost-frame-quot ]
[ drop ]
2tri
] curry change-call ; inline
-: step-msg ( continuation -- continuation' )
+: step-msg ( continuation -- continuation' ) USE: io
[
- 2dup nth \ break = [
- nip
- ] [
- swap 1+ cut [ break ] swap 3append
+ 2dup length = [ nip [ break ] append ] [
+ 2dup nth \ break = [ nip ] [
+ swap 1+ cut [ break ] glue
+ ] if
] if
] change-frame ;
{
{ call [ (step-into-quot) ] }
+ { dip [ (step-into-dip) ] }
+ { 2dip [ (step-into-2dip) ] }
+ { 3dip [ (step-into-3dip) ] }
{ (throw) [ drop (step-into-quot) ] }
{ execute [ (step-into-execute) ] }
{ if [ (step-into-if) ] }
{ (call-next-method) [ (step-into-call-next-method) ] }
} [ "step-into" set-word-prop ] assoc-each
+! Never step into these words
{
>n ndrop >c c>
continue continue-with
: step-into-msg ( continuation -- continuation' )
[
swap cut [
- swap % unclip {
- { [ dup \ break eq? ] [ , ] }
- { [ dup quotation? ] [ add-breakpoint , \ break , ] }
- { [ dup array? ] [ add-breakpoint , \ break , ] }
- { [ dup word? ] [ literalize , \ (step-into-execute) , ] }
- [ , \ break , ]
- } cond %
+ swap %
+ [ \ break , ] [
+ unclip {
+ { [ dup \ break eq? ] [ , ] }
+ { [ dup quotation? ] [ add-breakpoint , \ break , ] }
+ { [ dup array? ] [ add-breakpoint , \ break , ] }
+ { [ dup word? ] [ literalize , \ (step-into-execute) , ] }
+ [ , \ break , ]
+ } cond %
+ ] if-empty
] [ ] make
] change-frame ;
: walker-loop ( -- )
+running+ set-status
- [ status +stopped+ eq? not ] [
+ [ status +stopped+ eq? ] [
[
{
! ignore these commands while the thread is
[ walker-suspended ]
} case
] handle-synchronous
- ] [ ] while ;
+ ] [ ] until ;
: associate-thread ( walker -- )
walker-thread tset
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: byte-arrays strings sequences sequences.private
-fry kernel words parser lexer assocs math.order ;
+fry kernel words parser lexer assocs math math.order summary ;
IN: tr
+ERROR: bad-tr ;
+
+M: bad-tr summary
+ drop "TR: can only be used with ASCII characters" ;
+
<PRIVATE
+: ascii? ( ch -- ? ) 0 127 between? ; inline
+
+: tr-nth ( n mapping -- ch ) nth-unsafe 127 bitand ; inline
+
+: check-tr ( from to -- )
+ [ [ ascii? ] all? ] both? [ bad-tr ] unless ;
+
: compute-tr ( quot from to -- mapping )
- zip [ 256 ] 2dip '[ [ @ _ at ] keep or ] B{ } map-as ; inline
+ zip [ 128 ] 2dip '[ [ @ _ at ] keep or ] B{ } map-as ; inline
: tr-hints ( word -- )
{ { byte-array } { string } } "specializer" set-word-prop ;
create-in dup tr-hints ;
: tr-quot ( mapping -- quot )
- '[ [ dup 0 255 between? [ _ nth-unsafe ] when ] map ] ;
+ '[ [ dup ascii? [ _ tr-nth ] when ] map ] ;
: define-tr ( word mapping -- )
tr-quot (( seq -- translated )) define-declared ;
: fast-tr-quot ( mapping -- quot )
- '[ [ _ nth-unsafe ] change-each ] ;
+ '[ [ _ tr-nth ] change-each ] ;
: define-fast-tr ( word mapping -- )
fast-tr-quot (( seq -- )) define-declared ;
: TR:
scan parse-definition
unclip-last [ unclip-last ] dip compute-tr
+ [ check-tr ]
[ [ create-tr ] dip define-tr ]
- [ [ "-fast" append create-tr ] dip define-fast-tr ] 2bi ;
+ [ [ "-fast" append create-tr ] dip define-fast-tr ] 2tri ;
parsing
HOOK: (close-window) ui-backend ( handle -- )
+HOOK: (open-offscreen-buffer) ui-backend ( world -- )
+
+HOOK: (close-offscreen-buffer) ui-backend ( handle -- )
+
HOOK: raise-window* ui-backend ( world -- )
-HOOK: select-gl-context ui-backend ( handle -- )
+GENERIC: select-gl-context ( handle -- )
+
+GENERIC: flush-gl-context ( handle -- )
-HOOK: flush-gl-context ui-backend ( handle -- )
+HOOK: offscreen-pixels ui-backend ( world -- alien w h )
HOOK: beep ui-backend ( -- )
: gadget-copy ( gadget clipboard -- )
over gadget-selection?
- [ >r [ gadget-selection ] keep r> copy-clipboard ]
+ [ [ [ gadget-selection ] keep ] dip copy-clipboard ]
[ 2drop ]
if ;
! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors math arrays cocoa cocoa.application
+USING: accessors math arrays assocs cocoa cocoa.application
command-line kernel memory namespaces cocoa.messages
cocoa.runtime cocoa.subclassing cocoa.pasteboard cocoa.types
-cocoa.windows cocoa.classes cocoa.application sequences system
+cocoa.windows cocoa.classes cocoa.nibs sequences system
ui ui.backend ui.clipboards ui.gadgets ui.gadgets.worlds
-ui.cocoa.views core-foundation threads math.geometry.rect ;
+ui.cocoa.views core-foundation threads math.geometry.rect fry
+libc generalizations alien.c-types cocoa.views combinators ;
IN: ui.cocoa
-TUPLE: handle view window ;
+TUPLE: handle ;
+TUPLE: window-handle < handle view window ;
+TUPLE: offscreen-handle < handle context buffer ;
-C: <handle> handle
+C: <window-handle> window-handle
+C: <offscreen-handle> offscreen-handle
SINGLETON: cocoa-ui-backend
M: cocoa-ui-backend do-events ( -- )
- [
- [ NSApp [ do-event ] curry loop ui-wait ] ui-try
- ] with-autorelease-pool ;
+ [ NSApp '[ _ do-event ] loop ui-wait ] with-autorelease-pool ;
TUPLE: pasteboard handle ;
<clipboard> selection set-global ;
: world>NSRect ( world -- NSRect )
- dup window-loc>> first2 rot rect-dim first2 <NSRect> ;
+ [ window-loc>> ] [ dim>> ] bi [ first2 ] bi@ <NSRect> ;
: gadget-window ( world -- )
- [
- dup <FactorView>
- dup rot world>NSRect <ViewWindow>
- dup install-window-delegate
- over -> release
- <handle>
- ] keep (>>handle) ;
+ dup <FactorView>
+ 2dup swap world>NSRect <ViewWindow>
+ [ [ -> release ] [ install-window-delegate ] bi* ]
+ [ <window-handle> ] 2bi
+ >>handle drop ;
M: cocoa-ui-backend set-title ( string world -- )
handle>> window>> swap <NSString> -> setTitle: ;
NSApp 1 -> activateIgnoringOtherApps:
] when* ;
-M: cocoa-ui-backend select-gl-context ( handle -- )
- view>> -> openGLContext -> makeCurrentContext ;
+: pixel-size ( pixel-format -- size )
+ 0 <int> [ NSOpenGLPFAColorSize 0 -> getValues:forAttribute:forVirtualScreen: ]
+ keep *int -3 shift ;
-M: cocoa-ui-backend flush-gl-context ( handle -- )
- view>> -> openGLContext -> flushBuffer ;
+: offscreen-buffer ( world pixel-format -- alien w h pitch )
+ [ dim>> first2 ] [ pixel-size ] bi*
+ { [ * * malloc ] [ 2drop ] [ drop nip ] [ nip * ] } 3cleave ;
+
+: gadget-offscreen-context ( world -- context buffer )
+ NSOpenGLPFAOffScreen 1array <PixelFormat>
+ [ nip NSOpenGLContext -> alloc swap f -> initWithFormat:shareContext: dup ]
+ [ offscreen-buffer ] 2bi
+ 4 npick [ -> setOffScreen:width:height:rowbytes: ] dip ;
+
+M: cocoa-ui-backend (open-offscreen-buffer) ( world -- )
+ dup gadget-offscreen-context <offscreen-handle> >>handle drop ;
+
+M: cocoa-ui-backend (close-offscreen-buffer) ( handle -- )
+ [ context>> -> release ]
+ [ buffer>> free ] bi ;
+
+GENERIC: (gl-context) ( handle -- context )
+M: window-handle (gl-context) view>> -> openGLContext ;
+M: offscreen-handle (gl-context) context>> ;
+
+M: handle select-gl-context ( handle -- )
+ (gl-context) -> makeCurrentContext ;
+
+M: handle flush-gl-context ( handle -- )
+ (gl-context) -> flushBuffer ;
+
+M: cocoa-ui-backend offscreen-pixels ( world -- alien w h )
+ [ handle>> buffer>> ] [ dim>> first2 neg ] bi ;
M: cocoa-ui-backend beep ( -- )
NSBeep ;
+CLASS: {
+ { +superclass+ "NSObject" }
+ { +name+ "FactorApplicationDelegate" }
+}
+
+{ "applicationDidFinishLaunching:" "void" { "id" "SEL" "id" }
+ [ 3drop event-loop ]
+} ;
+
+: install-app-delegate ( -- )
+ NSApp FactorApplicationDelegate install-delegate ;
+
SYMBOL: cocoa-init-hook
+cocoa-init-hook global [
+ [ "MiniFactor.nib" load-nib install-app-delegate ] or
+] change-at
+
M: cocoa-ui-backend ui
"UI" assert.app [
[
init-clipboard
- cocoa-init-hook get [ call ] when*
+ cocoa-init-hook get call
start-ui
- finish-launching
- event-loop
+ NSApp -> run
] ui-running
] with-cocoa ;
-! Copyright (C) 2006, 2007 Slava Pestov.
+! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: alien.syntax cocoa cocoa.nibs cocoa.application
cocoa.classes cocoa.dialogs cocoa.pasteboard cocoa.subclassing
-core-foundation help.topics kernel memory namespaces parser
-system ui ui.tools.browser ui.tools.listener ui.tools.workspace
-ui.cocoa eval locals ;
+core-foundation core-foundation.strings help.topics kernel
+memory namespaces parser system ui ui.tools.browser
+ui.tools.listener ui.tools.workspace ui.cocoa eval locals ;
IN: ui.cocoa.tools
: finder-run-files ( alien -- )
! Handle Open events from the Finder
CLASS: {
- { +superclass+ "NSObject" }
- { +name+ "FactorApplicationDelegate" }
+ { +superclass+ "FactorApplicationDelegate" }
+ { +name+ "FactorWorkspaceApplicationDelegate" }
}
{ "application:openFiles:" "void" { "id" "SEL" "id" "id" }
- [ >r 3drop r> finder-run-files ]
+ [ [ 3drop ] dip finder-run-files ]
}
{ "newFactorWorkspace:" "id" { "id" "SEL" "id" }
} ;
: install-app-delegate ( -- )
- NSApp FactorApplicationDelegate install-delegate ;
+ NSApp FactorWorkspaceApplicationDelegate install-delegate ;
! Service support; evaluate Factor code from other apps
:: do-service ( pboard error quot -- )
--- /dev/null
+IN: ui.cocoa.views.tests
+USING: ui.cocoa.views tools.test kernel math.geometry.rect
+namespaces ;
+
+[ t ] [
+ T{ rect
+ { loc { 0 0 } }
+ { dim { 1000 1000 } }
+ } "world" set
+
+ T{ rect
+ { loc { 1.5 2.25 } }
+ { dim { 13.0 14.0 } }
+ } dup "world" get rect>NSRect "world" get NSRect>rect =
+] unit-test
math cocoa.messages cocoa.subclassing cocoa.classes cocoa.views
cocoa.application cocoa.pasteboard cocoa.types cocoa.windows
sequences ui ui.gadgets ui.gadgets.worlds ui.gestures
-core-foundation threads combinators math.geometry.rect ;
+core-foundation.strings threads combinators math.geometry.rect ;
IN: ui.cocoa.views
: send-mouse-moved ( view event -- )
- over >r mouse-location r> window move-hand fire-motion ;
+ [ mouse-location ] [ drop window ] 2bi move-hand fire-motion ;
: button ( event -- n )
#! Cocoa -> Factor UI button mapping
{
{ S+ HEX: 20000 }
{ C+ HEX: 40000 }
- { A+ HEX: 80000 }
- { M+ HEX: 100000 }
+ { A+ HEX: 100000 }
+ { M+ HEX: 80000 }
} ;
: key-codes
: key-event>gesture ( event -- modifiers keycode action? )
dup event-modifiers swap key-code ;
-: send-key-event ( view event quot -- ? )
- >r key-event>gesture r> call swap window-focus
- send-gesture ; inline
-
-: send-user-input ( view string -- )
- CF>string swap window-focus user-input ;
+: send-key-event ( view gesture -- )
+ swap window propagate-key-gesture ;
: interpret-key-event ( view event -- )
NSArray swap -> arrayWithObject: -> interpretKeyEvents: ;
: send-key-down-event ( view event -- )
- 2dup [ <key-down> ] send-key-event
- [ interpret-key-event ] [ 2drop ] if ;
+ [ key-event>gesture <key-down> send-key-event ]
+ [ interpret-key-event ]
+ 2bi ;
: send-key-up-event ( view event -- )
- [ <key-up> ] send-key-event drop ;
+ key-event>gesture <key-up> send-key-event ;
: mouse-event>gesture ( event -- modifiers button )
dup event-modifiers swap button ;
: send-button-down$ ( view event -- )
- [ mouse-event>gesture <button-down> ] 2keep
- mouse-location rot window send-button-down ;
+ [ nip mouse-event>gesture <button-down> ]
+ [ mouse-location ]
+ [ drop window ]
+ 2tri send-button-down ;
: send-button-up$ ( view event -- )
- [ mouse-event>gesture <button-up> ] 2keep
- mouse-location rot window send-button-up ;
+ [ nip mouse-event>gesture <button-up> ]
+ [ mouse-location ]
+ [ drop window ]
+ 2tri send-button-up ;
: send-wheel$ ( view event -- )
- over >r
- dup -> deltaX sgn neg over -> deltaY sgn neg 2array -rot
- mouse-location
- r> window send-wheel ;
+ [ nip [ -> deltaX ] [ -> deltaY ] bi [ sgn neg ] bi@ 2array ]
+ [ mouse-location ]
+ [ drop window ]
+ 2tri send-wheel ;
: send-action$ ( view event gesture -- junk )
- >r drop window r> send-action f ;
+ [ drop window ] dip send-action f ;
: add-resize-observer ( observer object -- )
- >r "updateFactorGadgetSize:"
- "NSViewFrameDidChangeNotification" <NSString>
- r> add-observer ;
+ [
+ "updateFactorGadgetSize:"
+ "NSViewFrameDidChangeNotification" <NSString>
+ ] dip add-observer ;
: string-or-nil? ( NSString -- ? )
[ CF>string NSStringPboardType = ] [ t ] if* ;
: valid-service? ( gadget send-type return-type -- ? )
- over string-or-nil? over string-or-nil? and [
- drop [ gadget-selection? ] [ drop t ] if
- ] [
- 3drop f
- ] if ;
+ over string-or-nil? over string-or-nil? and
+ [ drop [ gadget-selection? ] [ drop t ] if ] [ 3drop f ] if ;
: NSRect>rect ( NSRect world -- rect )
- >r dup NSRect-x over NSRect-y r>
- rect-dim second swap - 2array
- over NSRect-w rot NSRect-h 2array
- <rect> ;
+ [ [ [ NSRect-x ] [ NSRect-y ] bi ] [ dim>> second ] bi* swap - 2array ]
+ [ drop [ NSRect-w ] [ NSRect-h ] bi 2array ]
+ 2bi <rect> ;
: rect>NSRect ( rect world -- NSRect )
- over rect-loc first2 rot rect-dim second swap -
- rot rect-dim first2 <NSRect> ;
+ [ [ rect-loc first2 ] [ dim>> second ] bi* swap - ]
+ [ drop rect-dim first2 ]
+ 2bi <NSRect> ;
CLASS: {
{ +superclass+ "NSOpenGLView" }
}
{ "mouseEntered:" "void" { "id" "SEL" "id" }
- [ [ nip send-mouse-moved ] ui-try ]
+ [ nip send-mouse-moved ]
}
{ "mouseExited:" "void" { "id" "SEL" "id" }
- [ [ 3drop forget-rollover ] ui-try ]
+ [ 3drop forget-rollover ]
}
{ "mouseMoved:" "void" { "id" "SEL" "id" }
- [ [ nip send-mouse-moved ] ui-try ]
+ [ nip send-mouse-moved ]
}
{ "mouseDragged:" "void" { "id" "SEL" "id" }
- [ [ nip send-mouse-moved ] ui-try ]
+ [ nip send-mouse-moved ]
}
{ "rightMouseDragged:" "void" { "id" "SEL" "id" }
- [ [ nip send-mouse-moved ] ui-try ]
+ [ nip send-mouse-moved ]
}
{ "otherMouseDragged:" "void" { "id" "SEL" "id" }
- [ [ nip send-mouse-moved ] ui-try ]
+ [ nip send-mouse-moved ]
}
{ "mouseDown:" "void" { "id" "SEL" "id" }
- [ [ nip send-button-down$ ] ui-try ]
+ [ nip send-button-down$ ]
}
{ "mouseUp:" "void" { "id" "SEL" "id" }
- [ [ nip send-button-up$ ] ui-try ]
+ [ nip send-button-up$ ]
}
{ "rightMouseDown:" "void" { "id" "SEL" "id" }
- [ [ nip send-button-down$ ] ui-try ]
+ [ nip send-button-down$ ]
}
{ "rightMouseUp:" "void" { "id" "SEL" "id" }
- [ [ nip send-button-up$ ] ui-try ]
+ [ nip send-button-up$ ]
}
{ "otherMouseDown:" "void" { "id" "SEL" "id" }
- [ [ nip send-button-down$ ] ui-try ]
+ [ nip send-button-down$ ]
}
{ "otherMouseUp:" "void" { "id" "SEL" "id" }
- [ [ nip send-button-up$ ] ui-try ]
+ [ nip send-button-up$ ]
}
{ "scrollWheel:" "void" { "id" "SEL" "id" }
- [ [ nip send-wheel$ ] ui-try ]
+ [ nip send-wheel$ ]
}
{ "keyDown:" "void" { "id" "SEL" "id" }
- [ [ nip send-key-down-event ] ui-try ]
+ [ nip send-key-down-event ]
}
{ "keyUp:" "void" { "id" "SEL" "id" }
- [ [ nip send-key-up-event ] ui-try ]
+ [ nip send-key-up-event ]
}
{ "cut:" "id" { "id" "SEL" "id" }
- [ [ nip T{ cut-action } send-action$ ] ui-try ]
+ [ nip T{ cut-action } send-action$ ]
}
{ "copy:" "id" { "id" "SEL" "id" }
- [ [ nip T{ copy-action } send-action$ ] ui-try ]
+ [ nip T{ copy-action } send-action$ ]
}
{ "paste:" "id" { "id" "SEL" "id" }
- [ [ nip T{ paste-action } send-action$ ] ui-try ]
+ [ nip T{ paste-action } send-action$ ]
}
{ "delete:" "id" { "id" "SEL" "id" }
- [ [ nip T{ delete-action } send-action$ ] ui-try ]
+ [ nip T{ delete-action } send-action$ ]
}
{ "selectAll:" "id" { "id" "SEL" "id" }
- [ [ nip T{ select-all-action } send-action$ ] ui-try ]
+ [ nip T{ select-all-action } send-action$ ]
}
! Multi-touch gestures: this is undocumented.
{ "validRequestorForSendType:returnType:" "id" { "id" "SEL" "id" "id" }
[
! We return either self or nil
- >r >r over window-focus r> r>
+ [ over window-focus ] 2dip
valid-service? [ drop ] [ 2drop f ] if
]
}
{ "writeSelectionToPasteboard:types:" "char" { "id" "SEL" "id" "id" }
[
CF>string-array NSStringPboardType swap member? [
- >r drop window-focus gadget-selection dup [
- r> set-pasteboard-string 1
- ] [
- r> 2drop 0
- ] if
- ] [
- 3drop 0
- ] if
+ [ drop window-focus gadget-selection ] dip over
+ [ set-pasteboard-string 1 ] [ 2drop 0 ] if
+ ] [ 3drop 0 ] if
]
}
{ "readSelectionFromPasteboard:" "char" { "id" "SEL" "id" }
[
pasteboard-string dup [
- >r drop window-focus r> swap user-input 1
- ] [
- 3drop 0
- ] if
+ [ drop window ] dip swap user-input 1
+ ] [ 3drop 0 ] if
]
}
! Text input
{ "insertText:" "void" { "id" "SEL" "id" }
- [ [ nip send-user-input ] ui-try ]
+ [ nip CF>string swap window user-input ]
}
{ "hasMarkedText" "char" { "id" "SEL" }
! Initialization
{ "updateFactorGadgetSize:" "void" { "id" "SEL" "id" }
- [
- [
- 2drop dup view-dim swap window (>>dim) yield
- ] ui-try
- ]
+ [ 2drop dup view-dim swap window (>>dim) yield ]
+}
+
+{ "doCommandBySelector:" "void" { "id" "SEL" "SEL" }
+ [ 3drop ]
}
{ "initWithFrame:pixelFormat:" "id" { "id" "SEL" "NSRect" "id" }
[
- rot drop
+ [ drop ] 2dip
SUPER-> initWithFrame:pixelFormat:
dup dup add-resize-observer
]
{ "dealloc" "void" { "id" "SEL" }
[
drop
- dup unregister-window
- dup remove-observer
- SUPER-> dealloc
+ [ unregister-window ]
+ [ remove-observer ]
+ [ SUPER-> dealloc ]
+ tri
]
} ;
[ gesture>string , ]
[
[ command-name , ]
- [ command-word \ $link swap 2array , ]
+ [ command-word <$link> , ]
[ command-description , ]
tri
] bi*
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays definitions kernel sequences strings
math assocs words generic namespaces make assocs quotations
-splitting ui.gestures unicode.case unicode.categories tr ;
+splitting ui.gestures unicode.case unicode.categories tr fry ;
IN: ui.commands
SYMBOL: +nullary+
[
commands>>
[ drop ] assoc-filter
- [ [ invoke-command ] curry swap set ] assoc-each
+ [ '[ _ invoke-command ] swap set ] assoc-each
] each
] H{ } make-assoc ;
! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.accessors alien.c-types arrays io kernel libc
-math math.vectors namespaces opengl opengl.gl prettyprint assocs
+math math.vectors namespaces opengl opengl.gl assocs
sequences io.files io.styles continuations freetype
ui.gadgets.worlds ui.render ui.backend byte-arrays accessors
-locals ;
-
+locals specialized-arrays.direct.uchar ;
IN: ui.freetype
TUPLE: freetype-renderer ;
} at ;
: ttf-path ( name -- string )
- "resource:fonts/" swap ".ttf" 3append ;
+ "resource:fonts/" ".ttf" surround ;
: (open-face) ( path length -- face )
#! We use FT_New_Memory_Face, not FT_New_Face, since
dup handle>> init-descent
dup [ ascent>> ] [ descent>> ] bi - ft-ceil >>height ; inline
-: set-char-size ( handle size -- )
- 0 swap 6 shift dpi get-global dup FT_Set_Char_Size freetype-error ;
+: set-char-size ( open-font size -- open-font )
+ [ dup handle>> 0 ] dip
+ 6 shift dpi get-global dup FT_Set_Char_Size freetype-error ;
-: <font> ( handle -- font )
+: <font> ( font -- open-font )
font new
H{ } clone >>widths
over first2 open-face >>handle
- dup handle>> rot third set-char-size
+ swap third set-char-size
init-font ;
M: freetype-renderer open-font ( font -- open-font )
freetype drop open-fonts get [ <font> ] cache ;
: load-glyph ( font char -- glyph )
- >r handle>> dup r> 0 FT_Load_Char
+ [ handle>> dup ] dip 0 FT_Load_Char
freetype-error face-glyph ;
: char-width ( open-font char -- w )
] cache nip ;
M: freetype-renderer string-width ( open-font string -- w )
- 0 -rot [ char-width + ] with each ;
+ [ 0 ] 2dip [ char-width + ] with each ;
M: freetype-renderer string-height ( open-font string -- h )
drop height>> ;
FT_RENDER_MODE_NORMAL FT_Render_Glyph freetype-error ;
:: copy-pixel ( i j bitmap texture -- i j )
- 255 j texture set-char-nth
- i bitmap char-nth j 1 + texture set-char-nth
+ 255 j texture set-nth
+ i bitmap nth j 1 + texture set-nth
i 1 + j 2 + ; inline
:: (copy-row) ( i j bitmap texture end -- )
rows [ glyph glyph-bitmap-rows ]
width [ glyph glyph-bitmap-width ]
width2 [ width next-power-of-2 2 * ] |
- 0 0
- rows [ bitmap texture width width2 copy-row ] times
- 2drop
+ bitmap [
+ [let | bitmap' [ bitmap rows width * <direct-uchar-array> ] |
+ 0 0
+ rows [ bitmap' texture width width2 copy-row ] times
+ 2drop
+ ]
+ ] when
] ;
: bitmap>texture ( glyph sprite -- id )
- tuck sprite-size2 * 2 * [
- [ copy-bitmap ] keep gray-texture
- ] with-malloc ;
+ tuck sprite-size2 * 2 * <byte-array>
+ [ copy-bitmap ] keep gray-texture ;
: glyph-texture-loc ( glyph font -- loc )
- over glyph-hori-bearing-x ft-floor -rot
- ascent>> swap glyph-hori-bearing-y - ft-floor 2array ;
+ [ drop glyph-hori-bearing-x ft-floor ]
+ [ ascent>> swap glyph-hori-bearing-y - ft-floor ]
+ 2bi 2array ;
: glyph-texture-size ( glyph -- dim )
[ glyph-bitmap-width next-power-of-2 ]
bi 2array ;
: <char-sprite> ( open-font char -- sprite )
- over >r render-glyph dup r> glyph-texture-loc
+ over [ render-glyph dup ] dip glyph-texture-loc
over glyph-size pick glyph-texture-size <sprite>
[ bitmap>texture ] keep [ init-sprite ] keep ;
fonts>> [ open-font H{ } clone 2array ] cache first2 ;
M: freetype-renderer draw-string ( font string loc -- )
- >r >r world get font-sprites r> r> (draw-string) ;
+ [ world get font-sprites ] 2dip (draw-string) ;
: run-char-widths ( open-font string -- widths )
char-widths [ scan-sums ] [ 2 v/n ] bi v+ ;
! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel sequences models ui.gadgets math.geometry.rect ;
+USING: accessors kernel sequences models ui.gadgets
+math.geometry.rect fry ;
IN: ui.gadgets.books
TUPLE: book < gadget ;
M: book pref-dim* ( book -- dim ) children>> pref-dims max-dim ;
M: book layout* ( book -- )
- [ children>> ] [ dim>> ] bi [ >>dim drop ] curry each ;
+ [ children>> ] [ dim>> ] bi '[ _ >>dim drop ] each ;
M: book focusable-child* ( book -- child/t ) current-page ;
{ $subsection button-paint }
"Button constructors take " { $emphasis "label specifiers" } " as input. A label specifier is either a string, an array of strings, a gadget or " { $link f } "."
{ $see-also <command-button> "ui-commands" } ;
+
+ABOUT: "ui.gadgets.buttons"
classes.tuple opengl opengl.gl math.vectors ui.commands ui.gadgets
ui.gadgets.borders ui.gadgets.labels ui.gadgets.theme
ui.gadgets.tracks ui.gadgets.packs ui.gadgets.worlds ui.gestures
-ui.render math.geometry.rect locals alien.c-types ;
-
+ui.render math.geometry.rect locals alien.c-types
+specialized-arrays.float fry ;
IN: ui.gadgets.buttons
TUPLE: button < border pressed? selected? quot ;
relayout-1 ;
: if-clicked ( button quot -- )
- >r dup button-update dup button-rollover? r> [ drop ] if ;
+ [ dup button-update dup button-rollover? ] dip [ drop ] if ;
: button-clicked ( button -- ) dup quot>> if-clicked ;
: roll-button-theme ( button -- button )
f black <solid> dup f <button-paint> >>boundary
+ f f pressed-gradient f <button-paint> >>interior
align-left ; inline
: <roll-button> ( label quot -- button )
: checkmark-points ( dim -- points )
{
- [ { 0 0 } v* { 0 1 } v+ ]
- [ { 1 1 } v* { 0 1 } v+ ]
- [ { 0 1 } v* ]
- [ { 1 0 } v* ]
+ [ { 0 0 } v* { 0.5 0.5 } v+ ]
+ [ { 1 1 } v* { 0.5 0.5 } v+ ]
+ [ { 1 0 } v* { -0.3 0.5 } v+ ]
+ [ { 0 1 } v* { -0.3 0.5 } v+ ]
} cleave 4array ;
: checkmark-vertices ( dim -- vertices )
- checkmark-points concat >c-float-array ;
+ checkmark-points concat >float-array ;
PRIVATE>
M: radio-paint recompute-pen
swap dim>>
- [ { 4 4 } swap { 9 9 } v- circle-steps circle-vertices >>interior-vertices ]
+ [ { 4 4 } swap { 9 9 } v- circle-steps fill-circle-vertices >>interior-vertices ]
[ { 1 1 } swap { 3 3 } v- circle-steps circle-vertices >>boundary-vertices ] bi
drop ;
M: radio-paint draw-boundary
[ (radio-paint) ] [ boundary-vertices>> gl-vertex-pointer ] bi
- GL_LINE_LOOP 0 circle-steps glDrawArrays ;
+ GL_LINE_STRIP 0 circle-steps 1+ glDrawArrays ;
:: radio-knob-theme ( gadget -- gadget )
[let | radio-paint [ black <radio-paint> ] |
over value>> = >>selected?
relayout-1 ;
-: <radio-controls> ( parent model assoc quot -- parent )
- #! quot has stack effect ( value model label -- )
- swapd [ swapd call add-gadget ] 2curry assoc-each ; inline
+: <radio-controls> ( assoc model parent quot: ( value model label -- ) -- parent )
+ '[ _ swap _ call add-gadget ] assoc-each ; inline
: radio-button-theme ( gadget -- gadget )
{ 5 5 } >>gap
: <radio-buttons> ( model assoc -- gadget )
<filled-pile>
- -rot
- [ <radio-button> ] <radio-controls>
+ spin [ <radio-button> ] <radio-controls>
{ 5 5 } >>gap ;
: <toggle-button> ( value model label -- gadget )
: <toggle-buttons> ( model assoc -- gadget )
<shelf>
- -rot
- [ <toggle-button> ] <radio-controls> ;
+ spin [ <toggle-button> ] <radio-controls> ;
: command-button-quot ( target command -- quot )
- [ invoke-command drop ] 2curry ;
+ '[ _ _ invoke-command drop ] ;
: <command-button> ( target gesture command -- button )
- [ command-string ] keep
- swapd
- command-button-quot
- <bevel-button> ;
+ [ command-string swap ] keep command-button-quot <bevel-button> ;
: <toolbar> ( target -- toolbar )
<shelf>
swap
"toolbar" over class command-map commands>> swap
- [ -rot <command-button> add-gadget ] curry assoc-each ;
+ '[ [ _ ] 2dip <command-button> add-gadget ] assoc-each ;
+
+: add-toolbar ( track -- track )
+ dup <toolbar> f track-add ;
: delete-canvas-dlist ( canvas -- )
[ find-gl-context ]
- [ dlist>> [ delete-dlist ] when* ]
- [ f >>dlist drop ] tri ;
+ [ [ [ delete-dlist ] when* f ] change-dlist drop ] bi ;
: make-canvas-dlist ( canvas quot -- dlist )
[ drop ] [ GL_COMPILE swap make-dlist ] 2bi
{ $values { "editor" "a new " { $link editor } } }
{ $description "Creates a new " { $link editor } " with an empty document." } ;
-! 'editor-caret' is now an old accessor, but it's documented as a word here. Maybe move this description somewhere else.
-
-! HELP: editor-caret ( editor -- caret )
-! { $values { "editor" editor } { "caret" model } }
-! { $description "Outputs a " { $link model } " holding the current caret location." } ;
-
{ editor-caret* editor-mark* } related-words
HELP: editor-caret*
{ $values { "editor" editor } { "loc" "a pair of integers" } }
{ $description "Outputs the current caret location as a line/column number pair." } ;
-! HELP: editor-mark ( editor -- mark )
-! { $values { "editor" editor } { "mark" model } }
-! { $description "Outputs a " { $link model } " holding the current mark location." } ;
-
HELP: editor-mark*
{ $values { "editor" editor } { "loc" "a pair of integers" } }
{ $description "Outputs the current mark location as a line/column number pair." } ;
! Copyright (C) 2006, 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays documents io kernel math models
-namespaces make opengl opengl.gl sequences strings io.styles
-math.vectors sorting colors combinators assocs math.order
-ui.clipboards ui.commands ui.gadgets ui.gadgets.borders
-ui.gadgets.buttons ui.gadgets.labels ui.gadgets.scrollers
-ui.gadgets.theme ui.gadgets.wrappers ui.render ui.gestures
+USING: accessors arrays documents kernel math models
+namespaces locals fry make opengl opengl.gl sequences strings
+io.styles math.vectors sorting colors combinators assocs
+math.order fry calendar alarms ui.clipboards ui.commands
+ui.gadgets ui.gadgets.borders ui.gadgets.buttons
+ui.gadgets.labels ui.gadgets.scrollers ui.gadgets.theme
+ui.gadgets.menus ui.gadgets.wrappers ui.render ui.gestures
math.geometry.rect ;
IN: ui.gadgets.editors
TUPLE: editor < gadget
font color caret-color selection-color
caret mark
-focused? ;
+focused? blink blink-alarm ;
: <loc> ( -- loc ) { 0 0 } <model> ;
dup deactivate-model
swap model>> remove-loc ;
+: blink-caret ( editor -- )
+ [ not ] change-blink relayout-1 ;
+
+SYMBOL: blink-interval
+
+750 milliseconds blink-interval set-global
+
+: stop-blinking ( editor -- )
+ [ [ cancel-alarm ] when* f ] change-blink-alarm drop ;
+
+: start-blinking ( editor -- )
+ [ stop-blinking ] [
+ t >>blink
+ dup '[ _ blink-caret ] blink-interval get every
+ >>blink-alarm drop
+ ] bi ;
+
+: restart-blinking ( editor -- )
+ dup focused?>> [
+ [ start-blinking ]
+ [ relayout-1 ]
+ bi
+ ] [ drop ] if ;
+
M: editor graft*
dup
dup caret>> activate-editor-model
M: editor ungraft*
dup
+ dup stop-blinking
dup caret>> deactivate-editor-model
dup mark>> deactivate-editor-model ;
caret>> set-model ;
: change-caret ( editor quot -- )
- over >r >r dup editor-caret* swap model>> r> call r>
+ [ [ [ editor-caret* ] [ model>> ] bi ] dip call ] [ drop ] 2bi
set-caret ; inline
: mark>caret ( editor -- )
- dup editor-caret* swap mark>> set-model ;
+ [ editor-caret* ] [ mark>> ] bi set-model ;
: change-caret&mark ( editor quot -- )
- over >r change-caret r> mark>caret ; inline
+ [ change-caret ] [ drop mark>caret ] 2bi ; inline
: editor-line ( n editor -- str ) control-value nth ;
editor-font* "" string-height ;
: y>line ( y editor -- line# )
- [ line-height / >fixnum ] keep model>> validate-line ;
-
-: point>loc ( point editor -- loc )
- [
- >r first2 r> tuck y>line dup ,
- >r dup editor-font* r>
- rot editor-line x>offset ,
- ] { } make ;
+ line-height / >fixnum ;
+
+:: point>loc ( point editor -- loc )
+ point second editor y>line {
+ { [ dup 0 < ] [ drop { 0 0 } ] }
+ { [ dup editor model>> last-line# > ] [ drop editor model>> doc-end ] }
+ [| n |
+ n
+ point first
+ editor editor-font*
+ n editor editor-line
+ x>offset 2array
+ ]
+ } cond ;
: clicked-loc ( editor -- loc )
[ hand-rel ] keep point>loc ;
: click-loc ( editor model -- )
- >r clicked-loc r> set-model ;
+ [ clicked-loc ] dip set-model ;
-: focus-editor ( editor -- ) t >>focused? relayout-1 ;
+: focus-editor ( editor -- )
+ dup start-blinking
+ t >>focused?
+ relayout-1 ;
-: unfocus-editor ( editor -- ) f >>focused? relayout-1 ;
-
-: (offset>x) ( font col# str -- x )
- swap head-slice string-width ;
+: unfocus-editor ( editor -- )
+ dup stop-blinking
+ f >>focused?
+ relayout-1 ;
: offset>x ( col# line# editor -- x )
- [ editor-line ] keep editor-font* -rot (offset>x) ;
+ [ editor-line ] keep editor-font* spin head-slice string-width ;
-: loc>x ( loc editor -- x ) >r first2 swap r> offset>x ;
+: loc>x ( loc editor -- x ) [ first2 swap ] dip offset>x ;
: line>y ( lines# editor -- y )
line-height * ;
: caret-loc ( editor -- loc )
- [ editor-caret* ] keep 2dup loc>x 1+
- rot first rot line>y 2array ;
+ [ editor-caret* ] keep
+ [ loc>x ] [ [ first ] dip line>y ] 2bi 2array ;
: caret-dim ( editor -- dim )
line-height 0 swap 2array ;
: scroll>caret ( editor -- )
dup graft-state>> second [
- dup caret-loc over caret-dim <rect>
- over scroll>rect
- ] when drop ;
+ [
+ [ caret-loc ] [ caret-dim { 1 0 } v+ ] bi <rect>
+ ] keep scroll>rect
+ ] [ drop ] if ;
: draw-caret ( -- )
- editor get focused?>> [
+ editor get [ focused?>> ] [ blink>> ] bi and [
editor get
[ caret-color>> gl-color ]
[
line-translation gl-translate ;
: draw-line ( editor str -- )
- >r font>> r> { 0 0 } draw-string ;
+ [ font>> ] dip { 0 0 } draw-string ;
: first-visible-line ( editor -- n )
- clip get rect-loc second origin get second -
- swap y>line ;
+ [
+ [ clip get rect-loc second origin get second - ] dip
+ y>line
+ ] keep model>> validate-line ;
: last-visible-line ( editor -- n )
- clip get rect-extent nip second origin get second -
- swap y>line 1+ ;
+ [
+ [ clip get rect-extent nip second origin get second - ] dip
+ y>line
+ ] keep model>> validate-line 1+ ;
: with-editor ( editor quot -- )
[
] with-scope ; inline
: visible-lines ( editor -- seq )
- \ first-visible-line get
- \ last-visible-line get
- rot control-value <slice> ;
+ [ \ first-visible-line get \ last-visible-line get ] dip
+ control-value <slice> ;
: with-editor-translation ( n quot -- )
- >r line-translation origin get v+ r> with-translation ;
+ [ line-translation origin get v+ ] dip with-translation ;
inline
: draw-lines ( -- )
] with-editor-translation ;
: selection-start/end ( editor -- start end )
- dup editor-mark* swap editor-caret* sort-pair ;
+ [ editor-mark* ] [ editor-caret* ] bi sort-pair ;
: (draw-selection) ( x1 x2 -- )
over -
swap [ gl-fill-rect ] with-translation ;
: draw-selected-line ( start end n -- )
- [ start/end-on-line ] keep tuck
- [ editor get offset>x ] 2dip
- editor get offset>x
+ [ start/end-on-line ] keep
+ tuck [ editor get offset>x ] 2bi@
(draw-selection) ;
: draw-selection ( -- )
editor get selection-color>> gl-color
editor get selection-start/end
over first [
- 2dup [
- >r 2dup r> draw-selected-line
+ 2dup '[
+ [ _ _ ] dip
+ draw-selected-line
1 translate-lines
- ] each-line 2drop
+ ] each-line
] with-editor-translation ;
M: editor draw-gadget*
drop relayout ;
: caret/mark-changed ( model editor -- )
- nip [ relayout-1 ] [ scroll>caret ] bi ;
+ nip [ restart-blinking ] [ scroll>caret ] bi ;
M: editor model-changed
{
M: editor gadget-text* editor-string % ;
: extend-selection ( editor -- )
- dup request-focus dup caret>> click-loc ;
+ dup request-focus
+ dup restart-blinking
+ dup caret>> click-loc ;
: mouse-elt ( -- element )
hand-click# get {
editor-mark* before? ;
: drag-selection-caret ( loc editor element -- loc )
- >r [ drag-direction? ] 2keep
- model>>
- r> prev/next-elt ? ;
+ [
+ [ drag-direction? ] 2keep model>>
+ ] dip prev/next-elt ? ;
: drag-selection-mark ( loc editor element -- loc )
- >r [ drag-direction? not ] 2keep
- nip dup editor-mark* swap model>>
- r> prev/next-elt ? ;
+ [
+ [ drag-direction? not ] keep
+ [ editor-mark* ] [ model>> ] bi
+ ] dip prev/next-elt ? ;
: drag-caret&mark ( editor -- caret mark )
dup clicked-loc swap mouse-elt
: editor-cut ( editor clipboard -- )
dupd gadget-copy remove-selection ;
-: delete/backspace ( elt editor quot -- )
+: delete/backspace ( editor quot -- )
over gadget-selection? [
- drop nip remove-selection
+ drop remove-selection
] [
- over >r >r dup editor-caret* swap model>>
- r> call r> model>> remove-doc-range
+ [ [ [ editor-caret* ] [ model>> ] bi ] dip call ]
+ [ drop model>> ]
+ 2bi remove-doc-range
] if ; inline
: editor-delete ( editor elt -- )
- swap [ over >r rot next-elt r> swap ] delete/backspace ;
+ '[ dupd _ next-elt ] delete/backspace ;
: editor-backspace ( editor elt -- )
- swap [ over >r rot prev-elt r> ] delete/backspace ;
+ '[ over [ _ prev-elt ] dip ] delete/backspace ;
: editor-select-prev ( editor elt -- )
- swap [ rot prev-elt ] change-caret ;
+ '[ _ prev-elt ] change-caret ;
: editor-prev ( editor elt -- )
dupd editor-select-prev mark>caret ;
: editor-select-next ( editor elt -- )
- swap [ rot next-elt ] change-caret ;
+ '[ _ next-elt ] change-caret ;
: editor-next ( editor elt -- )
dupd editor-select-next mark>caret ;
tuck caret>> set-model mark>> set-model ;
: select-elt ( editor elt -- )
- over >r
- >r dup editor-caret* swap model>> r> prev/next-elt
- r> editor-select ;
+ [ [ [ editor-caret* ] [ model>> ] bi ] dip prev/next-elt ] [ drop ] 2bi
+ editor-select ;
: start-of-document ( editor -- ) T{ doc-elt } editor-prev ;
[ drop dup extend-selection dup mark>> click-loc ]
[ select-elt ] if ;
-: insert-newline ( editor -- ) "\n" swap user-input ;
+: insert-newline ( editor -- ) "\n" swap user-input* drop ;
: delete-next-character ( editor -- )
T{ char-elt } editor-delete ;
T{ doc-elt } editor-select-next ;
editor "selection" f {
- { T{ button-down f { S+ } } extend-selection }
+ { T{ button-down f { S+ } 1 } extend-selection }
{ T{ drag } drag-selection }
{ T{ gain-focus } focus-editor }
{ T{ lose-focus } unfocus-editor }
{ T{ key-down f { S+ C+ } "END" } select-end-of-document }
} define-command-map
+: editor-menu ( editor -- )
+ { cut com-copy paste } show-commands-menu ;
+
+editor "misc" f {
+ { T{ button-down f f 3 } editor-menu }
+} define-command-map
+
! Multi-line editors
TUPLE: multiline-editor < editor ;
+USING: accessors kernel namespaces tools.test ui.gadgets
+ui.gadgets.frames ui.gadgets.grids ui.gadgets.labels ;
IN: ui.gadgets.frames.tests
-USING: ui.gadgets.frames ui.gadgets tools.test ;
[ ] [ <frame> layout ] unit-test
+
+[ t ] [
+ <frame>
+ "Hello world" <label> @top grid-add
+ "Hello world" <label> @center grid-add
+ dup pref-dim "dim1" set
+ { 1000 1000 } >>dim
+ dup layout*
+ dup pref-dim "dim2" set
+ drop
+ "dim1" get "dim2" get =
+] unit-test
-! Copyright (C) 2005, 2007 Slava Pestov.
+! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: arrays generic kernel math namespaces sequences words
-splitting grouping math.vectors ui.gadgets.grids ui.gadgets
-math.geometry.rect ;
+USING: accessors arrays generic kernel math namespaces sequences
+words splitting grouping math.vectors ui.gadgets.grids
+ui.gadgets math.geometry.rect ;
IN: ui.gadgets.frames
-! A frame arranges gadgets in a 3x3 grid, where the center
-! gadgets gets left-over space.
-TUPLE: frame < grid ;
+TUPLE: glue < gadget ;
+
+M: glue pref-dim* drop { 0 0 } ;
+
+: <glue> ( -- glue ) glue new-gadget ;
-: <frame-grid> ( -- grid ) 9 [ <gadget> ] replicate 3 group ;
+: <frame-grid> ( -- grid ) 9 [ <glue> ] replicate 3 group ;
-: @center 1 1 ;
-: @left 0 1 ;
-: @right 2 1 ;
-: @top 1 0 ;
-: @bottom 1 2 ;
+: @center 1 1 ; inline
+: @left 0 1 ; inline
+: @right 2 1 ; inline
+: @top 1 0 ; inline
+: @bottom 1 2 ; inline
-: @top-left 0 0 ;
-: @top-right 2 0 ;
-: @bottom-left 0 2 ;
-: @bottom-right 2 2 ;
+: @top-left 0 0 ; inline
+: @top-right 2 0 ; inline
+: @bottom-left 0 2 ; inline
+: @bottom-right 2 2 ; inline
+
+TUPLE: frame < grid ;
: new-frame ( class -- frame )
<frame-grid> swap new-grid ; inline
: <frame> ( -- frame )
frame new-frame ;
-: (fill-center) ( vec n -- )
- over first pick third v+ [v-] 1 rot set-nth ;
+: (fill-center) ( dim vec -- )
+ [ [ first ] [ third ] bi v+ [v-] ] keep set-second ;
-: fill-center ( horiz vert dim -- )
- tuck (fill-center) (fill-center) ;
+: fill-center ( dim horiz vert -- )
+ [ over ] dip [ (fill-center) ] 2bi@ ;
M: frame layout*
dup compute-grid
- [ rot rect-dim fill-center ] 3keep
- grid-layout ;
+ [ [ dim>> ] 2dip fill-center ] [ grid-layout ] 3bi ;
USING: accessors arrays hashtables kernel models math namespaces
make sequences quotations math.vectors combinators sorting
binary-search vectors dlists deques models threads
-concurrency.flags math.order math.geometry.rect ;
+concurrency.flags math.order math.geometry.rect fry ;
IN: ui.gadgets
SYMBOL: ui-notify-flag
: notify-ui-thread ( -- ) ui-notify-flag get-global raise-flag ;
-TUPLE: gadget < rect
- pref-dim parent children orientation focus
- visible? root? clipped? layout-state graft-state graft-node
- interior boundary
- model ;
+TUPLE: gadget < rect pref-dim parent children orientation focus
+visible? root? clipped? layout-state graft-state graft-node
+interior boundary model ;
M: gadget equal? 2drop f ;
2dup eq? [
2drop { 0 0 }
] [
- over rect-loc >r
- >r parent>> r> relative-loc
- r> v+
+ over rect-loc [ [ parent>> ] dip relative-loc ] dip v+
] if ;
GENERIC: user-input* ( str gadget -- ? )
[ swap loc>> v- ] dip v. 0 <=> ;
: (fast-children-on) ( dim axis children -- i )
- -rot [ ((fast-children-on)) ] 2curry search drop ;
+ -rot '[ _ _ ((fast-children-on)) ] search drop ;
: fast-children-on ( rect axis children -- from to )
[ [ rect-loc ] 2dip (fast-children-on) 0 or ]
: pick-up ( point gadget -- child/f )
2dup (pick-up) dup
- [ nip [ rect-loc v- ] keep pick-up ] [ rot 2drop ] if ;
+ [ nip [ rect-loc v- ] keep pick-up ] [ drop nip ] if ;
: max-dim ( dims -- dim ) { 0 0 } [ vmax ] reduce ;
: dim-sum ( seq -- dim ) { 0 0 } [ v+ ] reduce ;
-: orient ( gadget seq1 seq2 -- seq )
- >r >r orientation>> r> r> [ pick set-axis ] 2map nip ;
-
: each-child ( gadget quot -- )
- >r children>> r> each ; inline
+ [ children>> ] dip each ; inline
! Selection protocol
GENERIC: gadget-selection? ( gadget -- ? )
[ parent>> ] follow ;
: each-parent ( gadget quot -- ? )
- >r parents r> all? ; inline
+ [ parents ] dip all? ; inline
: find-parent ( gadget quot -- parent )
- >r parents r> find nip ; inline
+ [ parents ] dip find nip ; inline
: screen-loc ( gadget -- loc )
parents { 0 0 } [ rect-loc v+ ] reduce ;
: (screen-rect) ( gadget -- loc ext )
dup parent>> [
- >r rect-extent r> (screen-rect)
- >r tuck v+ r> vmin >r v+ r>
+ [ rect-extent ] dip (screen-rect)
+ [ tuck v+ ] dip vmin [ v+ ] dip
] [
rect-extent
] if* ;
-! Copyright (C) 2006, 2007 Slava Pestov.
+! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: kernel accessors math namespaces opengl opengl.gl sequences
-math.vectors ui.gadgets ui.gadgets.grids ui.render math.geometry.rect ;
+USING: kernel accessors math namespaces opengl opengl.gl
+sequences math.vectors ui.gadgets ui.gadgets.grids ui.render
+math.geometry.rect fry ;
IN: ui.gadgets.grid-lines
TUPLE: grid-lines color ;
grid-dim get spin set-axis ;
: draw-grid-lines ( gaps orientation -- )
- grid get rot grid-positions grid get rect-dim suffix [
- grid-line-from/to gl-line
- ] with each ;
+ [ grid get swap grid-positions grid get rect-dim suffix ] dip
+ [ '[ _ v- ] map ] keep
+ '[ _ swap grid-line-from/to gl-line ] each ;
M: grid-lines draw-boundary
color>> gl-color [
dup rect-dim half-gap v- grid-dim set
compute-grid
[ { 1 0 } draw-grid-lines ]
- [
- { 0.5 -0.5 } gl-translate
- { 0 1 } draw-grid-lines
- ] bi*
+ [ { 0 1 } draw-grid-lines ]
+ bi*
] with-scope ;
! See http://factorcode.org/license.txt for BSD license.
USING: arrays kernel math namespaces make sequences words io
io.streams.string math.vectors ui.gadgets columns accessors
-math.geometry.rect locals ;
+math.geometry.rect locals fry ;
IN: ui.gadgets.grids
TUPLE: grid < gadget
: <grid> ( children -- grid )
grid new-grid ;
-: grid-child ( grid i j -- gadget ) rot grid>> nth nth ;
+:: grid-child ( grid i j -- gadget ) i j grid grid>> nth nth ;
:: grid-add ( grid child i j -- grid )
grid i j grid-child unparent
grid child add-gadget
child i j grid grid>> nth set-nth ;
-: grid-remove ( grid i j -- grid ) <gadget> -rot grid-add ;
+: grid-remove ( grid i j -- grid ) [ <gadget> ] 2dip grid-add ;
: pref-dim-grid ( grid -- dims )
grid>> [ [ pref-dim ] map ] map ;
dupd add-gaps dim-sum v+ ;
M: grid pref-dim*
- dup gap>> swap compute-grid >r over r>
- gap-sum >r gap-sum r> (pair-up) ;
+ dup gap>> swap compute-grid [ over ] dip
+ [ gap-sum ] 2bi@ (pair-up) ;
: do-grid ( dims grid quot -- )
- -rot grid>>
- [ [ pick call ] 2each ] 2each
- drop ; inline
+ [ grid>> ] dip '[ _ 2each ] 2each ; inline
: grid-positions ( grid dims -- locs )
- >r gap>> dup r> add-gaps swap [ v+ ] accumulate nip ;
+ [ gap>> dup ] dip add-gaps swap [ v+ ] accumulate nip ;
: position-grid ( grid horiz vert -- )
- pick >r
- >r over r> grid-positions >r grid-positions r>
- pair-up r> [ (>>loc) ] do-grid ;
+ pick [ [ over ] dip [ grid-positions ] 2bi@ pair-up ] dip
+ [ (>>loc) ] do-grid ;
: resize-grid ( grid horiz vert -- )
pick fill?>> [
-! Copyright (C) 2006, 2007 Slava Pestov.
+! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays ui.gadgets.buttons ui.gadgets.borders
ui.gadgets.labels ui.gadgets.panes ui.gadgets.scrollers
ui.gadgets.tracks ui.gadgets.theme ui.gadgets.frames
-ui.gadgets.grids io kernel math models namespaces prettyprint
+ui.gadgets.grids io kernel math models namespaces
sequences sequences words classes.tuple ui.gadgets ui.render
colors accessors ;
IN: ui.gadgets.labelled
M: labelled-gadget focusable-child* content>> ;
: <labelled-scroller> ( gadget title -- gadget )
- >r <scroller> r> <labelled-gadget> ;
+ [ <scroller> ] dip <labelled-gadget> ;
: <labelled-pane> ( model quot scrolls? title -- gadget )
- >r >r <pane-control> r> >>scrolls? r>
+ [ [ <pane-control> ] dip >>scrolls? ] dip
<labelled-scroller> ;
: <close-box> ( quot -- button/f )
[ closable-gadget? ] find-parent ;
: <closable-gadget> ( gadget title quot -- gadget )
- closable-gadget new-frame
- -rot <title-bar> @top grid-add
- swap >>content
- dup content>> @center grid-add ;
+ [
+ [ closable-gadget new-frame ] dip
+ [ >>content ] [ @center grid-add ] bi
+ ] 2dip
+ <title-bar> @top grid-add ;
M: closable-gadget focusable-child* content>> ;
--- /dev/null
+USING: accessors tools.test ui.gadgets ui.gadgets.labels ;
+IN: ui.gadgets.labels.tests
+
+[ { 119 14 } ] [
+ <gadget> { 100 14 } >>dim
+ <gadget> { 14 14 } >>dim
+ label-on-right { 5 5 } >>gap
+ pref-dim
+] unit-test
: set-label-string ( string label -- )
CHAR: \n pick memq? [
- >r string-lines r> (>>text)
+ [ string-lines ] dip (>>text)
] [
(>>text)
] if ; inline
hook>> [ [ list? ] find-parent ] prepend ;
: <list-presentation> ( hook elt presenter -- gadget )
- keep >r >label text-theme r>
+ keep [ >label text-theme ] dip
<presentation>
swap >>hook ; inline
[ presenter>> ]
[ control-value ]
tri [
- >r 2dup r> swap <list-presentation>
+ [ 2dup ] dip swap <list-presentation>
] map 2nip ;
M: list model-changed
select-gadget ;
: list-page ( list vec -- )
- >r dup selected-rect rect-bounds 2 v/n v+
- over visible-dim r> v* v+ swap select-at ;
+ [ dup selected-rect rect-bounds 2 v/n v+ over visible-dim ] dip
+ v* v+ swap select-at ;
: list-page-up ( list -- ) { 0 -1 } list-page ;
IN: ui.gadgets.menus
HELP: <commands-menu>
-{ $values { "hook" { $quotation "( button -- )" } } { "target" object } { "commands" "a sequence of commands" } { "gadget" "a new " { $link gadget } } }
+{ $values { "target" object } { "commands" "a sequence of commands" } { "hook" { $quotation "( button -- )" } } { "menu" "a new " { $link gadget } } }
{ $description "Creates a popup menu of commands which are to be invoked on " { $snippet "target" } ". The " { $snippet "hook" } " quotation is run before a command is invoked." } ;
HELP: show-menu
-{ $values { "gadget" gadget } { "owner" gadget } }
-{ $description "Displays a popup menu in the " { $link world } " containing " { $snippet "owner" } " at the current mouse location." } ;
+{ $values { "owner" gadget } { "menu" gadget } }
+{ $description "Displays a popup menu in the " { $link world } " containing " { $snippet "owner" } " at the current mouse location. The popup menu can be any gadget." } ;
+
+HELP: show-commands-menu
+{ $values { "target" gadget } { "commands" "a sequence of commands" } }
+{ $description "Displays a popup menu with the given commands. The commands act on the target gadget. This is just a convenience word that combines " { $link <commands-menu> } " with " { $link show-menu } "." }
+{ $notes "Useful for right-click context menus." } ;
+
+ARTICLE: "ui.gadgets.menus" "Popup menus"
+"The " { $vocab-link "ui.gadgets.menus" } " vocabulary implements popup menus."
+{ $subsection <commands-menu> }
+{ $subsection show-menu }
+{ $subsection show-commands-menu } ;
+
+ABOUT: "ui.gadgets.menus"
-! Copyright (C) 2005, 2007 Slava Pestov.
+! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays ui.commands ui.gadgets ui.gadgets.buttons
-ui.gadgets.worlds ui.gestures generic hashtables kernel math
-models namespaces opengl sequences math.vectors
-ui.gadgets.theme ui.gadgets.packs ui.gadgets.borders colors
-math.geometry.rect ;
+USING: locals accessors arrays ui.commands ui.gadgets
+ui.gadgets.buttons ui.gadgets.worlds ui.gestures generic
+hashtables kernel math models namespaces opengl sequences
+math.vectors ui.gadgets.theme ui.gadgets.packs
+ui.gadgets.borders colors math.geometry.rect ;
IN: ui.gadgets.menus
: menu-loc ( world menu -- loc )
- >r rect-dim r> pref-dim [v-] hand-loc get-global vmin ;
+ [ rect-dim ] [ pref-dim ] bi* [v-] hand-loc get-global vmin ;
TUPLE: menu-glass < gadget ;
-: <menu-glass> ( menu world -- glass )
+: <menu-glass> ( world menu -- glass )
+ tuck menu-loc >>loc
menu-glass new-gadget
- >r over menu-loc >>loc r>
swap add-gadget ;
M: menu-glass layout* gadget-child prefer ;
: hide-glass ( world -- )
[ [ unparent ] when* f ] change-glass drop ;
-: show-glass ( gadget world -- )
- dup hide-glass
- swap [ hand-clicked set-global ] [ >>glass ] bi
- dup glass>> add-gadget drop ;
+: show-glass ( world gadget -- )
+ [ [ hide-glass ] [ hand-clicked set-global ] bi* ]
+ [ add-gadget drop ]
+ [ >>glass drop ]
+ 2tri ;
-: show-menu ( gadget owner -- )
- find-world [ <menu-glass> ] keep show-glass ;
+: show-menu ( owner menu -- )
+ [ find-world dup ] dip <menu-glass> show-glass ;
\ menu-glass H{
{ T{ button-down } [ find-world [ hide-glass ] when* ] }
{ T{ drag } [ update-clicked drop ] }
} set-gestures
-: <menu-item> ( hook target command -- button )
- dup command-name -rot command-button-quot
- swapd
- [ hand-clicked get find-world hide-glass ]
- 3append <roll-button> ;
+:: <menu-item> ( target hook command -- button )
+ command command-name [
+ hook call
+ target command command-button-quot call
+ hand-clicked get find-world hide-glass
+ ] <roll-button> ;
: menu-theme ( gadget -- gadget )
light-gray solid-interior
faint-boundary ;
-: <commands-menu> ( hook target commands -- gadget )
- <filled-pile>
- -roll
- [ <menu-item> add-gadget ] with with each
+: <commands-menu> ( target hook commands -- menu )
+ [ <filled-pile> ] 3dip
+ [ <menu-item> add-gadget ] with with each
5 <border> menu-theme ;
+
+: show-commands-menu ( target commands -- )
+ [ dup [ ] ] dip <commands-menu> show-menu ;
IN: ui.gadgets.packs.tests
USING: ui.gadgets.packs ui.gadgets.labels ui.gadgets ui.render
-kernel namespaces tools.test math.parser sequences math.geometry.rect ;
+kernel namespaces tools.test math.parser sequences math.geometry.rect
+accessors ;
[ t ] [
{ 0 0 } { 100 100 } <rect> clip set
visible-children [ label? ] all?
] unit-test
+
+[ { { 10 30 } } ] [
+ { { 10 20 } }
+ { { 100 30 } }
+ <gadget> { 0 1 } >>orientation
+ orient
+] unit-test
! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: sequences ui.gadgets kernel math math.functions
-math.vectors namespaces math.order accessors math.geometry.rect ;
+math.vectors math.order math.geometry.rect namespaces accessors
+fry ;
IN: ui.gadgets.packs
TUPLE: pack < gadget
- { align initial: 0 }
- { fill initial: 0 }
- { gap initial: { 0 0 } } ;
+{ align initial: 0 } { fill initial: 0 } { gap initial: { 0 0 } } ;
: packed-dim-2 ( gadget sizes -- list )
- [ over rect-dim over v- rot fill>> v*n v+ ] with map ;
+ swap [ dim>> ] [ fill>> ] bi '[ _ over v- _ v*n v+ ] map ;
+
+: orient ( seq1 seq2 gadget -- seq )
+ orientation>> '[ _ set-axis ] 2map ;
: packed-dims ( gadget sizes -- seq )
- 2dup packed-dim-2 swap orient ;
+ [ packed-dim-2 ] [ nip ] [ drop ] 2tri orient ;
: gap-locs ( gap sizes -- seq )
{ 0 0 } [ v+ over v+ ] accumulate 2nip ;
: aligned-locs ( gadget sizes -- seq )
- [ >r dup align>> swap rect-dim r> v- n*v ] with map ;
+ [ [ [ align>> ] [ dim>> ] bi ] dip v- n*v ] with map ;
: packed-locs ( gadget sizes -- seq )
- over gap>> over gap-locs >r dupd aligned-locs r> orient ;
+ [ aligned-locs ] [ [ gap>> ] dip gap-locs ] [ drop ] 2tri orient ;
: round-dims ( seq -- newseq )
{ 0 0 } swap
: pack-layout ( pack sizes -- )
round-dims over children>>
- >r dupd packed-dims r> 2dup [ (>>dim) ] 2each
- >r packed-locs r> [ (>>loc) ] 2each ;
+ [ dupd packed-dims ] dip
+ [ [ (>>dim) ] 2each ]
+ [ [ packed-locs ] dip [ (>>loc) ] 2each ] 2bi ;
: <pack> ( orientation -- pack )
pack new-gadget
: <shelf> ( -- pack ) { 1 0 } <pack> ;
-: gap-dims ( gap sizes -- seeq )
- [ dim-sum ] keep length 1 [-] rot n*v v+ ;
+: gap-dims ( sizes gadget -- seeq )
+ [ [ dim-sum ] [ length 1 [-] ] bi ] [ gap>> ] bi* n*v v+ ;
: pack-pref-dim ( gadget sizes -- dim )
- over gap>> over gap-dims >r max-dim r>
- rot orientation>> set-axis ;
+ [ nip max-dim ]
+ [ swap gap-dims ]
+ [ drop orientation>> ]
+ 2tri set-axis ;
M: pack pref-dim*
dup children>> pref-dims pack-pref-dim ;
[ t ] [ [ [ 1 2 3 ] pprint ] test-gadget-text ] unit-test
[ t ] [ [ \ + describe ] test-gadget-text ] unit-test
[ t ] [ [ \ = see ] test-gadget-text ] unit-test
-[ t ] [ [ \ = help ] test-gadget-text ] unit-test
+[ t ] [ [ \ = print-topic ] test-gadget-text ] unit-test
[ t ] [
[
[ t ] [ [ "test-article-1" $title ] test-gadget-text ] unit-test
-[ t ] [ [ "test-article-1" help ] test-gadget-text ] unit-test
+[ t ] [ [ "test-article-1" print-topic ] test-gadget-text ] unit-test
ARTICLE: "test-article-2" "This is a test article"
"Hello world, how are you today."
{ $table { "a" "b" } { "c" "d" } } ;
-[ t ] [ [ "test-article-2" help ] test-gadget-text ] unit-test
+[ t ] [ [ "test-article-2" print-topic ] test-gadget-text ] unit-test
<pane> [ \ = see ] with-pane
-<pane> [ \ = help ] with-pane
+<pane> [ \ = print-topic ] with-pane
[ ] [
\ = <model> [ see ] <pane-control> [ ] with-grafted-gadget
USING: arrays ui.gadgets ui.gadgets.borders ui.gadgets.buttons
ui.gadgets.labels ui.gadgets.scrollers ui.gadgets.paragraphs
ui.gadgets.incremental ui.gadgets.packs ui.gadgets.theme
-ui.clipboards ui.gestures ui.traverse ui.render hashtables io
-kernel namespaces sequences io.styles strings quotations math
-opengl combinators math.vectors sorting splitting
-io.streams.nested assocs ui.gadgets.presentations
+ui.gadgets.menus ui.clipboards ui.gestures ui.traverse ui.render
+hashtables io kernel namespaces sequences io.styles strings
+quotations math opengl combinators math.vectors sorting
+splitting io.streams.nested assocs ui.gadgets.presentations
ui.gadgets.slots ui.gadgets.grids ui.gadgets.grid-lines
classes.tuple models continuations destructors accessors
-math.geometry.rect ;
-
+math.geometry.rect fry ;
IN: ui.gadgets.panes
TUPLE: pane < pack
GENERIC: draw-selection ( loc obj -- )
: if-fits ( rect quot -- )
- >r clip get over intersects? r> [ drop ] if ; inline
+ [ clip get over intersects? ] dip [ drop ] if ; inline
M: gadget draw-selection ( loc gadget -- )
swap offset-rect [
: with-pane ( pane quot -- )
over scroll>top
- over pane-clear >r <pane-stream> r>
- over >r with-output-stream* r> ?nl ; inline
+ over pane-clear [ <pane-stream> ] dip
+ over [ with-output-stream* ] dip ?nl ; inline
: make-pane ( quot -- gadget )
<pane> [ swap with-pane ] keep smash-pane ; inline
swap >>model ;
: do-pane-stream ( pane-stream quot -- )
- >r pane>> r> keep scroll-pane ; inline
+ [ pane>> ] dip keep scroll-pane ; inline
M: pane-stream stream-nl
[ pane-nl drop ] do-pane-stream ;
! Character styles
: apply-style ( style gadget key quot -- style gadget )
- >r pick at r> when* ; inline
+ [ pick at ] dip when* ; inline
: apply-foreground-style ( style gadget -- style gadget )
foreground [ >>color ] apply-style ;
border-width [ <border> ] apply-style ;
: apply-printer-style ( style gadget -- style gadget )
- presented-printer [ [ make-pane ] curry >>printer ] apply-style ;
+ presented-printer [ '[ _ make-pane ] >>printer ] apply-style ;
: style-pane ( style pane -- pane )
apply-border-width-style
pane-cell-stream new-nested-pane-stream ;
M: pane-stream stream-write-table
- >r
- swap [ [ pane>> smash-pane ] map ] map
- styled-grid
- r> print-gadget ;
+ [
+ swap [ [ pane>> smash-pane ] map ] map
+ styled-grid
+ ] dip print-gadget ;
! Stream utilities
M: pack dispose drop ;
drop ;
: gadget-write1 ( char gadget -- )
- >r 1string r> stream-write ;
+ [ 1string ] dip stream-write ;
M: pack stream-write1 gadget-write1 ;
dup hand-rel over sloppy-pick-up >>caret
dup relayout-1 ;
-: begin-selection ( pane -- ) move-caret f >>mark drop ;
+: begin-selection ( pane -- )
+ f >>selecting?
+ move-caret
+ f >>mark
+ drop ;
: extend-selection ( pane -- )
hand-moved? [
] if ;
: select-to-caret ( pane -- )
+ t >>selecting?
dup mark>> [ caret>mark ] unless
move-caret
dup request-focus
com-copy-selection ;
+: pane-menu ( pane -- ) { com-copy } show-commands-menu ;
+
pane H{
{ T{ button-down } [ begin-selection ] }
{ T{ button-down f { S+ } 1 } [ select-to-caret ] }
- { T{ button-up f { S+ } 1 } [ drop ] }
+ { T{ button-up f { S+ } 1 } [ end-selection ] }
{ T{ button-up } [ end-selection ] }
{ T{ drag } [ extend-selection ] }
{ T{ copy-action } [ com-copy ] }
+ { T{ button-down f f 3 } [ pane-menu ] }
} set-gestures
-! Copyright (C) 2005, 2007 Slava Pestov
+! Copyright (C) 2005, 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays ui.gadgets ui.gadgets.labels ui.render kernel math
-namespaces sequences math.order math.geometry.rect ;
+USING: accessors arrays ui.gadgets ui.gadgets.labels ui.render
+kernel math namespaces sequences math.order math.geometry.rect
+locals ;
IN: ui.gadgets.paragraphs
! A word break gadget
dup line-height [ max ] change
y get + max-y [ max ] change ;
-: wrap-step ( quot child -- )
- dup pref-dim [
- over word-break-gadget? [
- dup first overrun? [ wrap-line ] when
- ] unless drop wrap-pos rot call
- ] keep first2 advance-y advance-x ; inline
+:: wrap-step ( quot child -- )
+ child pref-dim
+ [
+ child
+ [
+ word-break-gadget?
+ [ drop ] [ first overrun? [ wrap-line ] when ] if
+ ]
+ [ wrap-pos quot call ] bi
+ ]
+ [ first advance-x ]
+ [ second advance-y ]
+ tri ; inline
: wrap-dim ( -- dim ) max-x get max-y get 2array ;
! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays accessors definitions hashtables io kernel
-prettyprint sequences strings io.styles words help math models
+sequences strings io.styles words help math models
namespaces quotations
ui.gadgets ui.gadgets.borders ui.gadgets.buttons
ui.gadgets.labels ui.gadgets.menus ui.gadgets.worlds
: invoke-presentation ( presentation command -- )
over dup hook>> call
- >r object>> r> invoke-command ;
+ [ object>> ] dip invoke-command ;
: invoke-primary ( presentation -- )
dup object>> primary-operation
call-next-method ;
: <operations-menu> ( presentation -- menu )
- dup dup hook>> curry
- swap object>>
- dup object-operations <commands-menu> ;
+ [ object>> ]
+ [ dup hook>> curry ]
+ [ object>> object-operations ]
+ tri <commands-menu> ;
: operations-menu ( presentation -- )
- dup <operations-menu> swap show-menu ;
+ dup <operations-menu> show-menu ;
presentation H{
{ T{ button-down f f 3 } [ operations-menu ] }
kernel models models.compose models.range ui.gadgets.viewports
ui.gadgets.labels ui.gadgets.grids ui.gadgets.frames
ui.gadgets.sliders math math.vectors arrays sequences
-tools.test.ui math.geometry.rect accessors ;
+tools.test.ui math.geometry.rect accessors ui.gadgets.buttons
+ui.gadgets.packs ;
IN: ui.gadgets.scrollers.tests
[ ] [
"g2" get scroll>gadget
"s" get layout
"s" get scroller-value
- ] map [ { 3 0 } = ] all?
+ ] map [ { 2 0 } = ] all?
] unit-test
[ ] [ "Hi" <label> dup "l" set <scroller> "s" set ] unit-test
[ t ] [ "s" get @right grid-child slider? ] unit-test
[ f ] [ "s" get @right grid-child find-scroller* ] unit-test
+[ ] [
+ "Click Me" [ [ scroll>gadget ] [ unparent ] bi ] <bevel-button>
+ [ <pile> swap add-gadget <scroller> ] keep
+ dup quot>> call
+ layout
+] unit-test
+
+[ t ] [
+ <gadget> { 200 200 } >>dim
+ [ [ scroll>gadget ] [ unparent ] bi ] <bevel-button>
+ dup
+ <pile> swap add-gadget <scroller> { 100 100 } >>dim dup layout
+ swap dup quot>> call
+ dup layout
+ model>> dependencies>> [ range-max value>> ] map
+ viewport-gap 2 v*n =
+] unit-test
+
\ <scroller> must-infer
USING: accessors arrays ui.gadgets ui.gadgets.viewports
ui.gadgets.frames ui.gadgets.grids ui.gadgets.theme
ui.gadgets.sliders ui.gestures kernel math namespaces sequences
-models models.range models.compose
-combinators math.vectors classes.tuple math.geometry.rect
-combinators.short-circuit ;
+models models.range models.compose combinators math.vectors
+classes.tuple math.geometry.rect combinators.short-circuit ;
IN: ui.gadgets.scrollers
TUPLE: scroller < frame viewport x y follows ;
: scroll-down-line ( scroller -- ) y>> 1 swap slide-by-line ;
: do-mouse-scroll ( scroller -- )
- scroll-direction get-global first2
- pick y>> slide-by-line
- swap x>> slide-by-line ;
+ scroll-direction get-global
+ [ first swap x>> slide-by-line ]
+ [ second swap y>> slide-by-line ]
+ 2bi ;
scroller H{
{ T{ mouse-scroll } [ do-mouse-scroll ] }
dup model>> dependencies>> second <y-slider> >>y dup y>> @right grid-add
tuck model>> <viewport> >>viewport
- dup viewport>> @center grid-add ;
+ dup viewport>> @center grid-add ; inline
: <scroller> ( gadget -- scroller ) scroller new-scroller ;
: scroll ( value scroller -- )
[
- dup viewport>> rect-dim { 0 0 }
- rot viewport>> viewport-dim 4array flip
+ viewport>> [ rect-dim { 0 0 } ] [ viewport-dim ] bi
+ 4array flip
] keep
2dup control-value = [ 2drop ] [ set-control-value ] if ;
-: rect-min ( rect1 rect2 -- rect )
- >r [ rect-loc ] keep r> [ rect-dim ] bi@ vmin <rect> ;
+: rect-min ( rect dim -- rect' )
+ [ [ loc>> ] [ dim>> ] bi ] dip vmin <rect> ;
: (scroll>rect) ( rect scroller -- )
- [
- scroller-value vneg offset-rect
- viewport-gap offset-rect
- ] keep
- [ viewport>> rect-min ] keep
- [
- viewport>> 2rect-extent
- >r >r v- { 0 0 } vmin r> r> v- { 0 0 } vmax v+
- ] keep dup scroller-value rot v+ swap scroll ;
+ [ [ loc>> { 1 1 } v- ] [ dim>> { 1 1 } v+ ] bi <rect> ] dip
+ {
+ [ scroller-value vneg offset-rect viewport-gap offset-rect ]
+ [ viewport>> dim>> rect-min ]
+ [ viewport>> 2rect-extent [ v- { 0 0 } vmin ] [ v- { 0 0 } vmax ] 2bi* v+ ]
+ [ scroller-value v+ ]
+ [ scroll ]
+ } cleave ;
: relative-scroll-rect ( rect gadget scroller -- newrect )
viewport>> gadget-child relative-loc offset-rect ;
[ relative-scroll-rect ] keep
swap >>follows
relayout
- ] [
- 3drop
- ] if ;
+ ] [ 3drop ] if ;
+
+: (update-scroller) ( scroller -- )
+ [ scroller-value ] keep scroll ;
: (scroll>gadget) ( gadget scroller -- )
- >r { 0 0 } over pref-dim <rect> swap r>
- [ relative-scroll-rect ] keep
- (scroll>rect) ;
+ 2dup swap child? [
+ [ [ pref-dim { 0 0 } swap <rect> ] keep ] dip
+ [ relative-scroll-rect ] keep
+ (scroll>rect)
+ ] [ f >>follows (update-scroller) drop ] if ;
: scroll>gadget ( gadget -- )
dup find-scroller* dup [
] if ;
: (scroll>bottom) ( scroller -- )
- dup viewport>> viewport-dim { 0 1 } v* swap scroll ;
+ [ viewport>> viewport-dim { 0 1 } v* ] keep scroll ;
: scroll>bottom ( gadget -- )
find-scroller [ t >>follows relayout-1 ] when* ;
M: rect update-scroller swap (scroll>rect) ;
-M: f update-scroller drop dup scroller-value swap scroll ;
+M: f update-scroller drop (update-scroller) ;
M: scroller layout*
- dup call-next-method
- dup follows>>
- 2dup update-scroller
- >>follows drop ;
+ [ call-next-method ] [
+ dup follows>>
+ [ update-scroller ] [ >>follows drop ] 2bi
+ ] bi ;
M: scroller focusable-child*
viewport>> ;
M: scroller model-changed
- nip f >>follows drop ;
+ f >>follows 2drop ;
-TUPLE: limited-scroller < scroller fixed-dim ;
+TUPLE: limited-scroller < scroller
+{ min-dim initial: { 0 0 } }
+{ max-dim initial: { 1/0. 1/0. } } ;
-: <limited-scroller> ( gadget dim -- scroller )
- >r limited-scroller new-scroller r> >>fixed-dim ;
+: <limited-scroller> ( gadget -- scroller )
+ limited-scroller new-scroller ;
M: limited-scroller pref-dim*
- fixed-dim>> ;
+ [ call-next-method ] [ min-dim>> vmax ] [ max-dim>> vmin ] tri ;
ui.gadgets.frames ui.gadgets.grids math.order
ui.gadgets.theme ui.render kernel math namespaces sequences
vectors models models.range math.vectors math.functions
-quotations colors math.geometry.rect ;
+quotations colors math.geometry.rect fry ;
IN: ui.gadgets.sliders
TUPLE: elevator < gadget direction ;
: slider-max* ( gadget -- n ) model>> range-max-value* ;
: thumb-dim ( slider -- h )
- dup slider-page over slider-max 1 max / 1 min
- over elevator-length * min-thumb-dim max
- over elevator>> rect-dim
- rot orientation>> v. min ;
+ [
+ [ [ slider-page ] [ slider-max 1 max ] bi / 1 min ]
+ [ elevator-length ] bi * min-thumb-dim max
+ ]
+ [ [ elevator>> dim>> ] [ orientation>> ] bi v. ] bi min ;
: slider-scale ( slider -- n )
#! A scaling factor such that if x is a slider co-ordinate,
#! x*n is the screen position of the thumb, and conversely
#! for x/n. The '1 max' calls avoid division by zero.
- dup elevator-length over thumb-dim - 1 max
- swap slider-max* 1 max / ;
+ [ [ elevator-length ] [ thumb-dim ] bi - 1 max ]
+ [ slider-max* 1 max ]
+ bi / ;
: slider>screen ( m scale -- n ) slider-scale * ;
: screen>slider ( m scale -- n ) slider-scale / ;
: layout-thumb-loc ( slider -- )
dup thumb-loc (layout-thumb)
- >r [ floor ] map r> (>>loc) ;
+ [ [ floor ] map ] dip (>>loc) ;
: layout-thumb-dim ( slider -- )
- dup dup thumb-dim (layout-thumb) >r
- >r dup rect-dim r>
- rot orientation>> set-axis [ ceiling ] map
- r> (>>dim) ;
+ dup dup thumb-dim (layout-thumb)
+ [
+ [ [ rect-dim ] dip ] [ drop orientation>> ] 2bi set-axis
+ [ ceiling ] map
+ ] dip (>>dim) ;
: layout-thumb ( slider -- )
dup layout-thumb-loc layout-thumb-dim ;
: slide-by-line ( amount slider -- ) [ line>> * ] keep slide-by ;
: <slide-button> ( vector polygon amount -- button )
- >r gray swap <polygon-gadget> r>
- [ swap find-slider slide-by-line ] curry <repeat-button>
+ [ gray swap <polygon-gadget> ] dip
+ '[ _ swap find-slider slide-by-line ] <repeat-button>
swap >>orientation ;
: elevator, ( gadget orientation -- gadget )
tuck <elevator> >>elevator
- swap <thumb> >>thumb
+ swap <thumb> >>thumb
dup elevator>> over thumb>> add-gadget
@center grid-add ;
GENERIC: finish-editing ( slot-editor ref -- )
M: key-ref finish-editing
- drop T{ update-object } swap send-gesture drop ;
+ drop T{ update-object } swap propagate-gesture ;
M: value-ref finish-editing
- drop T{ update-slot } swap send-gesture drop ;
+ drop T{ update-slot } swap propagate-gesture ;
: slot-editor-value ( slot-editor -- object )
text>> control-value parse-fresh ;
: delete ( slot-editor -- )
dup ref>> delete-ref
- T{ update-object } swap send-gesture drop ;
+ T{ update-object } swap propagate-gesture ;
\ delete H{
{ +description+ "Delete the slot and close the slot editor." }
} define-command
: close ( slot-editor -- )
- T{ update-slot } swap send-gesture drop ;
+ T{ update-slot } swap propagate-gesture ;
\ close H{
{ +description+ "Close the slot editor without saving changes." }
: <slot-editor> ( ref -- gadget )
{ 0 1 } slot-editor new-track
swap >>ref
- dup <toolbar> f track-add
+ add-toolbar
<source-editor> >>text
dup text>> <scroller> 1 track-add
dup revert ;
: <edit-button> ( -- gadget )
"..."
- [ T{ edit-slot } swap send-gesture drop ]
+ [ T{ edit-slot } swap propagate-gesture ]
<roll-button> ;
: display-slot ( gadget editable-slot -- )
open-world-window ;
: show-summary ( object gadget -- )
- >r [ summary ] [ "" ] if* r> show-status ;
+ [ [ summary ] [ "" ] if* ] dip show-status ;
<gadget> { 100 100 } >>dim 1 track-add
pref-dim
] unit-test
+
+[ { 10 10 } ] [
+ { 0 1 } <track>
+ <gadget> { 10 10 } >>dim 1 track-add
+ <gadget> { 10 10 } >>dim 0 track-add
+ pref-dim
+] unit-test
! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors io kernel math namespaces
- sequences words math.vectors ui.gadgets ui.gadgets.packs
- math.geometry.rect fry ;
+USING: accessors io kernel namespaces fry
+math math.vectors math.geometry.rect math.order
+sequences words ui.gadgets ui.gadgets.packs ;
IN: ui.gadgets.tracks
M: track layout* ( track -- ) dup track-layout pack-layout ;
-: track-pref-dims-1 ( track -- dim ) children>> pref-dims max-dim ;
+: track-pref-dims-1 ( track -- dim )
+ children>> pref-dims max-dim ;
: track-pref-dims-2 ( track -- dim )
- [ children>> pref-dims ] [ normalized-sizes ] bi
- [ [ v/n ] when* ] 2map
- max-dim
- [ >fixnum ] map ;
+ [
+ [ children>> pref-dims ] [ normalized-sizes ] bi
+ [ dup { 0 f } memq? [ drop ] [ v/n ] if ] 2map
+ max-dim [ >fixnum ] map
+ ]
+ [ [ gap>> ] [ children>> length 1 [-] ] bi v*n ] bi
+ v+ ;
M: track pref-dim* ( gadget -- dim )
[ track-pref-dims-1 ]
swap add-gadget ;
M: viewport layout*
- dup rect-dim viewport-gap 2 v*n v-
- over gadget-child pref-dim vmax
- swap gadget-child (>>dim) ;
+ [
+ [ rect-dim viewport-gap 2 v*n v- ]
+ [ gadget-child pref-dim ]
+ bi vmax
+ ] [ gadget-child ] bi (>>dim) ;
M: viewport focusable-child*
gadget-child ;
help.syntax models opengl strings ;
IN: ui.gadgets.worlds
+HELP: user-input
+{ $values { "string" string } { "world" world } }
+{ $description "Calls " { $link user-input* } " on every parent of the world's currently-focused child." } ;
+
HELP: origin
{ $var-description "Within the dynamic extent of " { $link draw-world } ", holds the co-ordinate system origin for the gadget currently being drawn." } ;
{ $values { "world" world } }
{ $description "Redraws a world." }
{ $notes "This word should only be called by the UI backend. To force a gadget to redraw from user code, call " { $link relayout-1 } "." } ;
+
+HELP: find-gl-context
+{ $values { "gadget" gadget } }
+{ $description "Makes the OpenGL context of the gadget's containing native window the current OpenGL context." }
+{ $notes "This word should be called from " { $link graft* } " and " { $link ungraft* } " methods which need to allocate and deallocate OpenGL resources, such as textures, display lists, and so on." } ;
+
+ARTICLE: "ui-paint-custom" "Implementing custom drawing logic"
+"The UI uses OpenGL to render gadgets. Custom rendering logic can be plugged in with the " { $link "ui-pen-protocol" } ", or by implementing a generic word:"
+{ $subsection draw-gadget* }
+"Custom drawing code has access to the full OpenGL API in the " { $vocab-link "opengl" } " vocabulary."
+$nl
+"Gadgets which need to allocate and deallocate OpenGL resources such as textures, display lists, and so on, should perform the allocation in the " { $link graft* } " method, and the deallocation in the " { $link ungraft* } " method. Since those words are not necessarily called with the gadget's OpenGL context active, a utility word can be used to find and make the correct OpenGL context current:"
+{ $subsection find-gl-context }
+"OpenGL state must not be altered as a result of drawing a gadget, so any flags which were enabled should be disabled, and vice versa."
+{ $subsection "ui-paint-coord" }
+{ $subsection "gl-utilities" }
+{ $subsection "text-rendering" } ;
! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays assocs continuations kernel math models
-namespaces opengl sequences io combinators math.vectors
+namespaces opengl sequences io combinators fry math.vectors
ui.gadgets ui.gestures ui.render ui.backend ui.gadgets.tracks
-debugger math.geometry.rect ;
+math.geometry.rect ;
IN: ui.gadgets.worlds
TUPLE: world < track
: (request-focus) ( child world ? -- )
pick parent>> pick eq? [
- >r >r dup parent>> dup r> r>
+ [ dup parent>> dup ] 2dip
[ (request-focus) ] keep
] unless focus-child ;
2dup eq?
[ 2drop ] [ dup focused?>> (request-focus) ] if ;
-: <world> ( gadget title status -- world )
- { 0 1 } world new-track
+: new-world ( gadget title status class -- world )
+ { 0 1 } swap new-track
t >>root?
t >>active?
H{ } clone >>fonts
swap 1 track-add
dup request-focus ;
+: <world> ( gadget title status -- world )
+ world new-world ;
+
M: world layout*
dup call-next-method
dup glass>> [
- >r dup rect-dim r> (>>dim)
+ [ dup rect-dim ] dip (>>dim)
] when* drop ;
M: world focusable-child* gadget-child ;
: draw-world? ( world -- ? )
#! We don't draw deactivated worlds, or those with 0 size.
#! On Windows, the latter case results in GL errors.
- dup active?>>
- over handle>>
- rot rect-dim [ 0 > ] all? and and ;
+ [ active?>> ] [ handle>> ] [ dim>> [ 0 > ] all? ] tri and and ;
TUPLE: world-error error world ;
SYMBOL: ui-error-hook
: ui-error ( error -- )
- ui-error-hook get [ call ] [ print-error ] if* ;
+ ui-error-hook get [ call ] [ die ] if* ;
-[ rethrow ] ui-error-hook set-global
+ui-error-hook global [ [ rethrow ] or ] change-at
: draw-world ( world -- )
dup draw-world? [
{ T{ key-down f { C+ } "a" } [ T{ select-all-action } send-action ] }
{ T{ button-down f { C+ } 1 } [ drop T{ button-down f f 3 } button-gesture ] }
{ T{ button-down f { A+ } 1 } [ drop T{ button-down f f 2 } button-gesture ] }
+ { T{ button-down f { M+ } 1 } [ drop T{ button-down f f 2 } button-gesture ] }
{ T{ button-up f { C+ } 1 } [ drop T{ button-up f f 3 } button-gesture ] }
{ T{ button-up f { A+ } 1 } [ drop T{ button-up f f 2 } button-gesture ] }
+ { T{ button-up f { M+ } 1 } [ drop T{ button-up f f 2 } button-gesture ] }
} set-gestures
+PREDICATE: specific-button-up < button-up #>> ;
+PREDICATE: specific-button-down < button-down #>> ;
+PREDICATE: specific-drag < drag #>> ;
+
+: generalize-gesture ( gesture -- )
+ clone f >># button-gesture ;
+
+M: world handle-gesture ( gesture gadget -- ? )
+ 2dup call-next-method [
+ {
+ { [ over specific-button-up? ] [ drop generalize-gesture f ] }
+ { [ over specific-button-down? ] [ drop generalize-gesture f ] }
+ { [ over specific-drag? ] [ drop generalize-gesture f ] }
+ [ 2drop t ]
+ } cond
+ ] [ 2drop f ] if ;
+
: close-global ( world global -- )
- dup get-global find-world rot eq?
- [ f swap set-global ] [ drop ] if ;
+ [ get-global find-world eq? ] keep '[ f _ set-global ] when ;
-USING: ui.gadgets help.markup help.syntax hashtables
-strings kernel system ;
+USING: ui.gadgets ui.gadgets.worlds help.markup help.syntax
+hashtables strings kernel system ;
IN: ui.gestures
HELP: set-gestures
"The default implementation looks at the " { $snippet "\"gestures\"" } " word property of each superclass of the gadget's class." }
{ $notes "Methods should be defined on this word if you desire to handle an arbitrary set of gestures. To define handlers for a fixed set, it is easier to use " { $link set-gestures } "." } ;
-{ send-gesture handle-gesture set-gestures } related-words
+{ propagate-gesture handle-gesture set-gestures } related-words
-HELP: send-gesture
-{ $values { "gesture" "a gesture" } { "gadget" gadget } { "?" "a boolean" } }
-{ $description "Calls " { $link send-gesture } " on every parent of " { $snippet "gadget" } ". Outputs " { $link f } " if some parent handled the gesture, else outputs " { $link t } "." } ;
-
-HELP: user-input
-{ $values { "str" string } { "gadget" gadget } }
-{ $description "Calls " { $link user-input* } " on every parent of the gadget." } ;
+HELP: propagate-gesture
+{ $values { "gesture" "a gesture" } { "gadget" gadget } }
+{ $description "Calls " { $link handle-gesture } " on every parent of " { $snippet "gadget" } "." } ;
HELP: motion
{ $class-description "Mouse motion gesture." }
{ $class-description "Gesture sent when the " { $emphasis "select all" } " standard window system action is invoked." }
{ $examples { $code "T{ select-all-action }" } } ;
-HELP: generalize-gesture
-{ $values { "gesture" "a gesture" } { "newgesture" "a new gesture" } }
-{ $description "Turns a " { $link button-down } ", " { $link button-up } " or " { $link drag } " action naming a specific mouse button into one which can apply regardless of which mouse button was pressed." } ;
-
HELP: C+
{ $description "Control key modifier." } ;
{ $var-description "Global variable. The mouse button most recently pressed." } ;
HELP: hand-last-time
-{ $var-description "Global variable. The timestamp of the most recent mouse button click. This timestamp has the same format as the output value of " { $link millis } "." } ;
+{ $var-description "Global variable. The timestamp of the most recent mouse button click. This timestamp has the same format as the output value of " { $link micros } "." } ;
HELP: hand-buttons
{ $var-description "Global variable. A vector of mouse buttons currently held down." } ;
{ $example "USING: io ui.gestures ;" "T{ key-down f { C+ } \"x\" } gesture>string print" "C+x" }
} ;
+HELP: left-action
+{ $class-description "Gesture sent when the user performs a multi-touch three-finger swipe left." } ;
+
+HELP: right-action
+{ $class-description "Gesture sent when the user performs a multi-touch three-finger swipe right." } ;
+
+HELP: up-action
+{ $class-description "Gesture sent when the user performs a multi-touch three-finger swipe up." } ;
+
+HELP: down-action
+{ $class-description "Gesture sent when the user performs a multi-touch three-finger swipe down." } ;
+
+HELP: zoom-in-action
+{ $class-description "Gesture sent when the user performs a multi-touch two-finger pinch in." } ;
+
+HELP: zoom-out-action
+{ $class-description "Gesture sent when the user performs a multi-touch two-finger pinch out." } ;
+
+ARTICLE: "gesture-differences" "Gesture handling differences between platforms"
+"On Mac OS X, the modifier keys map as follows:"
+{ $table
+ { { $link S+ } "Shift" }
+ { { $link A+ } "Command (Apple)" }
+ { { $link C+ } "Control" }
+ { { $link M+ } "Option" }
+}
+"On Windows and X11:"
+{ $table
+ { { $link S+ } "Shift" }
+ { { $link A+ } "Alt" }
+ { { $link C+ } "Control" }
+ { { $link M+ } "Windows key" }
+}
+"On Windows, " { $link key-up } " gestures are not reported for all keyboard events."
+$nl
+{ $link "multitouch-gestures" } " are only supported on Mac OS X." ;
+
ARTICLE: "ui-gestures" "UI gestures"
"User actions such as keyboard input and mouse button clicks deliver " { $emphasis "gestures" } " to gadgets. If the direct receiver of the gesture does not handle it, the gesture is passed on to the receiver's parent, and this way it travels up the gadget hierarchy. Gestures which are not handled at some point are ignored."
$nl
{ $subsection "ui-user-input" }
"Mouse input:"
{ $subsection "mouse-gestures" }
+{ $subsection "multitouch-gestures" }
+"Guidelines for cross-platform applications:"
+{ $subsection "gesture-differences" }
"Abstractions built on top of gestures:"
{ $subsection "ui-commands" }
{ $subsection "ui-operations" } ;
"Global variable set when a mouse scroll wheel gesture is sent:"
{ $subsection scroll-direction } ;
+ARTICLE: "multitouch-gestures" "Multi-touch gestures"
+"Multi-touch gestures are only supported on Mac OS X with newer MacBook and MacBook Pro models."
+$nl
+"Three-finger swipe:"
+{ $subsection left-action }
+{ $subsection right-action }
+{ $subsection up-action }
+{ $subsection down-action }
+"Two-finger pinch:"
+{ $subsection zoom-in-action }
+{ $subsection zoom-out-action } ;
+
ARTICLE: "action-gestures" "Action gestures"
"Action gestures exist to keep keyboard shortcuts for common clipboard operations consistent."
{ $subsection cut-action }
! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs kernel math models namespaces
-make sequences words strings system hashtables math.parser
-math.vectors classes.tuple classes ui.gadgets boxes calendar
-alarms symbols combinators sets columns ;
+USING: accessors arrays assocs kernel math math.order models
+namespaces make sequences words strings system hashtables
+math.parser math.vectors classes.tuple classes boxes calendar
+alarms symbols combinators sets columns fry deques ui.gadgets ;
IN: ui.gestures
-: set-gestures ( class hash -- ) "gestures" set-word-prop ;
-
GENERIC: handle-gesture ( gesture gadget -- ? )
M: object handle-gesture
[ "gestures" word-prop ] map
assoc-stack dup [ call f ] [ 2drop t ] if ;
-: send-gesture ( gesture gadget -- ? )
- [ dupd handle-gesture ] each-parent nip ;
+: set-gestures ( class hash -- ) "gestures" set-word-prop ;
+
+: gesture-queue ( -- deque ) \ gesture-queue get ;
+
+GENERIC: send-queued-gesture ( request -- )
+
+TUPLE: send-gesture gesture gadget ;
+
+M: send-gesture send-queued-gesture
+ [ gesture>> ] [ gadget>> ] bi handle-gesture drop ;
+
+: queue-gesture ( ... class -- )
+ boa gesture-queue push-front notify-ui-thread ; inline
+
+: send-gesture ( gesture gadget -- )
+ \ send-gesture queue-gesture ;
+
+: each-gesture ( gesture seq -- ) [ send-gesture ] with each ;
+
+TUPLE: propagate-gesture gesture gadget ;
+
+M: propagate-gesture send-queued-gesture
+ [ gesture>> ] [ gadget>> ] bi
+ [ handle-gesture ] with each-parent drop ;
+
+: propagate-gesture ( gesture gadget -- )
+ \ propagate-gesture queue-gesture ;
+
+TUPLE: propagate-key-gesture gesture world ;
-: user-input ( str gadget -- )
- over empty?
- [ [ dupd user-input* ] each-parent ] unless
- 2drop ;
+: world-focus ( world -- gadget )
+ dup focus>> [ world-focus ] [ ] ?if ;
+
+M: propagate-key-gesture send-queued-gesture
+ [ gesture>> ] [ world>> world-focus ] bi
+ [ handle-gesture ] with each-parent drop ;
+
+: propagate-key-gesture ( gesture world -- )
+ \ propagate-key-gesture queue-gesture ;
+
+TUPLE: user-input string world ;
+
+M: user-input send-queued-gesture
+ [ string>> ] [ world>> world-focus ] bi
+ [ user-input* ] with each-parent drop ;
+
+: user-input ( string world -- )
+ '[ _ \ user-input queue-gesture ] unless-empty ;
! Gesture objects
TUPLE: motion ; C: <motion> motion
TUPLE: up-action ; C: <up-action> up-action
TUPLE: down-action ; C: <down-action> down-action
-TUPLE: zoom-in-action ; C: <zoom-in-action> zoom-in-action
-TUPLE: zoom-out-action ; C: <zoom-out-action> zoom-out-action
-
-: generalize-gesture ( gesture -- newgesture )
- clone f >># ;
+TUPLE: zoom-in-action ; C: <zoom-in-action> zoom-in-action
+TUPLE: zoom-out-action ; C: <zoom-out-action> zoom-out-action
! Modifiers
SYMBOLS: C+ A+ M+ S+ ;
TUPLE: key-down mods sym ;
: <key-gesture> ( mods sym action? class -- mods' sym' )
- >r [ S+ rot remove swap ] unless r> boa ; inline
+ [ [ [ S+ swap remove f like ] dip ] unless ] dip boa ; inline
: <key-down> ( mods sym action? -- key-down )
key-down <key-gesture> ;
SYMBOL: hand-last-button
SYMBOL: hand-last-time
0 hand-last-button set-global
-0 hand-last-time set-global
+<zero> hand-last-time set-global
SYMBOL: hand-buttons
V{ } clone hand-buttons set-global
{ 0 0 } scroll-direction set-global
SYMBOL: double-click-timeout
-300 double-click-timeout set-global
+300 milliseconds double-click-timeout set-global
: hand-moved? ( -- ? )
hand-loc get hand-click-loc get = not ;
: button-gesture ( gesture -- )
- hand-clicked get-global 2dup send-gesture [
- >r generalize-gesture r> send-gesture drop
- ] [
- 2drop
- ] if ;
+ hand-clicked get-global propagate-gesture ;
: drag-gesture ( -- )
hand-buttons get-global
: fire-motion ( -- )
hand-buttons get-global empty? [
- T{ motion } hand-gadget get-global send-gesture drop
+ T{ motion } hand-gadget get-global propagate-gesture
] [
drag-gesture
] if ;
-: each-gesture ( gesture seq -- )
- [ handle-gesture drop ] with each ;
-
: hand-gestures ( new old -- )
drop-prefix <reversed>
T{ mouse-leave } swap each-gesture
: forget-rollover ( -- )
f hand-world set-global
- hand-gadget get-global >r
- f hand-gadget set-global
- f r> parents hand-gestures ;
+ hand-gadget get-global
+ [ f hand-gadget set-global f ] dip
+ parents hand-gestures ;
: send-lose-focus ( gadget -- )
- T{ lose-focus } swap handle-gesture drop ;
+ T{ lose-focus } swap send-gesture ;
: send-gain-focus ( gadget -- )
- T{ gain-focus } swap handle-gesture drop ;
+ T{ gain-focus } swap send-gesture ;
: focus-child ( child gadget ? -- )
[
hand-click-loc get-global swap screen-loc v- ;
: multi-click-timeout? ( -- ? )
- millis hand-last-time get - double-click-timeout get <= ;
+ now hand-last-time get time- double-click-timeout get before=? ;
: multi-click-button? ( button -- button ? )
dup hand-last-button get = ;
: multi-click-position? ( -- ? )
- hand-loc get hand-click-loc get v- norm-sq 100 <= ;
+ hand-loc get hand-click-loc get distance 10 <= ;
: multi-click? ( button -- ? )
{
1 hand-click# set
] if
hand-last-button set
- millis hand-last-time set
+ now hand-last-time set
] bind ;
: update-clicked ( -- )
: move-hand ( loc world -- )
dup hand-world set-global
- under-hand >r over hand-loc set-global
- pick-up hand-gadget set-global
- under-hand r> hand-gestures ;
+ under-hand [
+ over hand-loc set-global
+ pick-up hand-gadget set-global
+ under-hand
+ ] dip hand-gestures ;
: send-button-down ( gesture loc world -- )
move-hand
: send-wheel ( direction loc world -- )
move-hand
scroll-direction set-global
- T{ mouse-scroll } hand-gadget get-global send-gesture
- drop ;
-
-: world-focus ( world -- gadget )
- dup focus>> [ world-focus ] [ ] ?if ;
+ T{ mouse-scroll } hand-gadget get-global propagate-gesture ;
: send-action ( world gesture -- )
- swap world-focus send-gesture drop ;
+ swap world-focus propagate-gesture ;
GENERIC: gesture>string ( gesture -- string/f )
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays definitions kernel ui.commands
ui.gestures sequences strings math words generic namespaces make
-hashtables help.markup quotations assocs ;
+hashtables help.markup quotations assocs fry ;
IN: ui.operations
SYMBOL: +keyboard+
operations get [ predicate>> call ] with filter ;
: find-operation ( obj quot -- command )
- >r object-operations r> find-last nip ; inline
+ [ object-operations ] dip find-last nip ; inline
: primary-operation ( obj -- operation )
[ command>> +primary+ word-prop ] find-operation ;
t >>listener? ;
: modify-operations ( operations hook translator -- operations )
- rot [ modify-operation ] with with map ;
+ '[ [ _ _ ] dip modify-operation ] map ;
: operations>commands ( object hook translator -- pairs )
[ object-operations ] 2dip modify-operations
USING: ui.gadgets ui.gestures help.markup help.syntax
-kernel classes strings opengl.gl models math.geometry.rect ;
+kernel classes strings opengl opengl.gl models
+math.geometry.rect ;
IN: ui.render
HELP: gadget
{ $subsection draw-string }
{ $subsection draw-text } ;
-ARTICLE: "ui-paint-custom" "Implementing custom drawing logic"
-"The UI uses OpenGL to render gadgets. Custom rendering logic can be plugged in with the " { $link "ui-pen-protocol" } ", or by implementing a generic word:"
-{ $subsection draw-gadget* }
-"Custom drawing code has access to the full OpenGL API in the " { $vocab-link "opengl" } " vocabulary."
-$nl
+ARTICLE: "ui-paint-coord" "The UI co-ordinate system"
"The UI uses a co-ordinate system where the y axis is oriented down. The OpenGL " { $link GL_MODELVIEW } " matrix is not saved or restored when rendering a gadget. Instead, the origin of the gadget relative to the OpenGL context is stored in a variable:"
{ $subsection origin }
-"Custom drawing implementations can translate co-ordinates manually, or save and restore the " { $link GL_MODELVIEW } " matrix."
-$nl
-"OpenGL state must not be altered as a result of drawing a gadget, so any flags which were enabled should be disabled, and vice versa."
-$nl
-"Gadgets must not draw outside of their bounding box, however clipping is not enforced by default, for performance reasons. This can be changed by setting the " { $snippet "clipped?" } " slot to " { $link t } " in the gadget's constructor."
+"Custom drawing implementations can translate co-ordinates manually, or save and restore the " { $link GL_MODELVIEW } " matrix using a word such as " { $link with-translation } "."
$nl
-"Saving the " { $link GL_MODELVIEW } " matrix and enabling/disabling flags can be done in a clean way using the combinators documented in the following section."
-{ $subsection "gl-utilities" }
-{ $subsection "text-rendering" } ;
+"Gadgets must not draw outside of their bounding box, however clipping is not enforced by default, for performance reasons. This can be changed by setting the " { $slot "clipped?" } " slot to " { $link t } " in the gadget's constructor." ;
ABOUT: "ui-paint-custom"
USING: accessors alien alien.c-types arrays hashtables io kernel
math namespaces opengl opengl.gl opengl.glu sequences strings
io.styles vectors combinators math.vectors ui.gadgets colors
-math.order math.geometry.rect locals ;
+math.order math.geometry.rect locals specialized-arrays.float ;
IN: ui.render
SYMBOL: clip
: flip-rect ( rect -- loc dim )
rect-bounds [
- >r { 1 -1 } v* r> { 0 -1 } v* v+
+ [ { 1 -1 } v* ] dip { 0 -1 } v* v+
viewport-translation get v+
] keep ;
>absolute clip [ rect-intersect ] change ;
: with-clipping ( gadget quot -- )
- clip get >r
- over change-clip do-clip call
- r> clip set do-clip ; inline
+ clip get [ over change-clip do-clip call ] dip clip set do-clip ; inline
: draw-gadget ( gadget -- )
{
direction dim v* dim over v- swap
colors length dup 1- v/n [ v*n ] with map
[ dup rot v+ 2array ] with map
- concat concat >c-float-array ;
+ concat concat >float-array ;
: gradient-colors ( colors -- seq )
- [ color>raw 4array dup 2array ] map concat concat >c-float-array ;
+ [ color>raw 4array dup 2array ] map concat concat
+ >float-array ;
M: gradient recompute-pen ( gadget gradient -- )
tuck
} cleave ;
! Polygon pen
-TUPLE: polygon color vertex-array count ;
+TUPLE: polygon color
+interior-vertices
+interior-count
+boundary-vertices
+boundary-count ;
: <polygon> ( color points -- polygon )
- [ concat >c-float-array ] [ length ] bi polygon boa ;
+ dup close-path [ [ concat >float-array ] [ length ] bi ] bi@
+ polygon boa ;
-: draw-polygon ( polygon mode -- )
- swap
+M: polygon draw-boundary
+ nip
[ color>> gl-color ]
- [ vertex-array>> gl-vertex-pointer ]
- [ 0 swap count>> glDrawArrays ]
+ [ boundary-vertices>> gl-vertex-pointer ]
+ [ [ GL_LINE_STRIP 0 ] dip boundary-count>> glDrawArrays ]
tri ;
-M: polygon draw-boundary
- GL_LINE_LOOP draw-polygon drop ;
-
M: polygon draw-interior
- dup count>> 2 > GL_POLYGON GL_LINES ?
- draw-polygon drop ;
+ nip
+ [ color>> gl-color ]
+ [ interior-vertices>> gl-vertex-pointer ]
+ [ [ GL_POLYGON 0 ] dip interior-count>> glDrawArrays ]
+ tri ;
: arrow-up { { 3 0 } { 6 6 } { 0 6 } } ;
: arrow-right { { 0 0 } { 6 3 } { 0 6 } } ;
: <polygon-gadget> ( color points -- gadget )
dup max-dim
- >r <polygon> <gadget> r> >>dim
+ [ <polygon> <gadget> ] dip >>dim
swap >>interior ;
! Font rendering
dup string? [
string-width
] [
- 0 -rot [ string-width max ] with each
+ [ 0 ] 2dip [ string-width max ] with each
] if ;
: text-dim ( open-font text -- dim )
[
[
2dup { 0 0 } draw-string
- >r open-font r> string-height
+ [ open-font ] dip string-height
0.0 swap 0.0 glTranslated
] with each
] with-translation
models models.history ui.commands ui.gadgets ui.gadgets.panes
ui.gadgets.scrollers ui.gadgets.tracks ui.gestures
ui.gadgets.buttons compiler.units assocs words vocabs
-accessors ;
+accessors fry combinators.short-circuit ;
IN: ui.tools.browser
TUPLE: browser-gadget < track pane history ;
: show-help ( link help -- )
- dup history>> add-history
- >r >link r> history>> set-model ;
+ history>> dup add-history
+ [ >link ] dip set-model ;
: <help-pane> ( browser-gadget -- gadget )
- history>> [ [ help ] curry try ] <pane-control> ;
+ history>> [ '[ _ print-topic ] try ] <pane-control> ;
: init-history ( browser-gadget -- )
"handbook" >link <history> >>history drop ;
: <browser-gadget> ( -- gadget )
{ 0 1 } browser-gadget new-track
dup init-history
- dup <toolbar> f track-add
+ add-toolbar
dup <help-pane> >>pane
dup pane>> <scroller> 1 track-add ;
[ call-next-method ] [ remove-definition-observer ] bi ;
: showing-definition? ( defspec assoc -- ? )
- [ key? ] 2keep
- [ >r dup word-link? [ name>> ] when r> key? ] 2keep
- >r dup vocab-link? [ vocab ] when r> key?
- or or ;
+ {
+ [ key? ]
+ [ [ dup word-link? [ name>> ] when ] dip key? ]
+ [ [ dup vocab-link? [ vocab ] when ] dip key? ]
+ } 2|| ;
M: browser-gadget definitions-changed ( assoc browser -- )
history>>
\ browser-help H{ { +nullary+ t } } define-command
browser-gadget "toolbar" f {
- { T{ key-down f { A+ } "b" } com-back }
- { T{ key-down f { A+ } "f" } com-forward }
- { T{ key-down f { A+ } "h" } com-documentation }
- { T{ key-down f { A+ } "v" } com-vocabularies }
+ { T{ key-down f { A+ } "LEFT" } com-back }
+ { T{ key-down f { A+ } "RIGHT" } com-forward }
+ { f com-documentation }
+ { f com-vocabularies }
{ T{ key-down f f "F1" } browser-help }
} define-command-map
"Creates a gadget displaying a description of the error, along with buttons to print the contents of the stacks in the listener, and a list of restarts."
} ;
-{ <debugger> debugger-window ui-try } related-words
+{ <debugger> debugger-window } related-words
HELP: debugger-window
{ $values { "error" "an error" } }
! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays ui ui.commands ui.gestures ui.gadgets
- ui.gadgets.worlds ui.gadgets.packs ui.gadgets.buttons
- ui.gadgets.labels ui.gadgets.panes ui.gadgets.presentations
- ui.gadgets.viewports ui.gadgets.lists ui.gadgets.tracks
- ui.gadgets.scrollers ui.gadgets.panes hashtables io kernel math
- models namespaces sequences sequences words continuations
- debugger prettyprint ui.tools.traceback help editors ;
-
+USING: accessors arrays hashtables io kernel math models
+namespaces sequences sequences words continuations debugger
+prettyprint help editors ui ui.commands ui.gestures ui.gadgets
+ui.gadgets.worlds ui.gadgets.packs ui.gadgets.buttons
+ui.gadgets.labels ui.gadgets.panes ui.gadgets.presentations
+ui.gadgets.viewports ui.gadgets.lists ui.gadgets.tracks
+ui.gadgets.scrollers ui.gadgets.panes ui.tools.traceback ;
IN: ui.tools.debugger
-: <restart-list> ( restarts restart-hook -- gadget )
- [ name>> ] rot <model> <list> ;
+TUPLE: debugger < track error restarts restart-hook restart-list continuation ;
+
+<PRIVATE
-TUPLE: debugger < track restarts ;
+: <restart-list> ( debugger -- gadget )
+ [ restart-hook>> ] [ restarts>> ] bi
+ [ name>> ] swap <model> <list> ; inline
-: <debugger-display> ( restart-list error -- gadget )
+: <error-pane> ( error -- pane )
+ <pane> [ [ print-error ] with-pane ] keep ; inline
+
+: <debugger-display> ( debugger -- gadget )
<filled-pile>
- <pane>
- swapd tuck [ print-error ] with-pane
- add-gadget
+ over error>> <error-pane> add-gadget
+ swap restart-list>> add-gadget ; inline
- swap add-gadget ;
+PRIVATE>
: <debugger> ( error restarts restart-hook -- gadget )
{ 0 1 } debugger new-track
- dup <toolbar> f track-add
- -rot <restart-list> >>restarts
- dup restarts>> rot <debugger-display> <scroller> 1 track-add ;
+ add-toolbar
+ swap >>restart-hook
+ swap >>restarts
+ swap >>error
+ error-continuation get >>continuation
+ dup <restart-list> >>restart-list
+ dup <debugger-display> <scroller> 1 track-add ;
-M: debugger focusable-child* restarts>> ;
+M: debugger focusable-child* restart-list>> ;
: debugger-window ( error -- )
#! No restarts for the debugger window
f [ drop ] <debugger> "Error" open-window ;
-[ debugger-window ] ui-error-hook set-global
+GENERIC: error-in-debugger? ( error -- ? )
+
+M: world-error error-in-debugger? world>> gadget-child debugger? ;
+
+M: object error-in-debugger? drop f ;
+
+[
+ dup error-in-debugger? [ rethrow ] [ debugger-window ] if
+] ui-error-hook set-global
M: world-error error.
"An error occurred while drawing the world " write
{ T{ button-down } request-focus }
} define-command-map
-: com-traceback ( -- ) error-continuation get traceback-window ;
+: com-traceback ( debugger -- ) continuation>> traceback-window ;
+
+\ com-traceback H{ } define-command
+
+: com-help ( debugger -- ) error>> (:help) ;
-\ com-traceback H{ { +nullary+ t } } define-command
+\ com-help H{ { +listener+ t } } define-command
-\ :help H{ { +nullary+ t } { +listener+ t } } define-command
+: com-edit ( debugger -- ) error>> (:edit) ;
-\ :edit H{ { +nullary+ t } { +listener+ t } } define-command
+\ com-edit H{ { +listener+ t } } define-command
debugger "toolbar" f {
{ T{ key-down f f "s" } com-traceback }
- { T{ key-down f f "h" } :help }
- { T{ key-down f f "e" } :edit }
+ { T{ key-down f f "h" } com-help }
+ { T{ key-down f f "e" } com-edit }
} define-command-map
-! Copyright (C) 2007 Slava Pestov.
+! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: ui.gadgets colors kernel ui.render namespaces
- models models.mapping sequences ui.gadgets.buttons
- ui.gadgets.packs ui.gadgets.labels tools.deploy.config
- namespaces ui.gadgets.editors ui.gadgets.borders ui.gestures
- ui.commands assocs ui.gadgets.tracks ui ui.tools.listener
- tools.deploy vocabs ui.tools.workspace system accessors ;
-
+USING: ui.gadgets colors kernel ui.render namespaces models
+models.mapping sequences ui.gadgets.buttons ui.gadgets.packs
+ui.gadgets.labels tools.deploy.config tools.deploy.config.editor
+namespaces ui.gadgets.editors ui.gadgets.borders ui.gestures
+ui.commands assocs ui.gadgets.tracks ui ui.tools.listener
+tools.deploy vocabs ui.tools.workspace system accessors fry ;
IN: ui.tools.deploy
TUPLE: deploy-gadget < pack vocab settings ;
: com-deploy ( gadget -- )
dup com-save
- dup find-deploy-vocab [ deploy ] curry call-listener
+ dup find-deploy-vocab '[ _ deploy ] call-listener
close-window ;
: com-help ( -- )
: com-close ( gadget -- )
close-window ;
+deploy-gadget "misc" "Miscellaneous commands" {
+ { T{ key-down f f "ESC" } com-close }
+} define-command-map
+
deploy-gadget "toolbar" f {
- { f com-close }
- { f com-help }
+ { T{ key-down f f "F1" } com-help }
{ f com-revert }
{ f com-save }
{ T{ key-down f f "RET" } com-deploy }
dup com-revert ;
: deploy-tool ( vocab -- )
- vocab-name dup <deploy-gadget> 10 <border>
- "Deploying \"" rot "\"" 3append open-window ;
+ vocab-name
+ [ <deploy-gadget> 10 <border> ]
+ [ "Deploying \"" "\"" surround ] bi
+ open-window ;
: <inspector-gadget> ( -- gadget )
{ 0 1 } inspector-gadget new-track
- dup <toolbar> f track-add
+ add-toolbar
<pane> >>pane
dup pane>> <scroller> 1 track-add ;
[ ] [ [ "interactor" get stream-read-quot drop ] "B" spawn drop ] unit-test
-[ ] [ 1000 sleep ] unit-test
+[ ] [ 1 seconds sleep ] unit-test
[ ] [ "interactor" get interactor-eof ] unit-test
] in-thread
] unit-test
-[ ] [ 100 sleep ] unit-test
+[ ] [ 100 milliseconds sleep ] unit-test
[ ] [ "interactor" get evaluate-input ] unit-test
-[ ] [ 100 sleep ] unit-test
+[ ] [ 100 milliseconds sleep ] unit-test
[ ] [ "interactor" get interactor-eof ] unit-test
] in-thread
] unit-test
-[ ] [ 100 sleep ] unit-test
+[ ] [ 100 milliseconds sleep ] unit-test
[ ] [ "interactor" get evaluate-input ] unit-test
ui.commands ui.gadgets ui.gadgets.editors ui.gadgets.status-bar
ui.gadgets.presentations ui.gadgets.worlds ui.gestures
definitions calendar concurrency.flags concurrency.mailboxes
-ui.tools.workspace accessors sets destructors ;
+ui.tools.workspace accessors sets destructors fry ;
IN: ui.tools.interactor
! If waiting is t, we're waiting for user input, and invoking
: interactor-continue ( obj interactor -- )
mailbox>> mailbox-put ;
-: clear-input ( interactor -- ) model>> clear-doc ;
+: clear-input ( interactor -- )
+ #! The with-datastack is a kludge to make it infer. Stupid.
+ model>> 1array [ clear-doc ] with-datastack drop ;
: interactor-finish ( interactor -- )
- #! The spawn is a kludge to make it infer. Stupid.
[ editor-string ] keep
[ interactor-input. ] 2keep
[ add-interactor-history ] keep
- [ clear-input ] curry "Clearing input" spawn drop ;
+ clear-input ;
: interactor-eof ( interactor -- )
dup interactor-busy? [
swap dup zero? [
2drop ""
] [
- >r interactor-read dup [ "\n" join ] when r> short head
+ [ interactor-read dup [ "\n" join ] when ] dip short head
] if ;
M: interactor stream-read-partial
: handle-interactive ( lines interactor -- quot/f ? )
tuck try-parse {
{ [ dup quotation? ] [ nip t ] }
- { [ dup not ] [ drop "\n" swap user-input f f ] }
+ { [ dup not ] [ drop "\n" swap user-input* drop f f ] }
[ handle-parse-error f f ]
} cond ;
]
} cond ;
-M: interactor pref-dim*
- [ line-height 4 * 0 swap 2array ] [ call-next-method ] bi
- vmax ;
-
interactor "interactor" f {
{ T{ key-down f f "RET" } evaluate-input }
{ T{ key-down f { C+ } "k" } clear-input }
ui.tools.listener hashtables kernel namespaces parser sequences
tools.test ui.commands ui.gadgets ui.gadgets.editors
ui.gadgets.panes vocabs words tools.test.ui slots.private
-threads arrays generic threads accessors listener math ;
+threads arrays generic threads accessors listener math
+calendar ;
IN: ui.tools.listener.tests
[ f ] [ "word" source-editor command-map commands>> empty? ] unit-test
[ ] [ "listener" get restart-listener ] unit-test
- [ ] [ 1000 sleep ] unit-test
+ [ ] [ 1 seconds sleep ] unit-test
[ ] [ "listener" get com-end ] unit-test
] with-grafted-gadget
! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: inspector ui.tools.interactor ui.tools.inspector
-ui.tools.workspace help.markup io io.styles
-kernel models namespaces parser quotations sequences ui.commands
-ui.gadgets ui.gadgets.editors ui.gadgets.labelled
-ui.gadgets.panes ui.gadgets.buttons ui.gadgets.scrollers
-ui.gadgets.tracks ui.gestures ui.operations vocabs words
-prettyprint listener debugger threads boxes concurrency.flags
-math arrays generic accessors combinators assocs ;
+USING: inspector help help.markup io io.styles kernel models
+namespaces parser quotations sequences vocabs words prettyprint
+listener debugger threads boxes concurrency.flags math arrays
+generic accessors combinators assocs fry ui.commands ui.gadgets
+ui.gadgets.editors ui.gadgets.labelled ui.gadgets.panes
+ui.gadgets.buttons ui.gadgets.scrollers ui.gadgets.packs
+ui.gadgets.tracks ui.gadgets.borders ui.gadgets.frames
+ui.gadgets.grids ui.gestures ui.operations ui.tools.browser
+ui.tools.interactor ui.tools.inspector ui.tools.workspace ;
IN: ui.tools.listener
-TUPLE: listener-gadget < track input output stack ;
-
-: listener-output, ( listener -- listener )
- <scrolling-pane> >>output
- dup output>> <scroller> "Output" <labelled-gadget> 1 track-add ;
+TUPLE: listener-gadget < track input output ;
: listener-streams ( listener -- input output )
[ input>> ] [ output>> <pane-stream> ] bi ;
: <listener-input> ( listener -- gadget )
output>> <pane-stream> <interactor> ;
-: listener-input, ( listener -- listener )
- dup <listener-input> >>input
- dup input>>
- { 0 100 } <limited-scroller>
- "Input" <labelled-gadget>
- f track-add ;
-
: welcome. ( -- )
"If this is your first time with Factor, please read the " print
- "handbook" ($link) "." print nl ;
+ "handbook" ($link) ". To see a list of keyboard shortcuts," print
+ "press F1." print nl ;
M: listener-gadget focusable-child*
input>> ;
M: listener-gadget call-tool* ( input listener -- )
- >r string>> r> input>> set-editor-string ;
+ [ string>> ] dip input>> set-editor-string ;
M: listener-gadget tool-scroller
output>> find-scroller ;
: call-listener ( quot -- )
[ workspace-busy? not ] get-workspace* listener>>
- [ dup wait-for-listener (call-listener) ] 2curry
+ '[ _ _ dup wait-for-listener (call-listener) ]
"Listener call" spawn drop ;
M: listener-command invoke-command ( target command -- )
: listener-run-files ( seq -- )
[
- [ [ run-file ] each ] curry call-listener
+ '[ _ [ run-file ] each ] call-listener
] unless-empty ;
: com-end ( listener -- )
: use-if-necessary ( word seq -- )
over vocabulary>> over and [
2dup [ assoc-stack ] keep = [ 2drop ] [
- >r vocabulary>> vocab-words r> push
+ [ vocabulary>> vocab-words ] dip push
] if
] [ 2drop ] if ;
: insert-word ( word -- )
get-workspace listener>> input>>
- [ >r word-completion-string r> user-input ]
+ [ [ word-completion-string ] dip user-input* drop ]
[ interactor-use use-if-necessary ]
2bi ;
[ select-all ]
2bi ;
-TUPLE: stack-display < track ;
-
-: <stack-display> ( workspace -- gadget )
- listener>>
- { 0 1 } stack-display new-track
- over <toolbar> f track-add
- swap stack>> [ [ stack. ] curry try ] t "Data stack" <labelled-pane>
- 1 track-add ;
-
-M: stack-display tool-scroller
- find-workspace listener>> tool-scroller ;
-
-: ui-listener-hook ( listener -- )
- >r datastack r> stack>> set-model ;
+: ui-help-hook ( topic -- )
+ browser-gadget call-tool ;
: ui-error-hook ( error listener -- )
find-workspace debugger-popup ;
: listener-thread ( listener -- )
dup listener-streams [
- [ [ ui-listener-hook ] curry listener-hook set ]
- [ [ ui-error-hook ] curry error-hook set ]
- [ [ ui-inspector-hook ] curry inspector-hook set ] tri
+ [ ui-help-hook ] help-hook set
+ [ '[ _ ui-error-hook ] error-hook set ]
+ [ '[ _ ui-inspector-hook ] inspector-hook set ] bi
welcome.
listener
] with-streams* ;
: start-listener-thread ( listener -- )
- [
- [ input>> register-self ] [ listener-thread ] bi
- ] curry "Listener" spawn drop ;
+ '[
+ _
+ [ input>> register-self ]
+ [ listener-thread ]
+ bi
+ ] "Listener" spawn drop ;
: restart-listener ( listener -- )
#! Returns when listener is ready to receive input.
[ wait-for-listener ]
} cleave ;
-: init-listener ( listener -- )
- f <model> >>stack drop ;
+: init-listener ( listener -- listener )
+ <scrolling-pane> >>output
+ dup <listener-input> >>input ;
+
+: <listener-scroller> ( listener -- scroller )
+ <frame>
+ over output>> @top grid-add
+ swap input>> @center grid-add
+ <scroller> ;
: <listener-gadget> ( -- gadget )
{ 0 1 } listener-gadget new-track
- dup init-listener
- listener-output,
- listener-input, ;
+ add-toolbar
+ init-listener
+ dup <listener-scroller> 1 track-add ;
: listener-help ( -- ) "ui-listener" help-window ;
\ listener-help H{ { +nullary+ t } } define-command
+: com-auto-use ( -- )
+ auto-use? [ not ] change ;
+
+\ com-auto-use H{ { +nullary+ t } { +listener+ t } } define-command
+
+listener-gadget "misc" "Miscellaneous commands" {
+ { T{ key-down f f "F1" } listener-help }
+} define-command-map
+
listener-gadget "toolbar" f {
{ f restart-listener }
- { T{ key-down f f "CLEAR" } clear-output }
- { T{ key-down f { C+ } "CLEAR" } clear-stack }
+ { T{ key-down f { A+ } "u" } com-auto-use }
+ { T{ key-down f { A+ } "k" } clear-output }
+ { T{ key-down f { A+ } "K" } clear-stack }
{ T{ key-down f { C+ } "d" } com-end }
- { T{ key-down f f "F1" } listener-help }
} define-command-map
M: listener-gadget handle-gesture ( gesture gadget -- ? )
! See http://factorcode.org/license.txt for BSD license.
USING: ui.tools.workspace kernel quotations tools.profiler
ui.commands ui.gadgets ui.gadgets.panes ui.gadgets.scrollers
-ui.gadgets.tracks ui.gestures ui.gadgets.buttons accessors ;
+ui.gadgets.tracks ui.gestures ui.gadgets.buttons accessors fry ;
IN: ui.tools.profiler
TUPLE: profiler-gadget < track pane ;
: <profiler-gadget> ( -- gadget )
{ 0 1 } profiler-gadget new-track
- dup <toolbar> f track-add
+ add-toolbar
<pane> >>pane
dup pane>> <scroller> 1 track-add ;
: with-profiler-pane ( gadget quot -- )
- >r pane>> r> with-pane ;
+ [ pane>> ] dip with-pane ;
: com-full-profile ( gadget -- )
[ profile. ] with-profiler-pane ;
GENERIC: profiler-presentation ( obj -- quot )
M: usage-profile profiler-presentation
- word>> [ usage-profile. ] curry ;
+ word>> '[ _ usage-profile. ] ;
M: vocab-profile profiler-presentation
- vocab>> [ vocab-profile. ] curry ;
+ vocab>> '[ _ vocab-profile. ] ;
M: f profiler-presentation
drop [ vocabs-profile. ] ;
USING: assocs ui.tools.search help.topics io.files io.styles
kernel namespaces sequences source-files threads
tools.test ui.gadgets ui.gestures vocabs accessors
-vocabs.loader words tools.test.ui debugger ;
+vocabs.loader words tools.test.ui debugger calendar ;
IN: ui.tools.search.tests
[ f ] [
: update-live-search ( search -- seq )
dup [
- 300 sleep
+ 300 milliseconds sleep
list>> control-value
] with-grafted-gadget ;
: test-live-search ( gadget quot -- ? )
- >r update-live-search dup assert-non-empty r> all? ;
+ [ update-live-search dup assert-non-empty ] dip all? ;
[ t ] [
"swp" all-words f <definition-search>
"" all-words t <definition-search>
dup [
{ "set-word-prop" } over field>> set-control-value
- 300 sleep
+ 300 milliseconds sleep
search-value \ set-word-prop eq?
] with-grafted-gadget
] unit-test
! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors assocs ui.tools.interactor ui.tools.listener
-ui.tools.workspace help help.topics io.files io.styles kernel
-models models.delay models.filter namespaces prettyprint
+USING: accessors assocs help help.topics io.files io.styles
+kernel models models.delay models.filter namespaces prettyprint
quotations sequences sorting source-files definitions strings
-tools.completion tools.crossref classes.tuple ui.commands
-ui.gadgets ui.gadgets.editors ui.gadgets.lists
-ui.gadgets.scrollers ui.gadgets.tracks ui.gestures ui.operations
-vocabs words vocabs.loader tools.vocabs unicode.case calendar ui
-;
+tools.completion tools.crossref classes.tuple vocabs words
+vocabs.loader tools.vocabs unicode.case calendar locals
+ui.tools.interactor ui.tools.listener ui.tools.workspace
+ui.commands ui.gadgets ui.gadgets.editors ui.gadgets.lists
+ui.gadgets.scrollers ui.gadgets.tracks ui.gadgets.borders
+ui.gestures ui.operations ui ;
IN: ui.tools.search
TUPLE: live-search < track field list ;
M: live-search handle-gesture ( gesture live-search -- ? )
tuck search-gesture dup [
over find-workspace hide-popup
- >r search-value r> invoke-command f
+ [ search-value ] dip invoke-command f
] [
2drop t
] if ;
{ T{ key-down f f "RET" } [ find-search-list invoke-value-action ] }
} set-gestures
-: <search-model> ( live-search producer -- live-search filter )
- >r dup field>> model>> ! live-search model :: producer
- ui-running? [ 1/5 seconds <delay> ] when
- [ "\n" join ] r> append <filter> ;
+: <search-model> ( live-search producer -- filter )
+ [
+ field>> model>>
+ ui-running? [ 1/5 seconds <delay> ] when
+ ] dip [ "\n" join ] prepend <filter> ;
-: <search-list> ( live-search seq limited? presenter -- live-search list )
- >r
- [ limited-completions ] [ completions ] ? curry
- <search-model>
- >r [ find-workspace hide-popup ] r> r>
- swap <list> ;
+: init-search-model ( live-search seq limited? -- live-search )
+ [ 2drop ]
+ [ [ limited-completions ] [ completions ] ? curry <search-model> ] 3bi
+ >>model ; inline
-: <live-search> ( string seq limited? presenter -- gadget )
+: <search-list> ( presenter live-search -- list )
+ [ [ find-workspace hide-popup ] ] [ ] [ model>> ] tri* <list> ;
+
+:: <live-search> ( string seq limited? presenter -- gadget )
{ 0 1 } live-search new-track
<search-field> >>field
- dup field>> f track-add
- -roll <search-list> >>list
+ seq limited? init-search-model
+ presenter over <search-list> >>list
+ dup field>> 1 <border> { 1 1 } >>fill f track-add
dup list>> <scroller> 1 track-add
- swap
- over field>> set-editor-string
- dup field>> end-of-document ;
+ string over field>> set-editor-string
+ dup field>> end-of-document ;
M: live-search focusable-child* field>> ;
[ dup synopsis >lower ] { } map>assoc sort-values ;
: <definition-search> ( string words limited? -- gadget )
- >r definition-candidates r> [ synopsis ] <live-search> ;
+ [ definition-candidates ] dip [ synopsis ] <live-search> ;
: word-candidates ( words -- candidates )
[ dup name>> >lower ] { } map>assoc ;
: <word-search> ( string words limited? -- gadget )
- >r word-candidates r> [ synopsis ] <live-search> ;
+ [ word-candidates ] dip [ synopsis ] <live-search> ;
: com-words ( workspace -- )
dup current-word all-words t <word-search>
"Word search" show-titled-popup ;
: show-vocab-words ( workspace vocab -- )
- "" over words natural-sort f <word-search>
- "Words in " rot vocab-name append show-titled-popup ;
+ [ "" swap words natural-sort f <word-search> ]
+ [ "Words in " swap vocab-name append ]
+ bi show-titled-popup ;
: show-word-usage ( workspace word -- )
- "" over smart-usage f <definition-search>
- "Words and methods using " rot name>> append
- show-titled-popup ;
+ [ "" swap smart-usage f <definition-search> ]
+ [ "Words and methods using " swap name>> append ]
+ bi show-titled-popup ;
: help-candidates ( seq -- candidates )
[ dup >link swap article-title >lower ] { } map>assoc
"Source file search" show-titled-popup ;
: show-vocab-files ( workspace vocab -- )
- "" over vocab-files <source-file-search>
- "Source files in " rot vocab-name append show-titled-popup ;
+ [ "" swap vocab-files <source-file-search> ]
+ [ "Source files in " swap vocab-name append ]
+ bi show-titled-popup ;
: vocab-candidates ( -- candidates )
all-vocabs-seq [ dup vocab-name >lower ] { } map>assoc ;
{ $heading "Editing commands" }
"The text editing commands are standard; see " { $link "gadgets-editors" } "."
{ $heading "Implementation" }
-"Listeners are instances of " { $link listener-gadget } ". The listener consists of an output area (instance of " { $link pane } "), and an input area (instance of " { $link interactor } "), and a stack display kept up to date using a " { $link listener-hook } "." ;
+"Listeners are instances of " { $link listener-gadget } ". The listener consists of an output area (instance of " { $link pane } ") and an input area (instance of " { $link interactor } ")." ;
ARTICLE: "ui-inspector" "UI inspector"
"The graphical inspector builds on the terminal inspector (see " { $link "inspector" } ") and provides in-place editing of slot values."
;
-ARTICLE: "ui-tool-tutorial" "UI tool tutorial"
-"The following is an example of a typical session with the UI which should give you a taste of its power:"
-{ $list
- { "You decide to refactor some code, and move a few words from a source file you have already loaded, into a new source file." }
- { "You press " { $operation edit } " in the listener, which displays a gadget where you can type part of a loaded file's name, and then press " { $snippet "RET" } " when the correct completion is highlighted. This opens the file in your editor." }
- { "You refactor your words, move them to a new source file, and load the new file using " { $link run-file } "." }
- { "Interactively testing the new code reveals a problem with one particular code snippet, so you enter it in the listener's input area, and press " { $operation walk } " to invoke the single stepper." }
- { "Single stepping through the code makes the problem obvious, so you right-click on a presentation of the broken word in the stepper, and choose " { $strong "Edit" } " from the menu." }
- { "After fixing the problem in the source editor, you right click on the word in the stepper and invoke " { $strong "Reload" } " from the menu." }
-} ;
-
ARTICLE: "ui-completion-words" "Word completion popup"
"Clicking a word in the word completion popup displays the word definition in the " { $link "ui-browser" } ". Pressing " { $snippet "RET" } " with a word selected inserts the word name in the listener, along with a " { $link POSTPONE: USE: } " declaration (if necessary)."
{ $operations \ $operations } ;
{ $subsection "ui-completion-sources" } ;
ARTICLE: "ui-workspace-keys" "UI keyboard shortcuts"
+"See " { $link "gesture-differences" } " to find out how your platform's modifier keys map to modifiers in the Factor UI."
{ $command-map workspace "tool-switching" }
{ $command-map workspace "scrolling" }
{ $command-map workspace "workflow" }
-{ $command-map workspace "multi-touch" }
-{ $heading "Implementation" }
-"Workspaces are instances of " { $link workspace } "." ;
+{ $command-map workspace "multi-touch" } ;
ARTICLE: "ui-tools" "UI developer tools"
"The Factor development environment can seem rather different from what you are used to, because it is very simple and powerful.."
$nl
"To take full advantage of the UI, you should be using a supported text editor. See " { $link "editor" } "."
-{ $subsection "ui-tool-tutorial" }
{ $subsection "ui-workspace-keys" }
{ $subsection "ui-presentations" }
{ $subsection "ui-completion" }
ui.gadgets.scrollers ui.gadgets.tracks ui.gadgets.worlds
ui.gadgets.presentations ui.gestures words vocabs.loader
tools.test tools.vocabs ui.gadgets.buttons ui.gadgets.status-bar
-mirrors ;
+mirrors fry ;
IN: ui.tools
: <workspace-tabs> ( workspace -- tabs )
<toggle-buttons> ;
: <workspace-book> ( workspace -- gadget )
- dup
- <stack-display>
+ <gadget>
<browser-gadget>
<inspector-gadget>
<profiler-gadget>
dup <workspace-book> >>book
dup <workspace-tabs> f track-add
- dup book>> 1/5 track-add
- dup listener>> 4/5 track-add
- dup <toolbar> f track-add ;
+ dup book>> 0 track-add
+ dup listener>> 1 track-add
+ add-toolbar ;
: resize-workspace ( workspace -- )
- dup sizes>> over control-value zero? [
- 1/5 over set-second
- 4/5 swap set-third
+ dup sizes>> over control-value 0 = [
+ 0 over set-second
+ 1 swap set-third
] [
2/3 over set-second
1/3 swap set-third
[ workspace-window ] ui-hook set-global
-: com-listener ( workspace -- ) stack-display select-tool ;
+: select-tool ( workspace n -- ) swap book>> model>> set-model ;
-: com-browser ( workspace -- ) browser-gadget select-tool ;
+: com-listener ( workspace -- ) 0 select-tool ;
-: com-inspector ( workspace -- ) inspector-gadget select-tool ;
+: com-browser ( workspace -- ) 1 select-tool ;
-: com-profiler ( workspace -- ) profiler-gadget select-tool ;
+: com-inspector ( workspace -- ) 2 select-tool ;
+
+: com-profiler ( workspace -- ) 3 select-tool ;
workspace "tool-switching" f {
{ T{ key-down f { A+ } "1" } com-listener }
] workspace-window-hook set-global
: inspect-continuation ( traceback -- )
- control-value [ inspect ] curry call-listener ;
+ control-value '[ _ inspect ] call-listener ;
traceback-gadget "toolbar" f {
{ T{ key-down f f "v" } variables }
dup model>> <callstack-display> 2/3 track-add
- dup <toolbar> f track-add ;
+ add-toolbar ;
: <namestack-display> ( model -- gadget )
[ [ name>> namestack. ] when* ]
<pane-control> ;
: <variables-gadget> ( model -- gadget )
- <namestack-display> { 400 400 } <limited-scroller> ;
+ <namestack-display>
+ <limited-scroller>
+ { 400 400 } >>min-dim
+ { 400 400 } >>max-dim ;
: variables ( traceback -- )
model>> <variables-gadget>
"Dynamic variables" open-status-window ;
: traceback-window ( continuation -- )
- <model> <traceback-gadget> "Traceback" open-window ;
+ <model> <traceback-gadget> "Traceback" open-status-window ;
ui.gadgets.status-bar ui.gadgets.tracks ui.commands ui.gadgets
models models.filter ui.tools.workspace ui.gestures
ui.gadgets.labels ui threads namespaces make tools.walker assocs
-combinators ;
+combinators fry ;
IN: ui.tools.walker
TUPLE: walker-gadget < track
] "" make ;
: <thread-status> ( model thread -- gadget )
- [ walker-state-string ] curry <filter> <label-control> ;
+ '[ _ walker-state-string ] <filter> <label-control> ;
: <walker-gadget> ( status continuation thread -- gadget )
{ 0 1 } walker-gadget new-track
swap >>status
dup continuation>> <traceback-gadget> >>traceback
- dup <toolbar> f track-add
+ add-toolbar
dup status>> self <thread-status> f track-add
- dup traceback>> 1 track-add ;
+ dup traceback>> 1 track-add ;
: walker-help ( -- ) "ui-walker" help-window ;
} cond ;
: find-walker-window ( thread -- world/f )
- [ swap walker-for-thread? ] curry find-window ;
+ '[ _ swap walker-for-thread? ] find-window ;
: walker-window ( status continuation thread -- )
[ <walker-gadget> ] [ name>> ] bi open-status-window ;
-! Copyright (C) 2006, 2007 Slava Pestov.
+! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: classes continuations help help.topics kernel models
- sequences ui ui.backend ui.tools.debugger ui.gadgets
- ui.gadgets.books ui.gadgets.buttons ui.gadgets.labelled
- ui.gadgets.panes ui.gadgets.scrollers ui.gadgets.tracks
- ui.gadgets.worlds ui.gadgets.presentations ui.gadgets.status-bar
- ui.commands ui.gestures assocs arrays namespaces accessors ;
-
+sequences assocs arrays namespaces accessors math.vectors fry ui
+ui.backend ui.tools.debugger ui.gadgets ui.gadgets.books
+ui.gadgets.buttons ui.gadgets.labelled ui.gadgets.panes
+ui.gadgets.scrollers ui.gadgets.tracks ui.gadgets.worlds
+ui.gadgets.presentations ui.gadgets.status-bar ui.commands
+ui.gestures ;
IN: ui.tools.workspace
TUPLE: workspace < track book listener popup ;
[ find-tool swap ] keep book>> model>>
set-model ;
-: select-tool ( workspace class -- ) swap show-tool drop ;
-
: get-workspace* ( quot -- workspace )
- [ >r dup workspace? r> [ drop f ] if ] curry find-window
+ '[ dup workspace? _ [ drop f ] if ] find-window
[ dup raise-window gadget-child ]
[ workspace-window* ] if* ; inline
: get-tool ( class -- gadget )
get-workspace find-tool nip ;
+: <help-pane> ( topic -- pane )
+ <pane> [ [ help ] with-pane ] keep ;
+
: help-window ( topic -- )
[
- <pane> [ [ help ] with-pane ] keep
- { 550 700 } <limited-scroller>
- ] keep
- article-title open-window ;
+ <help-pane> <limited-scroller>
+ { 550 700 } >>max-dim
+ ] [ article-title ] bi
+ open-window ;
: hide-popup ( workspace -- )
dup popup>> track-remove
{ 600 700 } workspace-dim set-global
-M: workspace pref-dim* drop workspace-dim get ;
+M: workspace pref-dim* call-next-method workspace-dim get vmax ;
M: workspace focusable-child*
dup popup>> [ ] [ listener>> ] ?if ;
-! Copyright (C) 2007 Slava Pestov.
+! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors namespaces make sequences kernel math arrays io
ui.gadgets generic combinators ;
TUPLE: node value children ;
: traverse-step ( path gadget -- path' gadget' )
- >r unclip r> children>> ?nth ;
+ [ unclip ] dip children>> ?nth ;
: make-node ( quot -- ) { } make node boa , ; inline
traverse-step traverse-from-path ;
: (traverse-middle) ( frompath topath gadget -- )
- >r >r first 1+ r> first r> children>> <slice> % ;
+ [ first 1+ ] [ first ] [ children>> ] tri* <slice> % ;
: traverse-post ( topath gadget -- )
traverse-step traverse-to-path ;
DEFER: (gadget-subtree)
: traverse-child ( frompath topath gadget -- )
- dup -roll [
- >r >r rest-slice r> r> traverse-step (gadget-subtree)
- ] make-node ;
+ [ 2nip ] 3keep
+ [ [ rest-slice ] 2dip traverse-step (gadget-subtree) ]
+ make-node ;
: (gadget-subtree) ( frompath topath gadget -- )
{
{ [ dup not ] [ 3drop ] }
{ [ pick empty? pick empty? and ] [ 2nip , ] }
- { [ pick empty? ] [ rot drop traverse-to-path ] }
+ { [ pick empty? ] [ traverse-to-path drop ] }
{ [ over empty? ] [ nip traverse-from-path ] }
{ [ pick first pick first = ] [ traverse-child ] }
[ traverse-middle ]
USING: help.markup help.syntax strings quotations debugger
io.styles namespaces ui.backend ui.gadgets ui.gadgets.worlds
-ui.gadgets.tracks ui.gadgets.packs ui.gadgets.grids math.geometry.rect ;
+ui.gadgets.tracks ui.gadgets.packs ui.gadgets.grids math.geometry.rect colors ;
IN: ui
HELP: windows
{ $description "Opens a native window containing the given world. This grafts the world by calling " { $link graft } ". Each world can only be displayed in one top-level window at a time." }
{ $notes "This word should not be called directly by user code. Instead, use " { $link open-window } "." } ;
-HELP: ui-try
+HELP: raise-window
+{ $values { "gadget" gadget } }
+{ $description "Makes the native window containing the given gadget the front-most window." } ;
+
+HELP: with-ui
{ $values { "quot" quotation } }
-{ $description "Calls the quotation. If it throws an error, opens a window with the error and restores the data stack." }
-{ $notes "This is essentially a graphical variant of " { $link try } "." } ;
+{ $description "Calls the quotation, starting the UI first if necessary." }
+{ $notes "This combinator should be used in the " { $link POSTPONE: MAIN: } " word of a vocabulary, in order for the vocabulary to work when run from the UI listener (" { $snippet "\"my-app\" run" } " and the command line (" { $snippet "./factor -run=my-app" } ")." }
+{ $examples "The " { $vocab-link "hello-ui" } " vocabulary implements a simple UI application which uses this combinator." } ;
ARTICLE: "ui-glossary" "UI glossary"
{ $table
- { "color specifier"
- { "an array of four elements, all numbers between 0 and 1:"
- { $list
- "red"
- "green"
- "blue"
- "alpha - 0 is completely transparent, 1 is completely opaque"
- }
- }
- }
+ { "color" { "an instance of " { $link color } } }
{ "dimension" "a pair of integers denoting pixel size on screen" }
{ "font specifier"
{ "an array of three elements:"
{ $subsection "ui.gadgets.sliders" }
{ $subsection "ui.gadgets.scrollers" }
{ $subsection "gadgets-editors" }
+{ $subsection "ui.gadgets.menus" }
{ $subsection "ui.gadgets.panes" }
{ $subsection "ui.gadgets.presentations" }
{ $subsection "ui.gadgets.lists" } ;
ARTICLE: "ui-geometry" "Gadget geometry"
"The " { $link gadget } " class inherits from the " { $link rect } " class, and thus all gadgets have a bounding box:"
-{ $subsection rect }
-"Rectangles can be taken apart:"
-{ $subsection rect-loc }
-{ $subsection rect-dim }
-{ $subsection rect-bounds }
-{ $subsection rect-extent }
-"New rectangles can be created:"
-{ $subsection <zero-rect> }
-{ $subsection <rect> }
-{ $subsection <extent-rect> }
-"More utility words for working with rectangles:"
-{ $subsection offset-rect }
-{ $subsection rect-intersect }
-{ $subsection intersects? }
-
-! "A gadget's bounding box is always relative to its parent. "
-! { $subsection gadget-parent }
-
+{ $subsection "math.geometry.rect" }
"Word for converting from a child gadget's co-ordinate system to a parent's:"
{ $subsection relative-loc }
{ $subsection screen-loc }
"UI backends may implement the " { $link "clipboard-protocol" } "." ;
ARTICLE: "ui-backend-init" "UI initialization and the event loop"
-"An UI backend is required to define a word to start the UI:"
-{ $subsection ui }
-"This word should contain backend initialization, together with some boilerplate:"
+"An UI backend is required to define a method on the " { $link ui } " word. This word should contain backend initialization, together with some boilerplate:"
{ $code
"IN: shells"
""
"If the user clicks the window's close box, you must call the following word:"
{ $subsection close-window } ;
-HELP: raise-window
-{ $values { "gadget" gadget } }
-{ $description "Makes the native window containing the given gadget the front-most window." } ;
-
ARTICLE: "ui-layouts" "Gadget hierarchy and layouts"
"A layout gadget is a gadget whose sole purpose is to contain other gadgets. Layout gadgets position and resize children according to a certain policy, taking the preferred size of the children into account. Gadget hierarchies are constructed by building up nested layouts."
{ $subsection "ui-layout-basics" }
{ $subsection "clipboard-protocol" }
{ $see-also "ui-layout-impl" } ;
+ARTICLE: "starting-ui" "Starting the UI"
+"The UI starts automatically where possible:"
+{ $list
+ { "On Windows, the UI starts when the Factor executable is run." }
+ { "On X11, the UI starts if the " { $snippet "DISPLAY" } " environment variable is set." }
+ { "On Mac OS X, the UI starts if the " { $snippet "Factor.app" } " application bundle is run." }
+}
+"In all cases, passing the " { $snippet "-run=listener" } " command line switch starts the terminal listener instead. The UI can be started from the terminal listener using a word:"
+{ $subsection ui }
+"To run the terminal listener and the UI simultaneously, start the UI in a new thread:"
+{ $code "USING: threads ui ;" "[ ui ] in-thread" }
+"The main word of a vocabulary implementing a UI application should use a combinator to ensure that the application works when run from the command line as well as in the UI listener:"
+{ $subsection with-ui } ;
+
ARTICLE: "ui" "UI framework"
+"The " { $vocab-link "ui" } " vocabulary hierarchy implements the Factor UI framework. The implementation relies on a small amount of platform-specific code to open windows and receive keyboard and mouse events; UI gadgets are rendered using OpenGL."
+{ $subsection "starting-ui" }
{ $subsection "ui-glossary" }
{ $subsection "building-ui" }
{ $subsection "new-gadgets" }
--- /dev/null
+IN: ui.tests
+USING: ui tools.test ;
+
+\ event-loop must-infer
+\ open-window must-infer
-! Copyright (C) 2006, 2007 Slava Pestov.
+! Copyright (C) 2006, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays assocs io kernel math models namespaces make
-prettyprint dlists deques sequences threads sequences words
-debugger ui.gadgets ui.gadgets.worlds ui.gadgets.tracks
-ui.gestures ui.backend ui.render continuations init combinators
-hashtables concurrency.flags sets accessors ;
+dlists deques sequences threads sequences words ui.gadgets
+ui.gadgets.worlds ui.gadgets.tracks ui.gestures ui.backend
+ui.render continuations init combinators hashtables
+concurrency.flags sets accessors calendar ;
IN: ui
! Assoc mapping aliens to gadgets
focus-path f swap focus-gestures ;
M: world graft*
- dup (open-window)
- dup title>> over set-title
- request-focus ;
+ [ (open-window) ]
+ [ [ title>> ] keep set-title ]
+ [ request-focus ] tri ;
: reset-world ( world -- )
#! This is used when a window is being closed, but also
#! when restoring saved worlds on image startup.
- dup fonts>> clear-assoc
- dup unfocus-world
- f >>handle drop ;
+ [ fonts>> clear-assoc ]
+ [ unfocus-world ]
+ [ f >>handle drop ] tri ;
+
+: (ungraft-world) ( world -- )
+ [ free-fonts ]
+ [ hand-clicked close-global ]
+ [ hand-gadget close-global ] tri ;
M: world ungraft*
- dup free-fonts
- dup hand-clicked close-global
- dup hand-gadget close-global
- dup handle>> (close-window)
- reset-world ;
+ [ (ungraft-world) ]
+ [ handle>> (close-window) ]
+ [ reset-world ] tri ;
: find-window ( quot -- world )
windows get values
: init-ui ( -- )
<dlist> \ graft-queue set-global
<dlist> \ layout-queue set-global
+ <dlist> \ gesture-queue set-global
V{ } clone windows set-global ;
: restore-gadget-later ( gadget -- )
: notify ( gadget -- )
dup graft-state>>
- dup first { f f } { t t } ?
- pick (>>graft-state) {
+ [ first { f f } { t t } ? >>graft-state ] keep
+ {
{ { f t } [ dup activate-control graft* ] }
{ { t f } [ dup deactivate-control ungraft* ] }
} case ;
: notify-queued ( -- )
graft-queue [ notify ] slurp-deque ;
+: send-queued-gestures ( -- )
+ gesture-queue [ send-queued-gesture notify-queued ] slurp-deque ;
+
: update-ui ( -- )
- [ notify-queued layout-queued redraw-worlds ] assert-depth ;
+ [
+ [
+ notify-queued
+ layout-queued
+ redraw-worlds
+ send-queued-gestures
+ ] assert-depth
+ ] [ ui-error ] recover ;
: ui-wait ( -- )
- 10 sleep ;
-
-: ui-try ( quot -- ) [ ui-error ] recover ;
+ 10 milliseconds sleep ;
SYMBOL: ui-thread
\ ui-running get-global ;
: update-ui-loop ( -- )
- ui-running? ui-thread get-global self eq? and [
- ui-notify-flag get lower-flag
- [ update-ui ] ui-try
- update-ui-loop
- ] when ;
+ [ ui-running? ui-thread get-global self eq? and ]
+ [ ui-notify-flag get lower-flag update-ui ]
+ [ ] while ;
: start-ui-thread ( -- )
[ self ui-thread set-global update-ui-loop ]
ui.gestures io kernel math math.vectors namespaces make
sequences strings vectors words windows.kernel32 windows.gdi32
windows.user32 windows.opengl32 windows.messages windows.types
-windows.nt windows threads libc combinators continuations
-command-line shuffle opengl ui.render unicode.case ascii
-math.bitwise locals symbols accessors math.geometry.rect ;
+windows.nt windows threads libc combinators fry
+combinators.short-circuit continuations command-line shuffle
+opengl ui.render ascii math.bitwise locals symbols accessors
+math.geometry.rect math.order ascii calendar
+io.encodings.utf16n ;
IN: ui.windows
SINGLETON: windows-ui-backend
<pasteboard> clipboard set-global
<clipboard> selection set-global ;
-! world-handle is a <win>
-TUPLE: win hWnd hDC hRC world title ;
+TUPLE: win-base hDC hRC ;
+TUPLE: win < win-base hWnd world title ;
+TUPLE: win-offscreen < win-base hBitmap bits ;
C: <win> win
+C: <win-offscreen> win-offscreen
SYMBOLS: msg-obj class-name-ptr mouse-captured ;
: alt? ( -- ? ) left-alt? right-alt? or ;
: caps-lock? ( -- ? ) VK_CAPITAL GetKeyState zero? not ;
-: switch-case ( seq -- seq )
- dup first CHAR: a >= [ >upper ] [ >lower ] if ;
-
-: switch-case? ( -- ? ) shift? caps-lock? xor not ;
-
: key-modifiers ( -- seq )
[
shift? [ S+ , ] when
: exclude-key-wm-char? ( n -- bool )
exclude-keys-wm-char key? ;
-: keystroke>gesture ( n -- mods sym ? )
- dup wm-keydown-codes at* [
- nip >r key-modifiers r> t
- ] [
- drop 1string >r key-modifiers r>
- C+ pick member? >r A+ pick member? r> or [
- shift? [ >lower ] unless f
- ] [
- switch-case? [ switch-case ] when t
- ] if
- ] if ;
+: keystroke>gesture ( n -- mods sym )
+ wm-keydown-codes at* [ key-modifiers swap ] [ drop f f ] if ;
+
+: send-key-gesture ( sym action? quot hWnd -- )
+ [ [ key-modifiers ] 3dip call ] dip
+ window propagate-key-gesture ; inline
+
+: send-key-down ( sym action? hWnd -- )
+ [ [ <key-down> ] ] dip send-key-gesture ;
+
+: send-key-up ( sym action? hWnd -- )
+ [ [ <key-up> ] ] dip send-key-gesture ;
+
+: key-sym ( wParam -- string/f action? )
+ {
+ {
+ [ dup LETTER? ]
+ [ shift? caps-lock? xor [ CHAR: a + CHAR: A - ] unless 1string f ]
+ }
+ { [ dup digit? ] [ 1string f ] }
+ [ wm-keydown-codes at t ]
+ } cond ;
:: handle-wm-keydown ( hWnd uMsg wParam lParam -- )
wParam exclude-key-wm-keydown? [
- wParam keystroke>gesture <key-down>
- hWnd window-focus send-gesture drop
+ wParam key-sym over [
+ dup ctrl? alt? xor or [
+ hWnd send-key-down
+ ] [ 2drop ] if
+ ] [ 2drop ] if
] unless ;
:: handle-wm-char ( hWnd uMsg wParam lParam -- )
- wParam exclude-key-wm-char? ctrl? alt? xor or [
- wParam 1string
- hWnd window-focus user-input
+ wParam exclude-key-wm-char? [
+ ctrl? alt? xor [
+ wParam 1string
+ [ f hWnd send-key-down ]
+ [ hWnd window user-input ] bi
+ ] unless
] unless ;
:: handle-wm-keyup ( hWnd uMsg wParam lParam -- )
- wParam keystroke>gesture <key-up>
- hWnd window-focus send-gesture drop ;
+ wParam exclude-key-wm-keydown? [
+ wParam key-sym over [
+ hWnd send-key-up
+ ] [ 2drop ] if
+ ] unless ;
:: set-window-active ( hwnd uMsg wParam lParam ? -- n )
? hwnd window (>>active?)
: message>button ( uMsg -- button down? )
{
- { [ dup WM_LBUTTONDOWN = ] [ drop 1 t ] }
- { [ dup WM_LBUTTONUP = ] [ drop 1 f ] }
- { [ dup WM_MBUTTONDOWN = ] [ drop 2 t ] }
- { [ dup WM_MBUTTONUP = ] [ drop 2 f ] }
- { [ dup WM_RBUTTONDOWN = ] [ drop 3 t ] }
- { [ dup WM_RBUTTONUP = ] [ drop 3 f ] }
-
- { [ dup WM_NCLBUTTONDOWN = ] [ drop 1 t ] }
- { [ dup WM_NCLBUTTONUP = ] [ drop 1 f ] }
- { [ dup WM_NCMBUTTONDOWN = ] [ drop 2 t ] }
- { [ dup WM_NCMBUTTONUP = ] [ drop 2 f ] }
- { [ dup WM_NCRBUTTONDOWN = ] [ drop 3 t ] }
- { [ dup WM_NCRBUTTONUP = ] [ drop 3 f ] }
- } cond ;
+ { WM_LBUTTONDOWN [ 1 t ] }
+ { WM_LBUTTONUP [ 1 f ] }
+ { WM_MBUTTONDOWN [ 2 t ] }
+ { WM_MBUTTONUP [ 2 f ] }
+ { WM_RBUTTONDOWN [ 3 t ] }
+ { WM_RBUTTONUP [ 3 f ] }
+
+ { WM_NCLBUTTONDOWN [ 1 t ] }
+ { WM_NCLBUTTONUP [ 1 f ] }
+ { WM_NCMBUTTONDOWN [ 2 t ] }
+ { WM_NCMBUTTONUP [ 2 f ] }
+ { WM_NCRBUTTONDOWN [ 3 t ] }
+ { WM_NCRBUTTONUP [ 3 f ] }
+ } case ;
! If the user clicks in the window border ("non-client area")
! Windows sends us an NC[LMR]BUTTONDOWN message; but if the
message>button nc-buttons get
swap [ push ] [ delete ] if ;
-: >lo-hi ( WORD -- array ) [ lo-word ] keep hi-word 2array ;
-: mouse-wheel ( lParam -- array ) >lo-hi [ sgn neg ] map ;
+: >lo-hi ( WORD -- array ) [ lo-word ] [ hi-word ] bi 2array ;
-: mouse-absolute>relative ( lparam handle -- array )
- >r >lo-hi r>
- "RECT" <c-object> [ GetWindowRect win32-error=0/f ] keep
- get-RECT-top-left 2array v- ;
+: mouse-wheel ( wParam -- array ) >lo-hi [ sgn neg ] map ;
: mouse-event>gesture ( uMsg -- button )
key-modifiers swap message>button
[ <button-down> ] [ <button-up> ] if ;
-: prepare-mouse ( hWnd uMsg wParam lParam -- button coordinate world )
- nip >r mouse-event>gesture r> >lo-hi rot window ;
+:: prepare-mouse ( hWnd uMsg wParam lParam -- button coordinate world )
+ uMsg mouse-event>gesture
+ lParam >lo-hi
+ hWnd window ;
: set-capture ( hwnd -- )
mouse-captured get [
mouse-captured off ;
: handle-wm-buttondown ( hWnd uMsg wParam lParam -- )
- >r >r
- over set-capture
- dup message>button drop nc-buttons get delete
- r> r> prepare-mouse send-button-down ;
+ [
+ over set-capture
+ dup message>button drop nc-buttons get delete
+ ] 2dip prepare-mouse send-button-down ;
: handle-wm-buttonup ( hWnd uMsg wParam lParam -- )
mouse-captured get [ release-capture ] when
TrackMouseEvent drop
>lo-hi swap window move-hand fire-motion ;
-: handle-wm-mousewheel ( hWnd uMsg wParam lParam -- )
- >r nip r>
- pick mouse-absolute>relative >r mouse-wheel r> rot window send-wheel ;
+:: handle-wm-mousewheel ( hWnd uMsg wParam lParam -- )
+ wParam mouse-wheel hand-loc get hWnd window send-wheel ;
: handle-wm-cancelmode ( hWnd uMsg wParam lParam -- )
#! message sent if windows needs application to stop dragging
! return 0 if you handle the message, else just let DefWindowProc return its val
: ui-wndproc ( -- object )
"uint" { "void*" "uint" "long" "long" } "stdcall" [
- [
- pick
- trace-messages? get-global [ dup windows-message-name name>> print flush ] when
- wm-handlers get-global at* [ call ] [ drop DefWindowProc ] if
- ] ui-try
+ pick
+ trace-messages? get-global [ dup windows-message-name name>> print flush ] when
+ wm-handlers get-global at* [ call ] [ drop DefWindowProc ] if
] alien-callback ;
: peek-message? ( msg -- ? ) f 0 0 PM_REMOVE PeekMessage zero? ;
style 0 ex-style AdjustWindowRectEx win32-error=0/f ;
: make-RECT ( world -- RECT )
- dup window-loc>> dup rot rect-dim v+
+ [ window-loc>> dup ] [ rect-dim ] bi v+
"RECT" <c-object>
over first over set-RECT-right
swap second over set-RECT-bottom
: create-window ( rect -- hwnd )
make-adjusted-RECT
- >r class-name-ptr get-global f r>
- >r >r >r ex-style r> r>
+ [ class-name-ptr get-global f ] dip
+ [
+ [ ex-style ] 2dip
{ WS_CLIPSIBLINGS WS_CLIPCHILDREN style } flags
- r> get-RECT-dimensions
+ ] dip get-RECT-dimensions
f f f GetModuleHandle f CreateWindowEx dup win32-error=0/f ;
: show-window ( hWnd -- )
"MSG" malloc-object msg-obj set-global
"Factor-window" utf16n malloc-string class-name-ptr set-global
register-wndclassex drop
- GetDoubleClickTime double-click-timeout set-global ;
+ GetDoubleClickTime milliseconds double-click-timeout set-global ;
: cleanup-win32-ui ( -- )
class-name-ptr get-global [ dup f UnregisterClass drop free ] when*
f class-name-ptr set-global
f msg-obj set-global ;
-: setup-pixel-format ( hdc -- )
- 16 make-pfd [ ChoosePixelFormat dup win32-error=0/f ] 2keep
+: setup-pixel-format ( hdc flags -- )
+ 32 make-pfd [ ChoosePixelFormat dup win32-error=0/f ] 2keep
swapd SetPixelFormat win32-error=0/f ;
: get-dc ( hWnd -- hDC ) GetDC dup win32-error=0/f ;
[ wglMakeCurrent win32-error=0/f ] keep ;
: setup-gl ( hwnd -- hDC hRC )
- get-dc dup setup-pixel-format dup get-rc ;
+ get-dc dup windowed-pfd-dwFlags setup-pixel-format dup get-rc ;
M: windows-ui-backend (open-window) ( world -- )
- [ create-window dup setup-gl ] keep
+ [ create-window [ setup-gl ] keep ] keep
[ f <win> ] keep
[ swap hWnd>> register-window ] 2keep
dupd (>>handle)
hWnd>> show-window ;
-M: windows-ui-backend select-gl-context ( handle -- )
- [ hDC>> ] keep hRC>> wglMakeCurrent win32-error=0/f ;
+M: win-base select-gl-context ( handle -- )
+ [ hDC>> ] keep hRC>> wglMakeCurrent win32-error=0/f
+ GdiFlush drop ;
-M: windows-ui-backend flush-gl-context ( handle -- )
+M: win-base flush-gl-context ( handle -- )
hDC>> SwapBuffers win32-error=0/f ;
-! Move window to front
+: (bitmap-info) ( dim -- BITMAPINFO )
+ "BITMAPINFO" <c-object> [
+ BITMAPINFO-bmiHeader {
+ [ nip "BITMAPINFOHEADER" heap-size swap set-BITMAPINFOHEADER-biSize ]
+ [ [ first ] dip set-BITMAPINFOHEADER-biWidth ]
+ [ [ second ] dip set-BITMAPINFOHEADER-biHeight ]
+ [ nip 1 swap set-BITMAPINFOHEADER-biPlanes ]
+ [ nip 32 swap set-BITMAPINFOHEADER-biBitCount ]
+ [ nip BI_RGB swap set-BITMAPINFOHEADER-biCompression ]
+ [ [ first2 * 4 * ] dip set-BITMAPINFOHEADER-biSizeImage ]
+ [ nip 72 swap set-BITMAPINFOHEADER-biXPelsPerMeter ]
+ [ nip 72 swap set-BITMAPINFOHEADER-biYPelsPerMeter ]
+ [ nip 0 swap set-BITMAPINFOHEADER-biClrUsed ]
+ [ nip 0 swap set-BITMAPINFOHEADER-biClrImportant ]
+ } 2cleave
+ ] keep ;
+
+: make-offscreen-dc-and-bitmap ( dim -- hDC hBitmap bits )
+ f CreateCompatibleDC
+ dup rot (bitmap-info) DIB_RGB_COLORS f <void*>
+ [ f 0 CreateDIBSection ] keep *void*
+ [ 2dup SelectObject drop ] dip ;
+
+: setup-offscreen-gl ( dim -- hDC hRC hBitmap bits )
+ make-offscreen-dc-and-bitmap [
+ [ dup offscreen-pfd-dwFlags setup-pixel-format ]
+ [ get-rc ] bi
+ ] 2dip ;
+
+M: windows-ui-backend (open-offscreen-buffer) ( world -- )
+ dup dim>> setup-offscreen-gl <win-offscreen>
+ >>handle drop ;
+M: windows-ui-backend (close-offscreen-buffer) ( handle -- )
+ [ hDC>> DeleteDC drop ]
+ [ hBitmap>> DeleteObject drop ] bi ;
+
+! Windows 32-bit bitmaps don't actually use the alpha byte of
+! each pixel; it's left as zero
+
+: (make-opaque) ( byte-array -- byte-array' )
+ [ length 4 / ]
+ [ '[ 255 swap 4 * 3 + _ set-nth ] each ]
+ [ ] tri ;
+
+: (opaque-pixels) ( world -- pixels )
+ [ handle>> bits>> ] [ dim>> first2 * 4 * ] bi
+ memory>byte-array (make-opaque) ;
+
+M: windows-ui-backend offscreen-pixels ( world -- alien w h )
+ [ (opaque-pixels) ] [ dim>> first2 ] bi ;
+
M: windows-ui-backend raise-window* ( world -- )
handle>> [
hWnd>> SetFocus drop
M: windows-ui-backend set-title ( string world -- )
handle>>
dup title>> [ free ] when*
- >r utf16n malloc-string r>
+ [ utf16n malloc-string ] dip
2dup (>>title)
hWnd>> WM_SETTEXT 0 roll alien-address SendMessage drop ;
assocs kernel math namespaces opengl sequences strings x11.xlib
x11.events x11.xim x11.glx x11.clipboard x11.constants
x11.windows io.encodings.string io.encodings.ascii
-io.encodings.utf8 combinators debugger command-line qualified
+io.encodings.utf8 combinators command-line qualified
math.vectors classes.tuple opengl.gl threads math.geometry.rect
-environment ;
+environment ascii ;
IN: ui.x11
SINGLETON: x11-ui-backend
: XA_NET_WM_NAME ( -- atom ) "_NET_WM_NAME" x-atom ;
-TUPLE: x11-handle window glx xic ;
+TUPLE: x11-handle-base glx ;
+TUPLE: x11-handle < x11-handle-base xic window ;
+TUPLE: x11-pixmap-handle < x11-handle-base pixmap glx-pixmap ;
C: <x11-handle> x11-handle
+C: <x11-pixmap-handle> x11-pixmap-handle
M: world expose-event nip relayout ;
: event-modifiers ( event -- seq )
XKeyEvent-state modifiers modifier ;
+: valid-input? ( string gesture -- ? )
+ over empty? [ 2drop f ] [
+ mods>> { f { S+ } } member? [
+ [ [ 127 = not ] [ CHAR: \s >= ] bi and ] all?
+ ] [
+ [ [ 127 = not ] [ CHAR: \s >= ] [ alpha? not ] tri and and ] all?
+ ] if
+ ] if ;
+
: key-down-event>gesture ( event world -- string gesture )
dupd
handle>> xic>> lookup-string
- >r swap event-modifiers r> key-code <key-down> ;
+ [ swap event-modifiers ] dip key-code <key-down> ;
M: world key-down-event
- [ key-down-event>gesture ] keep world-focus
- [ send-gesture ] keep swap [ user-input ] [ 2drop ] if ;
+ [ key-down-event>gesture ] keep
+ [ propagate-key-gesture drop ]
+ [ 2over valid-input? [ nip user-input ] [ 3drop ] if ]
+ 3bi ;
: key-up-event>gesture ( event -- gesture )
dup event-modifiers swap 0 XLookupKeysym key-code <key-up> ;
M: world key-up-event
- >r key-up-event>gesture r> world-focus send-gesture drop ;
+ [ key-up-event>gesture ] dip propagate-key-gesture ;
: mouse-event>gesture ( event -- modifiers button loc )
- dup event-modifiers over XButtonEvent-button
- rot mouse-event-loc ;
+ [ event-modifiers ]
+ [ XButtonEvent-button ]
+ [ mouse-event-loc ]
+ tri ;
M: world button-down-event
- >r mouse-event>gesture >r <button-down> r> r>
+ [ mouse-event>gesture [ <button-down> ] dip ] dip
send-button-down ;
M: world button-up-event
- >r mouse-event>gesture >r <button-up> r> r>
+ [ mouse-event>gesture [ <button-up> ] dip ] dip
send-button-up ;
: mouse-event>scroll-direction ( event -- pair )
} at ;
M: world wheel-event
- >r dup mouse-event>scroll-direction swap mouse-event-loc r>
+ [ [ mouse-event>scroll-direction ] [ mouse-event-loc ] bi ] dip
send-wheel ;
M: world enter-event motion-event ;
M: world leave-event 2drop forget-rollover ;
M: world motion-event
- >r dup XMotionEvent-x swap XMotionEvent-y 2array r>
+ [ [ XMotionEvent-x ] [ XMotionEvent-y ] bi 2array ] dip
move-hand fire-motion ;
M: world focus-in-event
M: world selection-notify-event
[ handle>> window>> selection-from-event ] keep
- world-focus user-input ;
+ user-input ;
: supported-type? ( atom -- ? )
{ "UTF8_STRING" "STRING" "TEXT" }
: clipboard-for-atom ( atom -- clipboard )
{
- { [ dup XA_PRIMARY = ] [ drop selection get ] }
- { [ dup XA_CLIPBOARD = ] [ drop clipboard get ] }
+ { XA_PRIMARY [ selection get ] }
+ { XA_CLIPBOARD [ clipboard get ] }
[ drop <clipboard> ]
- } cond ;
+ } case ;
: encode-clipboard ( string type -- bytes )
XSelectionRequestEvent-target
[ XSelectionRequestEvent-requestor ] keep
[ XSelectionRequestEvent-property ] keep
[ XSelectionRequestEvent-target ] keep
- >r 8 PropModeReplace r>
+ [ 8 PropModeReplace ] dip
[
XSelectionRequestEvent-selection
clipboard-for-atom contents>>
: gadget-window ( world -- )
dup window-loc>> over rect-dim glx-window
- over "Factor" create-xic <x11-handle>
+ over "Factor" create-xic rot <x11-handle>
2dup window>> register-window
>>handle drop ;
M: x11-ui-backend do-events
wait-event dup XAnyEvent-window window dup
- [ [ 2dup handle-event ] assert-depth ] when 2drop ;
+ [ handle-event ] [ 2drop ] if ;
: x-clipboard@ ( gadget clipboard -- prop win )
atom>> swap
(>>contents) ;
M: x-clipboard paste-clipboard
- >r find-world handle>> window>>
- r> atom>> convert-selection ;
+ [ find-world handle>> window>> ] dip atom>> convert-selection ;
: init-clipboard ( -- )
XA_PRIMARY <x-clipboard> selection set-global
dup [ 127 <= ] all? [ XStoreName drop ] [ 3drop ] if ;
: set-title-new ( dpy window string -- )
- >r
- XA_NET_WM_NAME XA_UTF8_STRING 8 PropModeReplace
- r> utf8 encode dup length XChangeProperty drop ;
+ [ XA_NET_WM_NAME XA_UTF8_STRING 8 PropModeReplace ] dip
+ utf8 encode dup length XChangeProperty drop ;
M: x11-ui-backend set-title ( string world -- )
- handle>> window>> swap dpy get -rot
- 3dup set-title-old set-title-new ;
-
+ handle>> window>> swap
+ [ dpy get ] 2dip [ set-title-old ] [ set-title-new ] 3bi ;
+
M: x11-ui-backend set-fullscreen* ( ? world -- )
handle>> window>> "XClientMessageEvent" <c-object>
tuck set-XClientMessageEvent-window
"_NET_WM_STATE" x-atom over set-XClientMessageEvent-message_type
32 over set-XClientMessageEvent-format
"_NET_WM_STATE_FULLSCREEN" x-atom over set-XClientMessageEvent-data1
- >r dpy get root get 0 SubstructureNotifyMask r> XSendEvent drop ;
-
+ [ dpy get root get 0 SubstructureNotifyMask ] dip XSendEvent drop ;
M: x11-ui-backend (open-window) ( world -- )
dup gadget-window
dpy get swap window>> XRaiseWindow drop
] when* ;
-M: x11-ui-backend select-gl-context ( handle -- )
+M: x11-handle select-gl-context ( handle -- )
dpy get swap
- dup window>> swap glx>> glXMakeCurrent
+ [ window>> ] [ glx>> ] bi glXMakeCurrent
[ "Failed to set current GLX context" throw ] unless ;
-M: x11-ui-backend flush-gl-context ( handle -- )
+M: x11-handle flush-gl-context ( handle -- )
dpy get swap window>> glXSwapBuffers ;
+M: x11-pixmap-handle select-gl-context ( handle -- )
+ dpy get swap
+ [ glx-pixmap>> ] [ glx>> ] bi glXMakeCurrent
+ [ "Failed to set current GLX context" throw ] unless ;
+
+M: x11-pixmap-handle flush-gl-context ( handle -- )
+ drop ;
+
+M: x11-ui-backend (open-offscreen-buffer) ( world -- )
+ dup dim>> glx-pixmap <x11-pixmap-handle> >>handle drop ;
+M: x11-ui-backend (close-offscreen-buffer) ( handle -- )
+ dpy get swap
+ [ glx-pixmap>> glXDestroyGLXPixmap ]
+ [ pixmap>> XFreePixmap drop ]
+ [ glx>> glXDestroyContext ] 2tri ;
+
+M: x11-ui-backend offscreen-pixels ( world -- alien w h )
+ [ [ dim>> ] [ handle>> pixmap>> ] bi pixmap-bits ] [ dim>> first2 ] bi ;
+
M: x11-ui-backend ui ( -- )
[
f [
grapheme-table nth nth not ;
: chars ( i str n -- str[i] str[i+n] )
- swap >r dupd + r> [ ?nth ] curry bi@ ;
+ swap [ dupd + ] dip [ ?nth ] curry bi@ ;
: find-index ( seq quot -- i ) find drop ; inline
: find-last-index ( seq quot -- i ) find-last drop ; inline
"lt" locale set
! Lithuanian casing tests
] with-scope
+
+[ t ] [ "asdf" lower? ] unit-test
+[ f ] [ "asdF" lower? ] unit-test
+
+[ t ] [ "ASDF" upper? ] unit-test
+[ f ] [ "ASDf" upper? ] unit-test
assocs strings splitting kernel accessors ;
IN: unicode.case
-: at-default ( key assoc -- value/key ) over >r at r> or ;
+: at-default ( key assoc -- value/key ) [ at ] [ drop ] 2bi or ;
: ch>lower ( ch -- lower ) simple-lower at-default ;
: ch>upper ( ch -- upper ) simple-upper at-default ;
: >case-fold ( string -- fold )
>upper >lower ;
-: lower? ( string -- ? )
- dup >lower = ;
-: upper? ( string -- ? )
- dup >lower = ;
-: title? ( string -- ? )
- dup >title = ;
-: case-fold? ( string -- ? )
- dup >case-fold = ;
+: lower? ( string -- ? ) dup >lower = ;
+
+: upper? ( string -- ? ) dup >upper = ;
+
+: title? ( string -- ? ) dup >title = ;
+
+: case-fold? ( string -- ? ) dup >case-fold = ;
[ zero? ] tri@ and and ;\r
\r
: filter-ignorable ( weights -- weights' )\r
- >r f r> [\r
+ f swap [\r
tuck primary>> zero? and\r
[ swap ignorable?>> or ]\r
[ swap completely-ignorable? or not ] 2bi\r
: (process-data) ( index data -- newdata )
filter-comments
[ [ nth ] keep first swap ] with { } map>assoc
- [ >r hex> r> ] assoc-map ;
+ [ [ hex> ] dip ] assoc-map ;
: process-data ( index data -- hash )
(process-data) [ hex> ] assoc-map [ nip ] assoc-filter >hashtable ;
: hangul>jamo ( hangul -- jamo-string )
hangul-base - final-count /mod final-base +
- >r medial-count /mod medial-base +
- >r initial-base + r> r>
+ [
+ medial-count /mod medial-base +
+ [ initial-base + ] dip
+ ] dip
dup final-base = [ drop 2array ] [ 3array ] if ;
: jamo>hangul ( initial medial final -- hangul )
- >r >r initial-base - medial-count *
- r> medial-base - + final-count *
- r> final-base - + hangul-base + ;
+ [
+ [ initial-base - medial-count * ] dip
+ medial-base - + final-count *
+ ] dip final-base - + hangul-base + ;
! Normalization -- Decomposition
: reorder-next ( string i -- new-i done? )
over [ non-starter? ] find-from drop [
reorder-slice
- >r dup [ combining-class ] insertion-sort to>> r>
+ [ dup [ combining-class ] insertion-sort to>> ] dip
] [ length t ] if* ;
: reorder-loop ( string start -- )
! See http://factorcode.org/license.txt for BSD license.
USING: unicode.data kernel math sequences parser lexer
bit-arrays namespaces make sequences.private arrays quotations
-assocs classes.predicate math.order eval ;
+assocs classes.predicate math.order strings.parser ;
IN: unicode.syntax
! Character classes (categories)
categories [ swap member? ] with map >bit-array ;
: as-string ( strings -- bit-array )
- concat "\"" tuck 3append eval ;
+ concat unescape-string ;
: [category] ( categories -- quot )
[
: SEEK_CUR 1 ; inline
: SEEK_END 2 ; inline
-: DT_UNKNOWN 0 ; inline
-: DT_FIFO 1 ; inline
-: DT_CHR 2 ; inline
-: DT_DIR 4 ; inline
-: DT_BLK 6 ; inline
-: DT_REG 8 ; inline
-: DT_LNK 10 ; inline
-: DT_SOCK 12 ; inline
-: DT_WHT 14 ; inline
-
os {
{ macosx [ "unix.bsd.macosx" require ] }
{ freebsd [ "unix.bsd.freebsd" require ] }
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: debugger prettyprint accessors unix io kernel ;
+IN: unix.debugger
+
+M: unix-error error.
+ "Unix system call failed:" print
+ nl
+ dup message>> write " (" write errno>> pprint ")" print ;
+
+M: unix-system-call-error error.
+ "Unix system call ``" write dup word>> pprint "'' failed:" print
+ nl
+ dup message>> write " (" write dup errno>> pprint ")" print
+ nl
+ "It was called with the following arguments:" print
+ nl
+ args>> stack. ;
--- /dev/null
+unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax ;
+IN: unix.getfsstat.freebsd
+
+: MNT_WAIT 1 ; inline ! synchronously wait for I/O to complete
+: MNT_NOWAIT 2 ; inline ! start all I/O, but do not wait for it
+: MNT_LAZY 3 ; inline ! push data not written by filesystem syncer
+: MNT_SUSPEND 4 ; inline ! Suspend file system after sync
+
+FUNCTION: int getfsstat ( statfs* buf, int bufsize, int flags ) ;
--- /dev/null
+unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax ;
+IN: unix.getfsstat.macosx
+
+: MNT_WAIT 1 ; inline ! synchronously wait for I/O to complete
+: MNT_NOWAIT 2 ; inline ! start all I/O, but do not wait for it
+
+FUNCTION: int getfsstat64 ( statfs* buf, int bufsize, int flags ) ;
--- /dev/null
+unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax ;
+IN: unix.getfsstat.netbsd
+
+: MNT_WAIT 1 ; inline ! synchronously wait for I/O to complete
+: MNT_NOWAIT 2 ; inline ! start all I/O, but do not wait for it
+: MNT_LAZY 3 ; inline ! push data not written by filesystem syncer
+
+FUNCTION: int getvfsstat ( statfs* buf, int bufsize, int flags ) ;
--- /dev/null
+unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax ;
+IN: unix.getfsstat.openbsd
+
+: MNT_WAIT 1 ; ! synchronously wait for I/O to complete
+: MNT_NOWAIT 2 ; ! start all I/O, but do not wait for it
+: MNT_LAZY 3 ; ! push data not written by filesystem syncer
+
+FUNCTION: int getfsstat ( statfs* buf, int bufsize, int flags ) ;
--- /dev/null
+unportable
: all-groups ( -- seq )
[ getgrent dup ] [ group-struct>group ] [ drop ] produce ;
+: <group-cache> ( -- assoc )
+ all-groups [ [ id>> ] keep ] H{ } map>assoc ;
+
: with-group-cache ( quot -- )
- all-groups [ [ id>> ] keep ] H{ } map>assoc
- group-cache rot with-variable ; inline
+ [ <group-cache> group-cache ] dip with-variable ; inline
: real-group-id ( -- id )
getgid ; inline
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.syntax system sequences vocabs.loader words ;
+USING: alien.syntax system sequences vocabs.loader words
+accessors ;
IN: unix.kqueue
<< "unix.kqueue." os name>> append require >>
: EPOLL_CTL_DEL 2 ; inline ! Remove a file decriptor from the interface.
: EPOLL_CTL_MOD 3 ; inline ! Change file decriptor epoll_event structure.
-: EPOLLIN HEX: 001 ; inline
-: EPOLLPRI HEX: 002 ; inline
-: EPOLLOUT HEX: 004 ; inline
-: EPOLLRDNORM HEX: 040 ; inline
-: EPOLLRDBAND HEX: 080 ; inline
-: EPOLLWRNORM HEX: 100 ; inline
-: EPOLLWRBAND HEX: 200 ; inline
-: EPOLLMSG HEX: 400 ; inline
-: EPOLLERR HEX: 008 ; inline
-: EPOLLHUP HEX: 010 ; inline
-: EPOLLET 31 2^ ; inline
+: EPOLLIN HEX: 001 ; inline
+: EPOLLPRI HEX: 002 ; inline
+: EPOLLOUT HEX: 004 ; inline
+: EPOLLRDNORM HEX: 040 ; inline
+: EPOLLRDBAND HEX: 080 ; inline
+: EPOLLWRNORM HEX: 100 ; inline
+: EPOLLWRBAND HEX: 200 ; inline
+: EPOLLMSG HEX: 400 ; inline
+: EPOLLERR HEX: 008 ; inline
+: EPOLLHUP HEX: 010 ; inline
+: EPOLLONESHOT 30 2^ ; inline
+: EPOLLET 31 2^ ; inline
[ first ] [ ] bi exec-with-path ;
: exec-args-with-env ( seq seq -- int )
- >r [ first ] [ ] bi r> exec-with-env ;
+ [ [ first ] [ ] bi ] dip exec-with-env ;
: with-fork ( child parent -- )
[ [ fork-process dup zero? ] dip [ drop ] prepose ] dip
HEX: 7f bitand ; inline
: WIFEXITED ( status -- ? )
- WTERMSIG zero? ; inline
+ WTERMSIG 0 = ; inline
: WEXITSTATUS ( status -- value )
HEX: ff00 bitand -8 shift ; inline
HEX: 80 ; inline
: WCOREDUMP ( status -- ? )
- WCOREFLAG bitand zero? not ; inline
+ WCOREFLAG bitand 0 = not ; inline
: WIFSTOPPED ( status -- ? )
HEX: ff bitand HEX: 7f = ; inline
: S_IFIFO OCT: 010000 ; inline ! FIFO.
: S_IFLNK OCT: 120000 ; inline ! Symbolic link.
: S_IFSOCK OCT: 140000 ; inline ! Socket.
+: S_IFWHT OCT: 160000 ; inline ! Whiteout.
FUNCTION: int chmod ( char* path, mode_t mode ) ;
FUNCTION: int fchmod ( int fd, mode_t mode ) ;
+++ /dev/null
-Doug Coleman
\ No newline at end of file
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.syntax kernel unix math accessors
-combinators system io.backend alien.c-types unix.statfs
-io.files ;
+USING: alien.syntax ;
IN: unix.statfs.freebsd
-: ST_RDONLY 1 ; inline
-: ST_NOSUID 2 ; inline
+: MFSNAMELEN 16 ; inline ! length of type name including null */
+: MNAMELEN 88 ; inline ! size of on/from name bufs
+: STATFS_VERSION HEX: 20030518 ; inline ! current version number
-C-STRUCT: statvfs
- { "fsblkcnt_t" "f_bavail" }
- { "fsblkcnt_t" "f_bfree" }
- { "fsblkcnt_t" "f_blocks" }
- { "fsfilcnt_t" "f_favail" }
- { "fsfilcnt_t" "f_ffree" }
- { "fsfilcnt_t" "f_files" }
- { "ulong" "f_bsize" }
- { "ulong" "f_flag" }
- { "ulong" "f_frsize" }
- { "ulong" "f_fsid" }
- { "ulong" "f_namemax" } ;
+C-STRUCT: statfs
+ { "uint32_t" "f_version" }
+ { "uint32_t" "f_type" }
+ { "uint64_t" "f_flags" }
+ { "uint64_t" "f_bsize" }
+ { "uint64_t" "f_iosize" }
+ { "uint64_t" "f_blocks" }
+ { "uint64_t" "f_bfree" }
+ { "int64_t" "f_bavail" }
+ { "uint64_t" "f_files" }
+ { "int64_t" "f_ffree" }
+ { "uint64_t" "f_syncwrites" }
+ { "uint64_t" "f_asyncwrites" }
+ { "uint64_t" "f_syncreads" }
+ { "uint64_t" "f_asyncreads" }
+ { { "uint64_t" 10 } "f_spare" }
+ { "uint32_t" "f_namemax" }
+ { "uid_t" "f_owner" }
+ { "fsid_t" "f_fsid" }
+ { { "char" 80 } "f_charspare" }
+ { { "char" MFSNAMELEN } "f_fstypename" }
+ { { "char" MNAMELEN } "f_mntfromname" }
+ { { "char" MNAMELEN } "f_mntonname" } ;
-FUNCTION: int statvfs ( char* path, statvfs* buf ) ;
-
-TUPLE: freebsd-file-system-info < file-system-info
-bavail bfree blocks favail ffree files
-bsize flag frsize fsid namemax ;
-
-M: freebsd >file-system-info ( struct -- statfs )
- [ \ freebsd-file-system-info new ] dip
- {
- [
- [ statvfs-f_bsize ]
- [ statvfs-f_bavail ] bi * >>free-space
- ]
- [ statvfs-f_bavail >>bavail ]
- [ statvfs-f_bfree >>bfree ]
- [ statvfs-f_blocks >>blocks ]
- [ statvfs-f_favail >>favail ]
- [ statvfs-f_ffree >>ffree ]
- [ statvfs-f_files >>files ]
- [ statvfs-f_bsize >>bsize ]
- [ statvfs-f_flag >>flag ]
- [ statvfs-f_frsize >>frsize ]
- [ statvfs-f_fsid >>fsid ]
- [ statvfs-f_namemax >>namemax ]
- } cleave ;
-
-M: freebsd file-system-info ( path -- byte-array )
- normalize-path
- "statvfs" <c-object> tuck statvfs io-error
- >file-system-info ;
+FUNCTION: int statfs ( char* path, statvfs* buf ) ;
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: alien.c-types combinators kernel unix.stat
-math accessors system unix io.backend layouts vocabs.loader
-alien.syntax unix.statfs io.files ;
-IN: unix.statfs.linux
-
-C-STRUCT: statfs
- { "long" "f_type" }
- { "long" "f_bsize" }
- { "long" "f_blocks" }
- { "long" "f_bfree" }
- { "long" "f_bavail" }
- { "long" "f_files" }
- { "long" "f_ffree" }
- { "fsid_t" "f_fsid" }
- { "long" "f_namelen" } ;
-
-FUNCTION: int statfs ( char* path, statfs* buf ) ;
-
-TUPLE: linux32-file-system-info < file-system-info
-bsize blocks bfree bavail files ffree fsid namelen
-frsize spare ;
-
-M: linux >file-system-info ( struct -- statfs )
- [ \ linux32-file-system-info new ] dip
- {
- [
- [ statfs-f_bsize ]
- [ statfs-f_bavail ] bi * >>free-space
- ]
- [ statfs-f_type >>type ]
- [ statfs-f_bsize >>bsize ]
- [ statfs-f_blocks >>blocks ]
- [ statfs-f_bfree >>bfree ]
- [ statfs-f_bavail >>bavail ]
- [ statfs-f_files >>files ]
- [ statfs-f_ffree >>ffree ]
- [ statfs-f_fsid >>fsid ]
- [ statfs-f_namelen >>namelen ]
- } cleave ;
-
-M: linux file-system-info ( path -- byte-array )
- normalize-path
- "statfs" <c-object> tuck statfs io-error
- >file-system-info ;
+++ /dev/null
-Doug Coleman
\ No newline at end of file
+++ /dev/null
-unportable
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: alien.c-types combinators kernel unix.stat
-math accessors system unix io.backend layouts vocabs.loader
-alien.syntax unix.statfs io.files ;
-IN: unix.statfs.linux
-
-C-STRUCT: statfs64
- { "__SWORD_TYPE" "f_type" }
- { "__SWORD_TYPE" "f_bsize" }
- { "__fsblkcnt64_t" "f_blocks" }
- { "__fsblkcnt64_t" "f_bfree" }
- { "__fsblkcnt64_t" "f_bavail" }
- { "__fsfilcnt64_t" "f_files" }
- { "__fsfilcnt64_t" "f_ffree" }
- { "__fsid_t" "f_fsid" }
- { "__SWORD_TYPE" "f_namelen" }
- { "__SWORD_TYPE" "f_frsize" }
- { { "__SWORD_TYPE" 5 } "f_spare" } ;
-
-FUNCTION: int statfs64 ( char* path, statfs64* buf ) ;
-
-TUPLE: linux64-file-system-info < file-system-info
-bsize blocks bfree bavail files ffree fsid namelen
-frsize spare ;
-
-M: linux >file-system-info ( struct -- statfs )
- [ \ linux64-file-system-info new ] dip
- {
- [
- [ statfs64-f_bsize ]
- [ statfs64-f_bavail ] bi * >>free-space
- ]
- [ statfs64-f_type >>type ]
- [ statfs64-f_bsize >>bsize ]
- [ statfs64-f_blocks >>blocks ]
- [ statfs64-f_bfree >>bfree ]
- [ statfs64-f_bavail >>bavail ]
- [ statfs64-f_files >>files ]
- [ statfs64-f_ffree >>ffree ]
- [ statfs64-f_fsid >>fsid ]
- [ statfs64-f_namelen >>namelen ]
- [ statfs64-f_frsize >>frsize ]
- [ statfs64-f_spare >>spare ]
- } cleave ;
-
-M: linux file-system-info ( path -- byte-array )
- normalize-path
- "statfs64" <c-object> tuck statfs64 io-error
- >file-system-info ;
+++ /dev/null
-Doug Coleman
\ No newline at end of file
+++ /dev/null
-unportable
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.c-types combinators kernel unix.stat
-math accessors system unix io.backend layouts vocabs.loader
-sequences csv io.streams.string io.encodings.utf8 namespaces
-unix.statfs io.files ;
+USING: alien.syntax ;
IN: unix.statfs.linux
-cell-bits {
- { 32 [ "unix.statfs.linux.32" require ] }
- { 64 [ "unix.statfs.linux.64" require ] }
-} case
+C-STRUCT: statfs64
+ { "__SWORD_TYPE" "f_type" }
+ { "__SWORD_TYPE" "f_bsize" }
+ { "__fsblkcnt64_t" "f_blocks" }
+ { "__fsblkcnt64_t" "f_bfree" }
+ { "__fsblkcnt64_t" "f_bavail" }
+ { "__fsfilcnt64_t" "f_files" }
+ { "__fsfilcnt64_t" "f_ffree" }
+ { "__fsid_t" "f_fsid" }
+ { "__SWORD_TYPE" "f_namelen" }
+ { "__SWORD_TYPE" "f_frsize" }
+ { { "__SWORD_TYPE" 5 } "f_spare" } ;
-TUPLE: mtab-entry file-system-name mount-point type options
-frequency pass-number ;
-
-: mtab-csv>mtab-entry ( csv -- mtab-entry )
- [ mtab-entry new ] dip
- {
- [ first >>file-system-name ]
- [ second >>mount-point ]
- [ third >>type ]
- [ fourth <string-reader> csv first >>options ]
- [ 4 swap nth >>frequency ]
- [ 5 swap nth >>pass-number ]
- } cleave ;
-
-: parse-mtab ( -- array )
- [
- "/etc/mtab" utf8 <file-reader>
- CHAR: \s delimiter set csv
- ] with-scope
- [ mtab-csv>mtab-entry ] map ;
-
-M: linux file-systems
- parse-mtab [
- [ mount-point>> file-system-info ] keep
- {
- [ file-system-name>> >>device-name ]
- [ mount-point>> >>mount-point ]
- [ type>> >>type ]
- } cleave
- ] map ;
+FUNCTION: int statfs64 ( char* path, statfs64* buf ) ;
! See http://factorcode.org/license.txt for BSD license.
USING: alien.c-types io.encodings.utf8 io.encodings.string
kernel sequences unix.stat accessors unix combinators math
-grouping system unix.statfs io.files io.backend alien.strings
-math.bitwise alien.syntax ;
+grouping system alien.strings math.bitwise alien.syntax ;
IN: unix.statfs.macosx
: MNT_RDONLY HEX: 00000001 ; inline
FUNCTION: int statfs64 ( char* path, statfs64* buf ) ;
FUNCTION: int getmntinfo64 ( statfs64** mntbufp, int flags ) ;
-
-
-TUPLE: macosx-file-system-info < file-system-info
-block-size io-size blocks blocks-free blocks-available files
-files-free file-system-id owner type-id flags filesystem-subtype ;
-
-M: macosx file-systems ( -- array )
- f <void*> dup 0 getmntinfo64 dup io-error
- [ *void* ] dip
- "statfs64" heap-size [ * memory>byte-array ] keep group
- [ >file-system-info ] map ;
-
-M: macosx >file-system-info ( byte-array -- file-system-info )
- [ \ macosx-file-system-info new ] dip
- {
- [
- [ statfs64-f_bavail ] [ statfs64-f_bsize ] bi *
- >>free-space
- ]
- [ statfs64-f_mntonname utf8 alien>string >>mount-point ]
- [ statfs64-f_bsize >>block-size ]
-
- [ statfs64-f_iosize >>io-size ]
- [ statfs64-f_blocks >>blocks ]
- [ statfs64-f_bfree >>blocks-free ]
- [ statfs64-f_bavail >>blocks-available ]
- [ statfs64-f_files >>files ]
- [ statfs64-f_ffree >>files-free ]
- [ statfs64-f_fsid >>file-system-id ]
- [ statfs64-f_owner >>owner ]
- [ statfs64-f_type >>type-id ]
- [ statfs64-f_flags >>flags ]
- [ statfs64-f_fssubtype >>filesystem-subtype ]
- [
- statfs64-f_fstypename utf8 alien>string
- >>type
- ]
- [
- statfs64-f_mntfromname
- utf8 alien>string >>device-name
- ]
- } cleave ;
-
-M: macosx file-system-info ( path -- file-system-info )
- normalize-path
- "statfs64" <c-object> tuck statfs64 io-error
- >file-system-info ;
+++ /dev/null
-Doug Coleman
\ No newline at end of file
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: alien.syntax kernel unix.stat math unix
-combinators system io.backend accessors alien.c-types
-io.encodings.utf8 alien.strings unix.types unix.statfs io.files ;
-IN: unix.statfs.netbsd
-
-: _VFS_NAMELEN 32 ; inline
-: _VFS_MNAMELEN 1024 ; inline
-
-C-STRUCT: statvfs
- { "ulong" "f_flag" }
- { "ulong" "f_bsize" }
- { "ulong" "f_frsize" }
- { "ulong" "f_iosize" }
- { "fsblkcnt_t" "f_blocks" }
- { "fsblkcnt_t" "f_bfree" }
- { "fsblkcnt_t" "f_bavail" }
- { "fsblkcnt_t" "f_bresvd" }
- { "fsfilcnt_t" "f_files" }
- { "fsfilcnt_t" "f_ffree" }
- { "fsfilcnt_t" "f_favail" }
- { "fsfilcnt_t" "f_fresvd" }
- { "uint64_t" "f_syncreads" }
- { "uint64_t" "f_syncwrites" }
- { "uint64_t" "f_asyncreads" }
- { "uint64_t" "f_asyncwrites" }
- { "fsid_t" "f_fsidx" }
- { "ulong" "f_fsid" }
- { "ulong" "f_namemax" }
- { "uid_t" "f_owner" }
- { { "uint32_t" 4 } "f_spare" }
- { { "char" _VFS_NAMELEN } "f_fstypename" }
- { { "char" _VFS_NAMELEN } "f_mntonname" }
- { { "char" _VFS_NAMELEN } "f_mntfromname" } ;
-
-FUNCTION: int statvfs ( char* path, statvfs *buf ) ;
-
-TUPLE: netbsd-file-system-info < file-system-info
-flag bsize frsize io-size
-blocks blocks-free blocks-available blocks-reserved
-files ffree sync-reads sync-writes async-reads async-writes
-fsidx fsid namemax owner spare fstype mnotonname mntfromname
-file-system-type-name mount-from ;
-
-M: netbsd >file-system-info ( byte-array -- netbsd-file-system-info )
- [ \ netbsd-file-system-info new ] dip
- {
- [
- [ statvfs-f_bsize ]
- [ statvfs-f_bavail ] bi * >>free-space
- ]
- [ statvfs-f_flag >>flag ]
- [ statvfs-f_bsize >>bsize ]
- [ statvfs-f_frsize >>frsize ]
- [ statvfs-f_iosize >>io-size ]
- [ statvfs-f_blocks >>blocks ]
- [ statvfs-f_bfree >>blocks-free ]
- [ statvfs-f_favail >>blocks-available ]
- [ statvfs-f_fresvd >>blocks-reserved ]
- [ statvfs-f_files >>files ]
- [ statvfs-f_ffree >>ffree ]
- [ statvfs-f_syncreads >>sync-reads ]
- [ statvfs-f_syncwrites >>sync-writes ]
- [ statvfs-f_asyncreads >>async-reads ]
- [ statvfs-f_asyncwrites >>async-writes ]
- [ statvfs-f_fsidx >>fsidx ]
- [ statvfs-f_namemax >>namemax ]
- [ statvfs-f_owner >>owner ]
- [ statvfs-f_spare >>spare ]
- [ statvfs-f_fstypename utf8 alien>string >>file-system-type-name ]
- [ statvfs-f_mntonname utf8 alien>string >>mount-point ]
- [ statvfs-f_mntfromname utf8 alien>string >>mount-from ]
- } cleave ;
-
-M: netbsd file-system-info
- normalize-path "statvfs" <c-object> tuck statvfs io-error
- >file-system-info ;
+++ /dev/null
-unportable
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: alien.syntax kernel unix ;
-IN: unix.statfs.openbsd.32
-
-: MFSNAMELEN 16 ; inline
-: MNAMELEN 90 ; inline
-
-C-STRUCT: statfs
- { "u_int32_t" "f_flags" }
- { "int32_t" "f_bsize" }
- { "u_int32_t" "f_iosize" }
- { "u_int32_t" "f_blocks" }
- { "u_int32_t" "f_bfree" }
- { "int32_t" "f_bavail" }
- { "u_int32_t" "f_files" }
- { "u_int32_t" "f_ffree" }
- { "fsid_t" "f_fsid" }
- { "uid_t" "f_owner" }
- { "u_int32_t" "f_syncwrites" }
- { "u_int32_t" "f_asyncwrites" }
- { "u_int32_t" "f_ctime" }
- { { "u_int32_t" 3 } "f_spare" }
- { { "char" MFSNAMELEN } "f_fstypename" }
- { { "char" MNAMELEN } "f_mntonname" }
- { { "char" MNAMELEN } "f_mntfromname" } ;
+++ /dev/null
-Doug Coleman
\ No newline at end of file
+++ /dev/null
-unportable
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: alien.syntax unix ;
-IN: unix.statfs.openbsd.64
-
-: MFSNAMELEN 16 ; inline
-: MNAMELEN 90 ; inline
-
-C-STRUCT: statfss
- { "u_int32_t" "f_flags" }
- { "u_int32_t" "f_bsize" }
- { "u_int32_t" "f_iosize" }
- { "u_int64_t" "f_blocks" }
- { "u_int64_t" "f_bfree" }
- { "int64_t" "f_bavail" }
- { "u_int64_t" "f_files" }
- { "u_int64_t" "f_ffree" }
- { "int64_t" "f_favail" }
- { "u_int64_t" "f_syncwrites" }
- { "u_int64_t" "f_syncreads" }
- { "u_int64_t" "f_asyncwrites" }
- { "u_int64_t" "f_asyncreads" }
- { "fsid_t" "f_fsid" }
- { "u_int32_t" "f_namemax" }
- { "uid_t" "f_owner" }
- { "u_int32_t" "f_ctime" }
- { { "u_int32_t" 3 } " f_spare" }
- { { "char" MFSNAMELEN } "f_fstypename" }
- { { "char" MNAMELEN } "f_mntonname" }
- { { "char" MNAMELEN } "f_mntfromname" }
- { { "char" 512 } "mount_info" } ;
- ! { "mount_info" "mount_info" } ;
+++ /dev/null
-Doug Coleman
\ No newline at end of file
+++ /dev/null
-unportable
+++ /dev/null
-Doug Coleman
\ No newline at end of file
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien.syntax accessors combinators kernel
-unix.types math system io.backend alien.c-types unix
-unix.statfs io.files ;
+USING: alien.syntax ;
IN: unix.statfs.openbsd
-C-STRUCT: statvfs
- { "ulong" "f_bsize" }
- { "ulong" "f_frsize" }
- { "fsblkcnt_t" "f_blocks" }
- { "fsblkcnt_t" "f_bfree" }
- { "fsblkcnt_t" "f_bavail" }
- { "fsfilcnt_t" "f_files" }
- { "fsfilcnt_t" "f_ffree" }
- { "fsfilcnt_t" "f_favail" }
- { "ulong" "f_fsid" }
- { "ulong" "f_flag" }
- { "ulong" "f_namemax" } ;
+: MFSNAMELEN 16 ; inline
+: MNAMELEN 90 ; inline
-: ST_RDONLY 1 ; inline
-: ST_NOSUID 2 ; inline
+C-STRUCT: statfs
+ { "u_int32_t" "f_flags" }
+ { "u_int32_t" "f_bsize" }
+ { "u_int32_t" "f_iosize" }
+ { "u_int64_t" "f_blocks" }
+ { "u_int64_t" "f_bfree" }
+ { "int64_t" "f_bavail" }
+ { "u_int64_t" "f_files" }
+ { "u_int64_t" "f_ffree" }
+ { "int64_t" "f_favail" }
+ { "u_int64_t" "f_syncwrites" }
+ { "u_int64_t" "f_syncreads" }
+ { "u_int64_t" "f_asyncwrites" }
+ { "u_int64_t" "f_asyncreads" }
+ { "fsid_t" "f_fsid" }
+ { "u_int32_t" "f_namemax" }
+ { "uid_t" "f_owner" }
+ { "u_int32_t" "f_ctime" }
+ { { "u_int32_t" 3 } "f_spare" }
+ { { "char" MFSNAMELEN } "f_fstypename" }
+ { { "char" MNAMELEN } "f_mntonname" }
+ { { "char" MNAMELEN } "f_mntfromname" }
+ { { "char" 160 } "mount_info" } ;
-FUNCTION: int statvfs ( char* path, statvfs* buf ) ;
-
-TUPLE: openbsd-file-system-info < file-system-info
-bsize frsize blocks bfree bavail files ffree favail
-fsid flag namemax ;
-
-M: openbsd >file-system-info ( struct -- statfs )
- [ \ openbsd-file-system-info new ] dip
- {
- [
- [ statvfs-f_bsize ]
- [ statvfs-f_bavail ] bi * >>free-space
- ]
- [ statvfs-f_bsize >>bsize ]
- [ statvfs-f_frsize >>frsize ]
- [ statvfs-f_blocks >>blocks ]
- [ statvfs-f_bfree >>bfree ]
- [ statvfs-f_bavail >>bavail ]
- [ statvfs-f_files >>files ]
- [ statvfs-f_ffree >>ffree ]
- [ statvfs-f_favail >>favail ]
- [ statvfs-f_fsid >>fsid ]
- [ statvfs-f_flag >>flag ]
- [ statvfs-f_namemax >>namemax ]
- } cleave ;
-
-M: openbsd file-system-info ( path -- byte-array )
- normalize-path
- "statvfs" <c-object> tuck statvfs io-error
- >file-system-info ;
+FUNCTION: int statfs ( char* path, statvfs* buf ) ;
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test unix.statfs ;
-IN: unix.statfs.tests
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: sequences system vocabs.loader combinators accessors
-kernel math.order sorting ;
-IN: unix.statfs
-
-HOOK: >file-system-info os ( struct -- statfs )
-
-os {
- { linux [ "unix.statfs.linux" require ] }
- { macosx [ "unix.statfs.macosx" require ] }
- { freebsd [ "unix.statfs.freebsd" require ] }
- { netbsd [ "unix.statfs.netbsd" require ] }
- { openbsd [ "unix.statfs.openbsd" require ] }
-} case
+++ /dev/null
-unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax ;
+IN: unix.statvfs.freebsd
+
+C-STRUCT: statvfs
+ { "fsblkcnt_t" "f_bavail" }
+ { "fsblkcnt_t" "f_bfree" }
+ { "fsblkcnt_t" "f_blocks" }
+ { "fsfilcnt_t" "f_favail" }
+ { "fsfilcnt_t" "f_ffree" }
+ { "fsfilcnt_t" "f_files" }
+ { "ulong" "f_bsize" }
+ { "ulong" "f_flag" }
+ { "ulong" "f_frsize" }
+ { "ulong" "f_fsid" }
+ { "ulong" "f_namemax" } ;
+
+! Flags
+: ST_RDONLY HEX: 1 ; inline ! Read-only file system
+: ST_NOSUID HEX: 2 ; inline ! Does not honor setuid/setgid
+
+FUNCTION: int statvfs ( char* path, statvfs* buf ) ;
--- /dev/null
+unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax ;
+IN: unix.statvfs.linux
+
+C-STRUCT: statvfs64
+ { "ulong" "f_bsize" }
+ { "ulong" "f_frsize" }
+ { "__fsblkcnt64_t" "f_blocks" }
+ { "__fsblkcnt64_t" "f_bfree" }
+ { "__fsblkcnt64_t" "f_bavail" }
+ { "__fsfilcnt64_t" "f_files" }
+ { "__fsfilcnt64_t" "f_ffree" }
+ { "__fsfilcnt64_t" "f_favail" }
+ { "ulong" "f_fsid" }
+ { "ulong" "f_flag" }
+ { "ulong" "f_namemax" }
+ { { "int" 6 } "__f_spare" } ;
+
+FUNCTION: int statvfs64 ( char* path, statvfs64* buf ) ;
+
+: ST_RDONLY 1 ; inline ! Mount read-only.
+: ST_NOSUID 2 ; inline ! Ignore suid and sgid bits.
+: ST_NODEV 4 ; inline ! Disallow access to device special files.
+: ST_NOEXEC 8 ; inline ! Disallow program execution.
+: ST_SYNCHRONOUS 16 ; inline ! Writes are synced at once.
+: ST_MANDLOCK 64 ; inline ! Allow mandatory locks on an FS.
+: ST_WRITE 128 ; inline ! Write on file/directory/symlink.
+: ST_APPEND 256 ; inline ! Append-only file.
+: ST_IMMUTABLE 512 ; inline ! Immutable file.
+: ST_NOATIME 1024 ; inline ! Do not update access times.
--- /dev/null
+unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax ;
+IN: unix.statvfs.macosx
+
+C-STRUCT: statvfs
+ { "ulong" "f_bsize" }
+ { "ulong" "f_frsize" }
+ { "fsblkcnt_t" "f_blocks" }
+ { "fsblkcnt_t" "f_bfree" }
+ { "fsblkcnt_t" "f_bavail" }
+ { "fsfilcnt_t" "f_files" }
+ { "fsfilcnt_t" "f_ffree" }
+ { "fsfilcnt_t" "f_favail" }
+ { "ulong" "f_fsid" }
+ { "ulong" "f_flag" }
+ { "ulong" "f_namemax" } ;
+
+! Flags
+: ST_RDONLY HEX: 1 ; inline ! Read-only file system
+: ST_NOSUID HEX: 2 ; inline ! Does not honor setuid/setgid
+
+FUNCTION: int statvfs ( char* path, statvfs* buf ) ;
--- /dev/null
+unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax ;
+IN: unix.statvfs.netbsd
+
+: _VFS_NAMELEN 32 ; inline
+: _VFS_MNAMELEN 1024 ; inline
+
+C-STRUCT: statvfs
+ { "ulong" "f_flag" }
+ { "ulong" "f_bsize" }
+ { "ulong" "f_frsize" }
+ { "ulong" "f_iosize" }
+ { "fsblkcnt_t" "f_blocks" }
+ { "fsblkcnt_t" "f_bfree" }
+ { "fsblkcnt_t" "f_bavail" }
+ { "fsblkcnt_t" "f_bresvd" }
+ { "fsfilcnt_t" "f_files" }
+ { "fsfilcnt_t" "f_ffree" }
+ { "fsfilcnt_t" "f_favail" }
+ { "fsfilcnt_t" "f_fresvd" }
+ { "uint64_t" "f_syncreads" }
+ { "uint64_t" "f_syncwrites" }
+ { "uint64_t" "f_asyncreads" }
+ { "uint64_t" "f_asyncwrites" }
+ { "fsid_t" "f_fsidx" }
+ { "ulong" "f_fsid" }
+ { "ulong" "f_namemax" }
+ { "uid_t" "f_owner" }
+ { { "uint32_t" 4 } "f_spare" }
+ { { "char" _VFS_NAMELEN } "f_fstypename" }
+ { { "char" _VFS_MNAMELEN } "f_mntonname" }
+ { { "char" _VFS_MNAMELEN } "f_mntfromname" } ;
+
+FUNCTION: int statvfs ( char* path, statvfs* buf ) ;
--- /dev/null
+unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax ;
+IN: unix.statvfs.openbsd
+
+C-STRUCT: statvfs
+ { "ulong" "f_bsize" }
+ { "ulong" "f_frsize" }
+ { "fsblkcnt_t" "f_blocks" }
+ { "fsblkcnt_t" "f_bfree" }
+ { "fsblkcnt_t" "f_bavail" }
+ { "fsfilcnt_t" "f_files" }
+ { "fsfilcnt_t" "f_ffree" }
+ { "fsfilcnt_t" "f_favail" }
+ { "ulong" "f_fsid" }
+ { "ulong" "f_flag" }
+ { "ulong" "f_namemax" } ;
+
+: ST_RDONLY 1 ; inline
+: ST_NOSUID 2 ; inline
+
+FUNCTION: int statvfs ( char* path, statvfs* buf ) ;
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: combinators system vocabs.loader ;
+IN: unix.statvfs
+
+os {
+ { linux [ "unix.statvfs.linux" require ] }
+ { macosx [ "unix.statvfs.macosx" require ] }
+ { freebsd [ "unix.statvfs.freebsd" require ] }
+ { netbsd [ "unix.statvfs.netbsd" require ] }
+ { openbsd [ "unix.statvfs.openbsd" require ] }
+} case
--- /dev/null
+unportable
{ "time_t" "sec" }
{ "long" "nsec" } ;
-: make-timeval ( ms -- timeval )
- 1000 /mod 1000 *
+: make-timeval ( us -- timeval )
+ 1000000 /mod
"timeval" <c-object>
[ set-timeval-usec ] keep
[ set-timeval-sec ] keep ;
-: make-timespec ( ms -- timespec )
- 1000 /mod 1000000 *
+: make-timespec ( us -- timespec )
+ 1000000 /mod 1000 *
"timespec" <c-object>
[ set-timespec-nsec ] keep
[ set-timespec-sec ] keep ;
-! Copyright (C) 2005, 2007 Slava Pestov.
+! Copyright (C) 2005, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types alien.syntax kernel libc
sequences continuations byte-arrays strings math namespaces
system combinators vocabs.loader qualified accessors
stack-checker macros locals generalizations unix.types
-debugger io prettyprint ;
+io io.files vocabs vocabs.loader ;
IN: unix
: PROT_NONE 0 ; inline
: NGROUPS_MAX 16 ; inline
+: DT_UNKNOWN 0 ; inline
+: DT_FIFO 1 ; inline
+: DT_CHR 2 ; inline
+: DT_DIR 4 ; inline
+: DT_BLK 6 ; inline
+: DT_REG 8 ; inline
+: DT_LNK 10 ; inline
+: DT_SOCK 12 ; inline
+: DT_WHT 14 ; inline
+
+: dirent-type>file-type ( ch -- type )
+ {
+ { DT_BLK [ +block-device+ ] }
+ { DT_CHR [ +character-device+ ] }
+ { DT_DIR [ +directory+ ] }
+ { DT_LNK [ +symbolic-link+ ] }
+ { DT_SOCK [ +socket+ ] }
+ { DT_FIFO [ +fifo+ ] }
+ { DT_REG [ +regular-file+ ] }
+ { DT_WHT [ +whiteout+ ] }
+ [ drop +unknown+ ]
+ } case ;
+
C-STRUCT: group
{ "char*" "gr_name" }
{ "char*" "gr_passwd" }
ERROR: unix-error errno message ;
-M: unix-error error.
- "Unix system call failed:" print
- nl
- dup message>> write " (" write errno>> pprint ")" print ;
-
: (io-error) ( -- * ) err_no dup strerror unix-error ;
: io-error ( n -- ) 0 < [ (io-error) ] when ;
ERROR: unix-system-call-error args errno message word ;
-M: unix-system-call-error error.
- "Unix system call ``" write dup word>> pprint "'' failed:" print
- nl
- dup message>> write " (" write dup errno>> pprint ")" print
- nl
- "It was called with the following arguments:" print
- nl
- args>> stack. ;
-
MACRO:: unix-system-call ( quot -- )
[let | n [ quot infer in>> ]
word [ quot first ] |
: PATH_MAX 1024 ; inline
: read-symbolic-link ( path -- path )
- PATH_MAX <byte-array> dup >r
- PATH_MAX
- [ readlink ] unix-system-call
- r> swap head-slice >string ;
+ PATH_MAX <byte-array> dup [
+ PATH_MAX
+ [ readlink ] unix-system-call
+ ] dip swap head-slice >string ;
FUNCTION: ssize_t recv ( int s, void* buf, size_t nbytes, int flags ) ;
FUNCTION: ssize_t recvfrom ( int s, void* buf, size_t nbytes, int flags, sockaddr-in* from, socklen_t* fromlen ) ;
{ [ os bsd? ] [ "unix.bsd" require ] }
{ [ os solaris? ] [ "unix.solaris" require ] }
} cond
+
+"debugger" vocab [
+ "unix.debugger" require
+] when
SYMBOL: user-cache
+: <user-cache> ( -- assoc )
+ all-users [ [ uid>> ] keep ] H{ } map>assoc ;
+
: with-user-cache ( quot -- )
- all-users [ [ uid>> ] keep ] H{ } map>assoc
- user-cache rot with-variable ; inline
+ [ <user-cache> user-cache ] dip with-variable ; inline
GENERIC: user-passwd ( obj -- passwd )
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types alien.strings
-combinators.short-circuit fry kernel layouts sequences ;
+combinators.short-circuit fry kernel layouts sequences
+specialized-arrays.alien accessors ;
IN: unix.utilities
: more? ( alien -- ? )
[ ] produce nip ;
: strings>alien ( strings encoding -- alien )
- '[ _ malloc-string ] map f suffix >c-void*-array ;
+ '[ _ malloc-string ] void*-array{ } map-as f suffix underlying>> ;
[
[
[ url-encode ] dip
- [ url-encode "=" swap 3append , ] with each
+ [ url-encode "=" glue , ] with each
] assoc-each
] { } make "&" join ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel present prettyprint.custom prettyprint.backend urls ;
+IN: urls.prettyprint
+
+M: url pprint* dup present "URL\" " "\"" pprint-string ;
! See http://factorcode.org/license.txt for BSD license.
USING: kernel ascii combinators combinators.short-circuit
sequences splitting fry namespaces make assocs arrays strings
-io.sockets io.encodings.string
-io.encodings.utf8 math math.parser accessors parser
-strings.parser lexer prettyprint.backend hashtables present
-peg.ebnf urls.encoding ;
+io.sockets io.encodings.string io.encodings.utf8 math
+math.parser accessors parser strings.parser lexer
+hashtables present peg.ebnf urls.encoding ;
IN: urls
TUPLE: url protocol username password host port path query anchor ;
{ [ dup empty? ] [ drop ] }
{ [ over "/" tail? ] [ append ] }
{ [ "/" pick start not ] [ nip ] }
- [ [ "/" last-split1 drop "/" ] dip 3append ]
+ [ [ "/" split1-last drop "/" ] dip 3append ]
} cond ;
PRIVATE>
! Literal syntax
: URL" lexer get skip-blank parse-string >url parsed ; parsing
-M: url pprint* dup present "URL\" " "\"" pprint-string ;
+USING: vocabs vocabs.loader ;
+
+"prettyprint" vocab [
+ "urls.prettyprint" require
+] when
[ "4561_2612_1234_5467" v-credit-card ] must-fail
[ "4561-2621-1234-5467" v-credit-card ] must-fail
+
+[ t ] [ "http://double.co.nz/w?v=foo" dup v-url = ] unit-test
v-regexp ;
: v-url ( str -- str )
- "URL"
- R' (ftp|http|https)://(\w+:?\w*@)?(\S+)(:[0-9]+)?(/|/([\w#!:.?+=&%@!\-/]))?'
- v-regexp ;
+ "URL" R' (ftp|http|https)://\S+' v-regexp ;
: v-captcha ( str -- str )
dup empty? [ "must remain blank" throw ] unless ;
IN: values\r
\r
ARTICLE: "values" "Global values"\r
-"Usually, dynamically scoped variables are sufficient for holding data which is not literal. But occasionally, for global information that's calculated just once, it's useful to use the word mechanism instead, and set the word to the appropriate value just once. Values abstract over this concept. To create a new word as a value, use the following syntax:"\r
+"Usually, dynamically scoped variables are sufficient for holding data which is not literal. But occasionally, for global information that's calculated just once, it's useful to use the word mechanism instead, and set the word to the appropriate value just once. The " { $vocab-link "values" } " vocabulary implements " { $emphasis "values" } ", which abstract over this concept. To create a new word as a value, use the following syntax:"\r
{ $subsection POSTPONE: VALUE: }\r
"To get the value, just call the word. The following words manipulate values:"\r
{ $subsection get-value }\r
{ $subsection POSTPONE: to: }\r
{ $subsection change-value } ;\r
\r
+ABOUT: "values"\r
+\r
HELP: VALUE:\r
{ $syntax "VALUE: word" }\r
{ $values { "word" "a word to be created" } }\r
! See http://factorcode.org/license.txt for BSD license.
USING: arrays accessors sequences sequences.private
persistent.sequences assocs persistent.assocs kernel math
-vectors parser prettyprint.backend ;
+vectors parser prettyprint.custom ;
IN: vlists
TUPLE: vlist
HRESULT Drop ( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) ;\r
\r
: com-query-interface ( interface iid -- interface' )\r
- "void*" heap-size [\r
+ [\r
+ "void*" malloc-object &free\r
[ IUnknown::QueryInterface ole32-error ] keep *void*\r
- ] with-malloc ;\r
+ ] with-destructors ;\r
\r
: com-add-ref ( interface -- interface )\r
[ IUnknown::AddRef drop ] keep ; inline\r
-USING: alien alien.c-types effects kernel windows.ole32
-parser lexer splitting grouping sequences namespaces
-assocs quotations generalizations accessors words macros alien.syntax
-fry arrays ;
+USING: alien alien.c-types alien.accessors effects kernel
+windows.ole32 parser lexer splitting grouping sequences
+namespaces assocs quotations generalizations accessors words
+macros alien.syntax fry arrays layouts math ;
IN: windows.com.syntax
<PRIVATE
{ "void*" "vtbl" } ;
MACRO: com-invoke ( n return parameters -- )
- dup length -roll
+ [ 2nip length ] 3keep
'[
- _ npick com-interface-vtbl _ swap void*-nth _ _
+ _ npick com-interface-vtbl _ cell * alien-cell _ _
"stdcall" alien-indirect
] ;
-USING: alien alien.c-types windows.com.syntax init
-windows.com.syntax.private windows.com continuations kernel
+USING: alien alien.c-types alien.accessors windows.com.syntax
+init windows.com.syntax.private windows.com continuations kernel
namespaces windows.ole32 libc vocabs assocs accessors arrays
sequences quotations combinators math words compiler.units
-destructors fry math.parser generalizations sets ;
+destructors fry math.parser generalizations sets
+specialized-arrays.alien specialized-arrays.direct.alien ;
IN: windows.com.wrapper
TUPLE: com-wrapper callbacks vtbls disposed ;
_ case
[
"void*" heap-size * rot <displaced-alien> com-add-ref
- 0 rot set-void*-nth S_OK
- ] [ nip f 0 rot set-void*-nth E_NOINTERFACE ] if*
+ swap 0 set-alien-cell S_OK
+ ] [ nip f swap 0 set-alien-cell E_NOINTERFACE ] if*
] ;
: (make-add-ref) ( interfaces -- quot )
length "void*" heap-size * '[
- _ swap <displaced-alien>
- 0 over ulong-nth
- 1+ [ 0 rot set-ulong-nth ] keep
+ _
+ [ alien-unsigned-4 1+ dup ]
+ [ set-alien-unsigned-4 ]
+ 2bi
] ;
: (make-release) ( interfaces -- quot )
length "void*" heap-size * '[
- _ over <displaced-alien>
- 0 over ulong-nth
- 1- [ 0 rot set-ulong-nth ] keep
- dup zero? [ swap (free-wrapped-object) ] [ nip ] if
+ _
+ [ drop ]
+ [ alien-unsigned-4 1- dup ]
+ [ set-alien-unsigned-4 ]
+ 2tri
+ dup 0 = [ swap (free-wrapped-object) ] [ nip ] if
] ;
: (make-iunknown-methods) ( interfaces -- quots )
[ [ (( -- alien )) define-declared ] pick slip ]
with-compilation-unit ;
-: byte-array>malloc ( byte-array -- alien )
- [ byte-length malloc ] [ over byte-array>memory ] bi ;
-
: (callback-word) ( function-name interface-name counter -- word )
[ "::" rot 3append "-callback-" ] dip number>string 3append
"windows.com.wrapper.callbacks" create ;
: (malloc-wrapped-object) ( wrapper -- wrapped-object )
vtbls>> length "void*" heap-size *
[ "ulong" heap-size + malloc ] keep
- over <displaced-alien>
- 1 0 rot set-ulong-nth ;
+ [ [ 1 ] 2dip set-alien-unsigned-4 ] [ drop ] 2bi ;
: (callbacks>vtbl) ( callbacks -- vtbl )
- [ execute ] map >c-void*-array byte-array>malloc ;
+ [ execute ] void*-array{ } map-as underlying>> malloc-byte-array ;
: (callbacks>vtbls) ( callbacks -- vtbls )
[ (callbacks>vtbl) ] map ;
: com-wrap ( object wrapper -- wrapped-object )
[ vtbls>> ] [ (malloc-wrapped-object) ] bi
- [ [ set-void*-nth ] curry each-index ] keep
+ [ over length <direct-void*-array> 0 swap copy ] keep
[ +wrapped-objects+ get-global set-at ] keep ;
USING: windows.dinput windows.kernel32 windows.ole32 windows.com
windows.com.syntax alien alien.c-types alien.syntax kernel system namespaces
combinators sequences symbols fry math accessors macros words quotations
-libc continuations generalizations splitting locals assocs init ;
+libc continuations generalizations splitting locals assocs init
+struct-arrays ;
IN: windows.dinput.constants
! Some global variables aren't provided by the DirectInput DLL (they're in the
} cleave
"DIOBJECTDATAFORMAT" <c-object> (DIOBJECTDATAFORMAT) ;
-: malloc-DIOBJECTDATAFORMAT-array ( struct array -- alien )
- [ nip length "DIOBJECTDATAFORMAT" malloc-array dup ]
- [
- -rot [| args i alien struct |
+:: malloc-DIOBJECTDATAFORMAT-array ( struct array -- alien )
+ [let | alien [ array length "DIOBJECTDATAFORMAT" malloc-struct-array ] |
+ array [| args i |
struct args <DIOBJECTDATAFORMAT>
- i alien set-DIOBJECTDATAFORMAT-nth
- ] 2curry each-index
- ] 2bi ;
+ i alien set-nth
+ ] each-index
+ alien underlying>>
+ ] ;
: (DIDATAFORMAT) ( dwSize dwObjSize dwFlags dwDataSize dwNumObjs rgodf alien -- alien )
[ {
: DC_BRUSH 18 ; inline
: DC_PEN 19 ; inline
+: BI_RGB 0 ; inline
+: BI_RLE8 1 ; inline
+: BI_RLE4 2 ; inline
+: BI_BITFIELDS 3 ; inline
+
+: DIB_RGB_COLORS 0 ; inline
+: DIB_PAL_COLORS 1 ; inline
+
LIBRARY: gdi32
! FUNCTION: AbortPath
! FUNCTION: CreateColorSpaceA
! FUNCTION: CreateColorSpaceW
! FUNCTION: CreateCompatibleBitmap
-! FUNCTION: CreateCompatibleDC
+FUNCTION: HDC CreateCompatibleDC ( HDC hdc ) ;
! FUNCTION: CreateDCA
! FUNCTION: CreateDCW
! FUNCTION: CreateDIBitmap
! FUNCTION: CreateDIBPatternBrush
! FUNCTION: CreateDIBPatternBrushPt
-! FUNCTION: CreateDIBSection
+FUNCTION: HBITMAP CreateDIBSection ( HDC hdc, BITMAPINFO* pbmi, UINT iUsage, void** ppvBits, HANDLE hSection, DWORD dwOffset ) ;
! FUNCTION: CreateDiscardableBitmap
! FUNCTION: CreateEllipticRgn
! FUNCTION: CreateEllipticRgnIndirect
! FUNCTION: DdEntry8
! FUNCTION: DdEntry9
! FUNCTION: DeleteColorSpace
-! FUNCTION: DeleteDC
+FUNCTION: BOOL DeleteDC ( HDC hdc ) ;
! FUNCTION: DeleteEnhMetaFile
! FUNCTION: DeleteMetaFile
FUNCTION: BOOL DeleteObject ( HGDIOBJ hObject ) ;
! FUNCTION: GdiEntry8
! FUNCTION: GdiEntry9
! FUNCTION: GdiFixUpHandle
-! FUNCTION: GdiFlush
+FUNCTION: BOOL GdiFlush ( ) ;
! FUNCTION: GdiFullscreenControl
! FUNCTION: GdiGetBatchLimit
! FUNCTION: GdiGetCharDimensions
! FUNCTION: SelectClipPath
FUNCTION: int SelectClipRgn ( HDC hDC, HRGN hrgn ) ;
! FUNCTION: SelectFontLocal
-! FUNCTION: SelectObject
+FUNCTION: HGDIOBJ SelectObject ( HDC hdc, HGDIOBJ hgdiobj ) ;
! FUNCTION: SelectPalette
! FUNCTION: SetAbortProc
! FUNCTION: SetArcDirection
: THREAD_PRIORITY_TIME_CRITICAL 15 ; inline
C-STRUCT: OVERLAPPED
- { "int" "internal" }
- { "int" "internal-high" }
- { "int" "offset" }
- { "int" "offset-high" }
- { "void*" "event" } ;
+ { "UINT_PTR" "internal" }
+ { "UINT_PTR" "internal-high" }
+ { "DWORD" "offset" }
+ { "DWORD" "offset-high" }
+ { "HANDLE" "event" } ;
C-STRUCT: SYSTEMTIME
{ "WORD" "wYear" }
{ "DWORD" "type" } ;
C-STRUCT: GUID
- { "ulong" "Data1" }
- { "ushort" "Data2" }
- { "ushort" "Data3" }
- { { "uchar" 8 } "Data4" } ;
+ { "ULONG" "Data1" }
+ { "WORD" "Data2" }
+ { "WORD" "Data3" }
+ { { "UCHAR" 8 } "Data4" } ;
: SE_CREATE_TOKEN_NAME "SeCreateTokenPrivilege" ;
USING: alien alien.syntax alien.c-types alien.strings math
kernel sequences windows windows.types debugger io accessors
math.order namespaces make math.parser windows.kernel32
-combinators ;
+combinators locals specialized-arrays.direct.uchar ;
IN: windows.ole32
LIBRARY: ole32
: GUID-STRING-LENGTH
"{01234567-89ab-cdef-0123-456789abcdef}" length ; inline
-: (guid-section>guid) ( guid string start end quot -- )
- [ roll subseq hex> swap ] dip call ; inline
-: (guid-byte>guid) ( guid string start end byte -- )
- [ roll subseq hex> ] dip
- rot GUID-Data4 set-uchar-nth ; inline
+:: (guid-section>guid) ( string guid start end quot -- )
+ start end string subseq hex> guid quot call ; inline
-: string>guid ( string -- guid )
- "GUID" <c-object> [ {
- [ 1 9 [ set-GUID-Data1 ] (guid-section>guid) ]
-
- [ 10 14 [ set-GUID-Data2 ] (guid-section>guid) ]
-
- [ 15 19 [ set-GUID-Data3 ] (guid-section>guid) ]
+:: (guid-byte>guid) ( string guid start end byte -- )
+ start end string subseq hex> byte guid set-nth ; inline
- [ 20 22 0 (guid-byte>guid) ]
- [ 22 24 1 (guid-byte>guid) ]
-
- [ 25 27 2 (guid-byte>guid) ]
- [ 27 29 3 (guid-byte>guid) ]
- [ 29 31 4 (guid-byte>guid) ]
- [ 31 33 5 (guid-byte>guid) ]
- [ 33 35 6 (guid-byte>guid) ]
- [ 35 37 7 (guid-byte>guid) ]
- } 2cleave ] keep ;
+: string>guid ( string -- guid )
+ "GUID" <c-object> [
+ {
+ [ 1 9 [ set-GUID-Data1 ] (guid-section>guid) ]
+ [ 10 14 [ set-GUID-Data2 ] (guid-section>guid) ]
+ [ 15 19 [ set-GUID-Data3 ] (guid-section>guid) ]
+ [ ]
+ } 2cleave
+
+ GUID-Data4 8 <direct-uchar-array> {
+ [ 20 22 0 (guid-byte>guid) ]
+ [ 22 24 1 (guid-byte>guid) ]
+
+ [ 25 27 2 (guid-byte>guid) ]
+ [ 27 29 3 (guid-byte>guid) ]
+ [ 29 31 4 (guid-byte>guid) ]
+ [ 31 33 5 (guid-byte>guid) ]
+ [ 33 35 6 (guid-byte>guid) ]
+ [ 35 37 7 (guid-byte>guid) ]
+ } 2cleave
+ ] keep ;
: (guid-section%) ( guid quot len -- )
[ call >hex ] dip CHAR: 0 pad-left % ; inline
+
: (guid-byte%) ( guid byte -- )
- swap GUID-Data4 uchar-nth >hex 2
- CHAR: 0 pad-left % ; inline
+ swap nth >hex 2 CHAR: 0 pad-left % ; inline
: guid>string ( guid -- string )
- [ "{" % {
- [ [ GUID-Data1 ] 8 (guid-section%) "-" % ]
- [ [ GUID-Data2 ] 4 (guid-section%) "-" % ]
- [ [ GUID-Data3 ] 4 (guid-section%) "-" % ]
- [ 0 (guid-byte%) ]
- [ 1 (guid-byte%) "-" % ]
- [ 2 (guid-byte%) ]
- [ 3 (guid-byte%) ]
- [ 4 (guid-byte%) ]
- [ 5 (guid-byte%) ]
- [ 6 (guid-byte%) ]
- [ 7 (guid-byte%) "}" % ]
- } cleave ] "" make ;
+ [
+ "{" % {
+ [ [ GUID-Data1 ] 8 (guid-section%) "-" % ]
+ [ [ GUID-Data2 ] 4 (guid-section%) "-" % ]
+ [ [ GUID-Data3 ] 4 (guid-section%) "-" % ]
+ [ ]
+ } cleave
+ GUID-Data4 8 <direct-uchar-array> {
+ [ 0 (guid-byte%) ]
+ [ 1 (guid-byte%) "-" % ]
+ [ 2 (guid-byte%) ]
+ [ 3 (guid-byte%) ]
+ [ 4 (guid-byte%) ]
+ [ 5 (guid-byte%) ]
+ [ 6 (guid-byte%) ]
+ [ 7 (guid-byte%) "}" % ]
+ } cleave
+ ] "" make ;
: WGL_SWAP_UNDERLAY14 HEX: 20000000 ; inline
: WGL_SWAP_UNDERLAY15 HEX: 40000000 ; inline
-: pfd-dwFlags ( -- n )
+: windowed-pfd-dwFlags ( -- n )
{ PFD_DRAW_TO_WINDOW PFD_SUPPORT_OPENGL PFD_DOUBLEBUFFER } flags ;
+: offscreen-pfd-dwFlags ( -- n )
+ { PFD_DRAW_TO_BITMAP PFD_SUPPORT_OPENGL } flags ;
! TODO: compare to http://www.nullterminator.net/opengl32.html
-: make-pfd ( bits -- pfd )
+: make-pfd ( flags bits -- pfd )
"PIXELFORMATDESCRIPTOR" <c-object>
"PIXELFORMATDESCRIPTOR" heap-size over set-PIXELFORMATDESCRIPTOR-nSize
1 over set-PIXELFORMATDESCRIPTOR-nVersion
- pfd-dwFlags over set-PIXELFORMATDESCRIPTOR-dwFlags
+ rot over set-PIXELFORMATDESCRIPTOR-dwFlags
PFD_TYPE_RGBA over set-PIXELFORMATDESCRIPTOR-iPixelType
[ set-PIXELFORMATDESCRIPTOR-cColorBits ] keep
16 over set-PIXELFORMATDESCRIPTOR-cDepthBits
USING: alien alien.c-types alien.strings alien.syntax combinators
kernel windows windows.user32 windows.ole32
-windows.com windows.com.syntax io.files ;
+windows.com windows.com.syntax io.files io.encodings.utf16n ;
IN: windows.shell32
: CSIDL_DESKTOP HEX: 00 ; inline
TYPEDEF: long LONG_PTR
TYPEDEF: long* PLONG_PTR
-TYPEDEF: int ULONG
+TYPEDEF: uint ULONG
TYPEDEF: void* ULONG_PTR
TYPEDEF: void* PULONG_PTR
TYPEDEF: void* LPCVOID
TYPEDEF: float FLOAT
-TYPEDEF: short HALF_PTR
-TYPEDEF: ushort UHALF_PTR
-TYPEDEF: int INT_PTR
-TYPEDEF: uint UINT_PTR
+
+TYPEDEF: intptr_t HALF_PTR
+TYPEDEF: intptr_t UHALF_PTR
+TYPEDEF: intptr_t INT_PTR
+TYPEDEF: intptr_t UINT_PTR
TYPEDEF: int LONG_PTR
TYPEDEF: ulong ULONG_PTR
! { "BYTE[32]" "rgbReserved" }
! ;
+C-STRUCT: BITMAPINFOHEADER
+ { "DWORD" "biSize" }
+ { "LONG" "biWidth" }
+ { "LONG" "biHeight" }
+ { "WORD" "biPlanes" }
+ { "WORD" "biBitCount" }
+ { "DWORD" "biCompression" }
+ { "DWORD" "biSizeImage" }
+ { "LONG" "biXPelsPerMeter" }
+ { "LONG" "biYPelsPerMeter" }
+ { "DWORD" "biClrUsed" }
+ { "DWORD" "biClrImportant" } ;
+
+C-STRUCT: RGBQUAD
+ { "BYTE" "rgbBlue" }
+ { "BYTE" "rgbGreen" }
+ { "BYTE" "rgbRed" }
+ { "BYTE" "rgbReserved" } ;
+
+C-STRUCT: BITMAPINFO
+ { "BITMAPINFOHEADER" "bmiHeader" }
+ { "RGBQUAD[1]" "bmiColors" } ;
+
TYPEDEF: void* LPPAINTSTRUCT
TYPEDEF: void* PAINTSTRUCT
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.syntax alien.c-types alien.strings arrays
combinators kernel math namespaces parser prettyprint sequences
-windows.errors windows.types windows.kernel32 words ;
+windows.errors windows.types windows.kernel32 words
+io.encodings.utf16n ;
IN: windows
: lo-word ( wparam -- lo ) <short> *short ; inline
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types alien.strings alien.syntax arrays
byte-arrays kernel math sequences windows.types windows.kernel32
-windows.errors windows math.bitwise alias ;
+windows.errors windows math.bitwise alias io.encodings.utf16n ;
IN: windows.winsock
USE: libc
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types alien.strings alien.syntax arrays
kernel math namespaces sequences io.encodings.string
-io.encodings.utf8 io.encodings.ascii x11.xlib x11.constants ;
+io.encodings.utf8 io.encodings.ascii x11.xlib x11.constants
+specialized-arrays.int accessors ;
IN: x11.clipboard
! This code was based on by McCLIM's Backends/CLX/port.lisp
"TARGETS" x-atom 32 PropModeReplace
{
"UTF8_STRING" "STRING" "TARGETS" "TIMESTAMP"
- } [ x-atom ] map >c-int-array
+ } [ x-atom ] int-array{ } map-as underlying>>
4 XChangeProperty drop ;
: set-timestamp-prop ( evt -- )
[ XSelectionRequestEvent-requestor ] keep
[ XSelectionRequestEvent-property ] keep
>r "TIMESTAMP" x-atom 32 PropModeReplace r>
- XSelectionRequestEvent-time 1array >c-int-array
+ XSelectionRequestEvent-time <int>
1 XChangeProperty drop ;
: send-notify ( evt prop -- )
! See http://factorcode.org/license.txt for BSD license.
!
! based on glx.h from xfree86, and some of glxtokens.h
-USING: alien alien.c-types alien.syntax alien.syntax.private x11.xlib
-namespaces make kernel sequences parser words ;
+USING: alien alien.c-types alien.syntax x11.xlib namespaces make
+kernel sequences parser words specialized-arrays.int accessors ;
IN: x11.glx
LIBRARY: glx
FUNCTION: void* glXGetProcAddressARB ( char* procname ) ;
! GLX Events
-! (also skipped for now. only has GLXPbufferClobberEvent, the rest is handled by xlib methinks
+! (also skipped for now. only has GLXPbufferClobberEvent, the rest is handled by xlib methinks)
-: choose-visual ( -- XVisualInfo* )
- dpy get scr get
+: choose-visual ( flags -- XVisualInfo* )
+ [ dpy get scr get ] dip
[
+ %
GLX_RGBA ,
- GLX_DOUBLEBUFFER ,
GLX_DEPTH_SIZE , 16 ,
0 ,
- ] { } make >c-int-array
+ ] int-array{ } make underlying>>
glXChooseVisual
[ "Could not get a double-buffered GLX RGBA visual" throw ] unless* ;
: create-glx ( XVisualInfo* -- GLXContext )
- >r dpy get r> f 1 glXCreateContext
+ [ dpy get ] dip f 1 glXCreateContext
[ "Failed to create GLX context" throw ] unless* ;
: destroy-glx ( GLXContext -- )
- dpy get swap glXDestroyContext ;
\ No newline at end of file
+ dpy get swap glXDestroyContext ;
! Copyright (C) 2005, 2006 Eduardo Cavazos and Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
USING: alien alien.c-types hashtables kernel math math.vectors
-math.bitwise namespaces sequences x11.xlib x11.constants x11.glx ;
+math.bitwise namespaces sequences x11.xlib x11.constants x11.glx
+arrays fry ;
IN: x11.windows
: create-window-mask ( -- n )
dup r> auto-position ;
: glx-window ( loc dim -- window glx )
- choose-visual
+ GLX_DOUBLEBUFFER 1array choose-visual
[ create-window ] keep
[ create-glx ] keep
XFree ;
+: create-pixmap ( dim visual -- pixmap )
+ [ [ { 0 0 } swap ] dip create-window ] [
+ drop [ dpy get ] 2dip first2 24 XCreatePixmap
+ [ "Failed to create offscreen pixmap" throw ] unless*
+ ] 2bi ;
+
+: (create-glx-pixmap) ( pixmap visual -- pixmap glx-pixmap )
+ [ drop ] [
+ [ dpy get ] 2dip swap glXCreateGLXPixmap
+ [ "Failed to create offscreen GLXPixmap" throw ] unless*
+ ] 2bi ;
+
+: create-glx-pixmap ( dim visual -- pixmap glx-pixmap )
+ [ create-pixmap ] [ (create-glx-pixmap) ] bi ;
+
+: glx-pixmap ( dim -- glx pixmap glx-pixmap )
+ { } choose-visual
+ [ nip create-glx ] [ create-glx-pixmap ] [ nip XFree ] 2tri ;
+
: destroy-window ( win -- )
dpy get swap XDestroyWindow drop ;
: map-window ( win -- ) dpy get swap XMapWindow drop ;
: unmap-window ( win -- ) dpy get swap XUnmapWindow drop ;
+
+: pixmap-bits ( dim pixmap -- alien )
+ swap first2 '[ dpy get _ 0 0 _ _ AllPlanes ZPixmap XGetImage ] call
+ [ XImage-pixels ] [ XDestroyImage drop ] bi ;
-! Copyright (C) 2007 Slava Pestov
+! Copyright (C) 2007, 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: alien alien.c-types arrays byte-arrays hashtables
-io kernel math namespaces sequences strings
-continuations x11.xlib ;
+USING: alien alien.c-types alien.strings arrays byte-arrays
+hashtables io io.encodings.string kernel math namespaces
+sequences strings continuations x11.xlib specialized-arrays.uint
+accessors io.encodings.utf16n ;
IN: x11.xim
SYMBOL: xim
: (init-xim) ( classname medifier -- im )
XSetLocaleModifiers [ "XSetLocaleModifiers() failed" throw ] unless
- dpy get f rot dup XOpenIM ;
+ [ dpy get f ] dip dup XOpenIM ;
: init-xim ( classname -- )
dup "" (init-xim)
xim get-global XCloseIM drop f xim set-global ;
: with-xim ( quot -- )
- >r "Factor" init-xim r> [ close-xim ] [ ] cleanup ;
+ [ "Factor" init-xim ] dip [ close-xim ] [ ] cleanup ;
: create-xic ( window classname -- xic )
- >r >r xim get-global
- XNClientWindow r>
- XNFocusWindow over
- XNInputStyle XIMPreeditNothing XIMStatusNothing bitor
- XNResourceName r>
+ [
+ [ xim get-global XNClientWindow ] dip
+ XNFocusWindow over
+ XNInputStyle XIMPreeditNothing XIMStatusNothing bitor
+ XNResourceName
+ ] dip
XNResourceClass over 0 XCreateIC
[ "XCreateIC() failed" throw ] unless* ;
SYMBOL: keysym
: prepare-lookup ( -- )
- buf-size "uint" <c-array> keybuf set
+ buf-size <uint-array> keybuf set
0 <KeySym> keysym set ;
: finish-lookup ( len -- string keysym )
- keybuf get swap c-uint-array> >string
+ keybuf get swap 2 * head utf16n decode
keysym get *KeySym ;
: lookup-string ( event xic -- string keysym )
[
prepare-lookup
- swap keybuf get buf-size keysym get 0 <int>
+ swap keybuf get underlying>> buf-size keysym get 0 <int>
XwcLookupString
finish-lookup
] with-scope ;
USING: kernel arrays alien alien.c-types alien.strings
alien.syntax math math.bitwise words sequences namespaces
-continuations io.encodings.ascii ;
+continuations io io.encodings.ascii ;
IN: x11.xlib
LIBRARY: xlib
FUNCTION: int XConvertSelection ( Display* display, Atom selection, Atom target, Atom property, Window requestor, Time time ) ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! 5 - Pixmap and Cursor Functions
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! 5.1 - Creating and Freeing Pixmaps
+
+FUNCTION: Pixmap XCreatePixmap ( Display* display, Drawable d, uint width, uint height, uint depth ) ;
+FUNCTION: int XFreePixmap ( Display* display, Pixmap pixmap ) ;
+
+
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! 6 - Color Management Functions
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
char* string,
int length ) ;
+! 8.7 - Transferring Images between Client and Server
+
+: XYBitmap 0 ; inline
+: XYPixmap 1 ; inline
+: ZPixmap 2 ; inline
+: AllPlanes -1 ; inline
+
+C-STRUCT: XImage-funcs
+ { "void*" "create_image" }
+ { "void*" "destroy_image" }
+ { "void*" "get_pixel" }
+ { "void*" "put_pixel" }
+ { "void*" "sub_image" }
+ { "void*" "add_pixel" } ;
+
+C-STRUCT: XImage
+ { "int" "width" }
+ { "int" "height" }
+ { "int" "xoffset" }
+ { "int" "format" }
+ { "char*" "data" }
+ { "int" "byte_order" }
+ { "int" "bitmap_unit" }
+ { "int" "bitmap_bit_order" }
+ { "int" "bitmap_pad" }
+ { "int" "depth" }
+ { "int" "bytes_per_line" }
+ { "int" "bits_per_pixel" }
+ { "ulong" "red_mask" }
+ { "ulong" "green_mask" }
+ { "ulong" "blue_mask" }
+ { "XPointer" "obdata" }
+ { "XImage-funcs" "f" } ;
+
+FUNCTION: XImage* XGetImage ( Display* display, Drawable d, int x, int y, uint width, uint height, ulong plane_mask, int format ) ;
+FUNCTION: int XDestroyImage ( XImage *ximage ) ;
+
+: XImage-size ( ximage -- size )
+ [ XImage-height ] [ XImage-bytes_per_line ] bi * ;
+
+: XImage-pixels ( ximage -- byte-array )
+ [ XImage-data ] [ XImage-size ] bi memory>byte-array ;
+
!
! 9 - Window and Session Manager Functions
!
SYMBOL: root
: init-locale ( -- )
- LC_ALL "" setlocale [ "setlocale() failed" throw ] unless
- XSupportsLocale [ "XSupportsLocale() failed" throw ] unless ;
+ LC_ALL "" setlocale [ "setlocale() failed" print flush ] unless
+ XSupportsLocale [ "XSupportsLocale() failed" print flush ] unless ;
: flush-dpy ( -- ) dpy get XFlush drop ;
: close-x ( -- ) dpy get XCloseDisplay drop ;
: with-x ( display-string quot -- )
- >r initialize-x r> [ close-x ] [ ] cleanup ;
+ [ initialize-x ] dip [ close-x ] [ ] cleanup ;
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences sequences.private assocs arrays
delegate.protocols delegate vectors accessors multiline
-macros words quotations combinators slots ;
+macros words quotations combinators slots fry ;
IN: xml.data
TUPLE: name space main url ;
TUPLE: comment text ;
C: <comment> comment
-TUPLE: directive text ;
-C: <directive> directive
+TUPLE: directive ;
+
+TUPLE: element-decl < directive name content-spec ;
+C: <element-decl> element-decl
+
+TUPLE: attlist-decl < directive name att-defs ;
+C: <attlist-decl> attlist-decl
+
+TUPLE: entity-decl < directive name def ;
+C: <entity-decl> entity-decl
+
+TUPLE: system-id system-literal ;
+C: <system-id> system-id
+
+TUPLE: public-id pubid-literal system-literal ;
+C: <public-id> public-id
+
+TUPLE: doctype-decl < directive name external-id internal-subset ;
+C: <doctype-decl> doctype-decl
TUPLE: instruction text ;
C: <instruction> instruction
C: <attrs> attrs
: attr@ ( key alist -- index {key,value} )
- >r assure-name r> alist>>
+ [ assure-name ] dip alist>>
[ first names-match? ] with find ;
M: attrs at*
2dup attr@ nip [
2nip set-second
] [
- >r assure-name swap 2array r>
+ [ assure-name swap 2array ] dip
[ alist>> ?push ] keep (>>alist)
] if* ;
: >attrs ( assoc -- attrs )
dup [
V{ } assoc-clone-like
- [ >r assure-name r> ] assoc-map
+ [ [ assure-name ] dip ] assoc-map
] when <attrs> ;
M: attrs assoc-like
drop dup attrs? [ >attrs ] unless ;
MACRO: clone-slots ( class -- tuple )
[
"slots" word-prop
- [ name>> reader-word 1quotation [ clone ] compose ] map
- [ cleave ] curry
- ] [ [ boa ] curry ] bi compose ;
+ [ name>> reader-word '[ _ execute clone ] ] map
+ '[ _ cleave ]
+ ] [ '[ _ boa ] ] bi compose ;
M: tag clone
tag clone-slots ;
<PRIVATE
: tag>xml ( xml tag -- newxml )
- >r [ prolog>> ] [ before>> ] [ after>> ] tri r>
+ [ [ prolog>> ] [ before>> ] [ after>> ] tri ] dip
swap <xml> ;
: seq>xml ( xml seq -- newxml )
! Copyright (C) 2005, 2006 Daniel Ehrenberg
! See http://factorcode.org/license.txt for BSD license.
-USING: namespaces make kernel assocs sequences ;
+USING: namespaces make kernel assocs sequences fry ;
IN: xml.entities
: entities-out
: escape-string-by ( str table -- escaped )
#! Convert <, >, &, ' and " to HTML entities.
- [ [ dupd at [ % ] [ , ] ?if ] curry each ] "" make ;
+ [ '[ dup _ at [ % ] [ , ] ?if ] each ] "" make ;
: escape-string ( str -- newstr )
entities-out escape-string-by ;
-USING: continuations xml xml.errors tools.test kernel arrays xml.data state-parser quotations ;
+USING: continuations xml xml.errors tools.test kernel arrays
+xml.data state-parser quotations fry ;
IN: xml.errors.tests
: xml-error-test ( expected-error xml-string -- )
- [ string>xml ] curry swap [ = ] curry must-fail-with ;
+ '[ _ string>xml ] swap '[ _ = ] must-fail-with ;
T{ no-entity f 1 10 "nbsp" } "<x> </x>" xml-error-test
T{ mismatched f 1 8 T{ name f "" "x" "" } T{ name f "" "y" "" }
T{ versionless-prolog f 1 8 } "<?xml?><x/>" xml-error-test
T{ bad-instruction f 1 11 T{ instruction f "xsl" }
} "<x><?xsl?></x>" xml-error-test
-T{ bad-directive f 1 15 T{ directive f "DOCTYPE" }
-} "<x/><!DOCTYPE>" xml-error-test
namespaces io.streams.string xml.backend ;
IN: xml.errors
-TUPLE: multitags ;
-C: <multitags> multitags
+ERROR: multitags ;
+
M: multitags summary ( obj -- str )
drop "XML document contains multiple main tags" ;
-TUPLE: pre/post-content string pre? ;
-C: <pre/post-content> pre/post-content
+ERROR: pre/post-content string pre? ;
+
M: pre/post-content summary ( obj -- str )
[
"The text string:" print
] with-string-writer ;
TUPLE: no-entity < parsing-error thing ;
-: <no-entity> ( string -- error )
- \ no-entity parsing-error swap >>thing ;
+
+: no-entity ( string -- * )
+ \ no-entity parsing-error swap >>thing throw ;
+
M: no-entity summary ( obj -- str )
[
dup call-next-method write
] with-string-writer ;
TUPLE: xml-string-error < parsing-error string ; ! this should not exist
-: <xml-string-error> ( string -- xml-string-error )
- \ xml-string-error parsing-error swap >>string ;
+
+: xml-string-error ( string -- * )
+ \ xml-string-error parsing-error swap >>string throw ;
+
M: xml-string-error summary ( obj -- str )
[
dup call-next-method write
] with-string-writer ;
TUPLE: mismatched < parsing-error open close ;
-: <mismatched> ( open close -- error )
- \ mismatched parsing-error swap >>close swap >>open ;
+
+: mismatched ( open close -- * )
+ \ mismatched parsing-error swap >>close swap >>open throw ;
+
M: mismatched summary ( obj -- str )
[
dup call-next-method write
] with-string-writer ;
TUPLE: unclosed < parsing-error tags ;
-: <unclosed> ( -- unclosed )
- unclosed parsing-error
- xml-stack get rest-slice [ first name>> ] map >>tags ;
+
+: unclosed ( -- * )
+ \ unclosed parsing-error
+ xml-stack get rest-slice [ first name>> ] map >>tags
+ throw ;
+
M: unclosed summary ( obj -- str )
[
dup call-next-method write
] with-string-writer ;
TUPLE: bad-uri < parsing-error string ;
-: <bad-uri> ( string -- bad-uri )
- \ bad-uri parsing-error swap >>string ;
+
+: bad-uri ( string -- * )
+ \ bad-uri parsing-error swap >>string throw ;
+
M: bad-uri summary ( obj -- str )
[
dup call-next-method write
] with-string-writer ;
TUPLE: nonexist-ns < parsing-error name ;
-: <nonexist-ns> ( name-string -- nonexist-ns )
- \ nonexist-ns parsing-error swap >>name ;
+
+: nonexist-ns ( name-string -- * )
+ \ nonexist-ns parsing-error swap >>name throw ;
+
M: nonexist-ns summary ( obj -- str )
[
dup call-next-method write
] with-string-writer ;
TUPLE: unopened < parsing-error ; ! this should give which tag was unopened
-: <unopened> ( -- unopened )
- \ unopened parsing-error ;
+
+: unopened ( -- * )
+ \ unopened parsing-error throw ;
+
M: unopened summary ( obj -- str )
[
call-next-method write
] with-string-writer ;
TUPLE: not-yes/no < parsing-error text ;
-: <not-yes/no> ( text -- not-yes/no )
- \ not-yes/no parsing-error swap >>text ;
+
+: not-yes/no ( text -- * )
+ \ not-yes/no parsing-error swap >>text throw ;
+
M: not-yes/no summary ( obj -- str )
[
dup call-next-method write
! this should actually print the names
TUPLE: extra-attrs < parsing-error attrs ;
-: <extra-attrs> ( attrs -- extra-attrs )
- \ extra-attrs parsing-error swap >>attrs ;
+
+: extra-attrs ( attrs -- * )
+ \ extra-attrs parsing-error swap >>attrs throw ;
+
M: extra-attrs summary ( obj -- str )
[
dup call-next-method write
] with-string-writer ;
TUPLE: bad-version < parsing-error num ;
-: <bad-version> ( num -- error )
- \ bad-version parsing-error swap >>num ;
+
+: bad-version ( num -- * )
+ \ bad-version parsing-error swap >>num throw ;
+
M: bad-version summary ( obj -- str )
[
"XML version must be \"1.0\" or \"1.1\". Version here was " write
num>> .
] with-string-writer ;
-TUPLE: notags ;
-C: <notags> notags
+ERROR: notags ;
+
M: notags summary ( obj -- str )
drop "XML document lacks a main tag" ;
TUPLE: bad-prolog < parsing-error prolog ;
-: <bad-prolog> ( prolog -- bad-prolog )
- \ bad-prolog parsing-error swap >>prolog ;
+
+: bad-prolog ( prolog -- * )
+ \ bad-prolog parsing-error swap >>prolog throw ;
+
M: bad-prolog summary ( obj -- str )
[
dup call-next-method write
] with-string-writer ;
TUPLE: capitalized-prolog < parsing-error name ;
-: <capitalized-prolog> ( name -- capitalized-prolog )
- \ capitalized-prolog parsing-error swap >>name ;
+
+: capitalized-prolog ( name -- capitalized-prolog )
+ \ capitalized-prolog parsing-error swap >>name throw ;
+
M: capitalized-prolog summary ( obj -- str )
[
dup call-next-method write
] with-string-writer ;
TUPLE: versionless-prolog < parsing-error ;
-: <versionless-prolog> ( -- versionless-prolog )
- \ versionless-prolog parsing-error ;
+
+: versionless-prolog ( -- * )
+ \ versionless-prolog parsing-error throw ;
+
M: versionless-prolog summary ( obj -- str )
[
call-next-method write
] with-string-writer ;
TUPLE: bad-instruction < parsing-error instruction ;
-: <bad-instruction> ( instruction -- bad-instruction )
- \ bad-instruction parsing-error swap >>instruction ;
+
+: bad-instruction ( instruction -- * )
+ \ bad-instruction parsing-error swap >>instruction throw ;
+
M: bad-instruction summary ( obj -- str )
[
dup call-next-method write
"Misplaced processor instruction:" print
- instruction>> write-item nl
+ instruction>> write-xml-chunk nl
] with-string-writer ;
TUPLE: bad-directive < parsing-error dir ;
-: <bad-directive> ( directive -- bad-directive )
- \ bad-directive parsing-error swap >>dir ;
+
+: bad-directive ( directive -- * )
+ \ bad-directive parsing-error swap >>dir throw ;
+
M: bad-directive summary ( obj -- str )
+ [
+ dup call-next-method write
+ "Unknown directive:" print
+ dir>> write
+ ] with-string-writer ;
+
+TUPLE: bad-doctype-decl < parsing-error ;
+
+: bad-doctype-decl ( -- * )
+ \ bad-doctype-decl parsing-error throw ;
+
+M: bad-doctype-decl summary ( obj -- str )
+ call-next-method "\nBad DOCTYPE" append ;
+
+TUPLE: bad-external-id < parsing-error ;
+
+: bad-external-id ( -- * )
+ \ bad-external-id parsing-error throw ;
+
+M: bad-external-id summary ( obj -- str )
+ call-next-method "\nBad external ID" append ;
+
+TUPLE: misplaced-directive < parsing-error dir ;
+
+: misplaced-directive ( directive -- * )
+ \ misplaced-directive parsing-error swap >>dir throw ;
+
+M: misplaced-directive summary ( obj -- str )
[
dup call-next-method write
"Misplaced directive:" print
- dir>> write-item nl
+ dir>> write-xml-chunk nl
] with-string-writer ;
UNION: xml-parse-error multitags notags extra-attrs nonexist-ns
USING: tools.test io.streams.string xml.generator xml.writer accessors ;
[ "<html><body><a href=\"blah\"/></body></html>" ]
-[ "html" [ "body" [ "a" { { "href" "blah" } } contained*, ] tag, ] make-xml [ body>> write-item ] with-string-writer ] unit-test
+[ "html" [ "body" [ "a" { { "href" "blah" } } contained*, ] tag, ] make-xml [ body>> write-xml-chunk ] with-string-writer ] unit-test
IN: xml.generator
: comment, ( string -- ) <comment> , ;
-: directive, ( string -- ) <directive> , ;
: instruction, ( string -- ) <instruction> , ;
: nl, ( -- ) "\n" , ;
: (tag,) ( name attrs quot -- tag )
- -rot >r >r V{ } make r> r> rot <tag> ; inline
+ -rot [ V{ } make ] 2dip rot <tag> ; inline
: tag*, ( name attrs quot -- )
(tag,) , ; inline
PROCESS: calculate ( tag -- n )
: calc-2children ( tag -- n n )
- children-tags first2 >r calculate r> calculate ;
+ children-tags first2 [ calculate ] dip calculate ;
TAG: number calculate
children>string string>number ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+IN: xml.tests
+USING: xml xml.writer io.files io.encodings.utf8 tools.test kernel ;
+
+[ t ] [
+ "resource:basis/xml/tests/funny-dtd.xml" utf8 file-contents string>xml
+ dup xml>string string>xml =
+] unit-test
--- /dev/null
+<?xml version="1.0" standalone="yes" ?><!DOCTYPE SHOUTCASTSERVER [<!ELEMENT SHOUTCASTSERVER (CURRENTLISTENERS,PEAKLISTENERS,MAXLISTENERS,REPORTEDLISTENERS,AVERAGETIME,SERVERGENRE,SERVERURL,SERVERTITLE,SONGTITLE,SONGURL,IRC,ICQ,AIM,WEBHITS,STREAMHITS,STREAMSTATUS,BITRATE,CONTENT,VERSION,WEBDATA,LISTENERS,SONGHISTORY)><!ELEMENT CURRENTLISTENERS (#PCDATA)><!ELEMENT PEAKLISTENERS (#PCDATA)><!ELEMENT MAXLISTENERS (#PCDATA)><!ELEMENT REPORTEDLISTENERS (#PCDATA)><!ELEMENT AVERAGETIME (#PCDATA)><!ELEMENT SERVERGENRE (#PCDATA)><!ELEMENT SERVERURL (#PCDATA)><!ELEMENT SERVERTITLE (#PCDATA)><!ELEMENT SONGTITLE (#PCDATA)><!ELEMENT SONGURL (#PCDATA)><!ELEMENT IRC (#PCDATA)><!ELEMENT ICQ (#PCDATA)><!ELEMENT AIM (#PCDATA)><!ELEMENT WEBHITS (#PCDATA)><!ELEMENT STREAMHITS (#PCDATA)><!ELEMENT STREAMSTATUS (#PCDATA)><!ELEMENT BITRATE (#PCDATA)><!ELEMENT CONTENT (#PCDATA)><!ELEMENT VERSION (#PCDATA)><!ELEMENT WEBDATA (INDEX,LISTEN,PALM7,LOGIN,LOGINFAIL,PLAYED,COOKIE,ADMIN,UPDINFO,KICKSRC,KICKDST,UNBANDST,BANDST,VIEWBAN,UNRIPDST,RIPDST,VIEWRIP,VIEWXML,VIEWLOG,INVALID)><!ELEMENT INDEX (#PCDATA)><!ELEMENT LISTEN (#PCDATA)><!ELEMENT PALM7 (#PCDATA)><!ELEMENT LOGIN (#PCDATA)><!ELEMENT LOGINFAIL (#PCDATA)><!ELEMENT PLAYED (#PCDATA)><!ELEMENT COOKIE (#PCDATA)><!ELEMENT ADMIN (#PCDATA)><!ELEMENT UPDINFO (#PCDATA)><!ELEMENT KICKSRC (#PCDATA)><!ELEMENT KICKDST (#PCDATA)><!ELEMENT UNBANDST (#PCDATA)><!ELEMENT BANDST (#PCDATA)><!ELEMENT VIEWBAN (#PCDATA)><!ELEMENT UNRIPDST (#PCDATA)><!ELEMENT RIPDST (#PCDATA)><!ELEMENT VIEWRIP (#PCDATA)><!ELEMENT VIEWXML (#PCDATA)><!ELEMENT VIEWLOG (#PCDATA)><!ELEMENT INVALID (#PCDATA)><!ELEMENT LISTENERS (LISTENER*)><!ELEMENT LISTENER (HOSTNAME,USERAGENT,UNDERRUNS,CONNECTTIME, POINTER, UID)><!ELEMENT HOSTNAME (#PCDATA)><!ELEMENT USERAGENT (#PCDATA)><!ELEMENT UNDERRUNS (#PCDATA)><!ELEMENT CONNECTTIME (#PCDATA)><!ELEMENT POINTER (#PCDATA)><!ELEMENT UID (#PCDATA)><!ELEMENT SONGHISTORY (SONG*)><!ELEMENT SONG (PLAYEDAT, TITLE)><!ELEMENT PLAYEDAT (#PCDATA)><!ELEMENT TITLE (#PCDATA)>]><SHOUTCASTSERVER><CURRENTLISTENERS>0</CURRENTLISTENERS><PEAKLISTENERS>3</PEAKLISTENERS><MAXLISTENERS>500</MAXLISTENERS><REPORTEDLISTENERS>0</REPORTEDLISTENERS><AVERAGETIME>85</AVERAGETIME><SERVERGENRE>various</SERVERGENRE><SERVERURL>http://zomgwtfbbq.info</SERVERURL><SERVERTITLE>[zOMBradio][DJKyleL]</SERVERTITLE><SONGTITLE>Daft Punk - One More Time / Aerodynamic</SONGTITLE><SONGURL></SONGURL><IRC></IRC><ICQ></ICQ><AIM>arkz1372</AIM><WEBHITS>1645</WEBHITS><STREAMHITS>78</STREAMHITS><STREAMSTATUS>0</STREAMSTATUS><BITRATE>96</BITRATE><CONTENT>audio/aacp</CONTENT><VERSION>1.9.8</VERSION><WEBDATA><INDEX>61</INDEX><LISTEN>6</LISTEN><PALM7>0</PALM7><LOGIN>0</LOGIN><LOGINFAIL>30</LOGINFAIL><PLAYED>2</PLAYED><COOKIE>1</COOKIE><ADMIN>11</ADMIN><UPDINFO>1</UPDINFO><KICKSRC>0</KICKSRC><KICKDST>0</KICKDST><UNBANDST>0</UNBANDST><BANDST>0</BANDST><VIEWBAN>3</VIEWBAN><UNRIPDST>0</UNRIPDST><RIPDST>1</RIPDST><VIEWRIP>3</VIEWRIP><VIEWXML>1490</VIEWXML><VIEWLOG>3</VIEWLOG><INVALID>30</INVALID></WEBDATA><LISTENERS></LISTENERS><SONGHISTORY><SONG><PLAYEDAT>1227896017</PLAYEDAT><TITLE>Daft Punk - One More Time / Aerodynamic</TITLE></SONG></SONGHISTORY></SHOUTCASTSERVER>
+
! Example
-: sample-doc
+: sample-doc ( -- string )
{
"<html xmlns:f='http://littledan.onigirihouse.com/namespaces/replace'>"
"<body>"
USING: kernel xml tools.test io namespaces make sequences
xml.errors xml.entities parser strings xml.data io.files
xml.writer xml.utilities state-parser continuations assocs
-sequences.deep accessors ;
+sequences.deep accessors io.streams.string ;
! This is insufficient
\ read-xml must-infer
"c" get-id children>string
] unit-test
[ "foo" ] [ "<x y='foo'/>" string>xml "y" over
- at swap "z" >r tuck r> swap set-at
+ at swap "z" [ tuck ] dip swap set-at
T{ name f "blah" "z" f } swap at ] unit-test
[ "foo" ] [ "<boo><![CDATA[foo]]></boo>" string>xml children>string ] unit-test
[ "<?xml version=\"1.0\" encoding=\"UTF-8\"?><foo>bar baz</foo>" ]
[ "<foo>bar</foo>" string>xml [ " baz" append ] map xml>string ] unit-test
[ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<foo>\n bar\n</foo>" ]
[ "<foo> bar </foo>" string>xml pprint-xml>string ] unit-test
+[ "<!-- B+, B, or B--->" string>xml ] must-fail
+[ ] [ "<?xml version='1.0'?><!-- declarations for <head> & <body> --><foo/>" string>xml drop ] unit-test
+[ T{ element-decl f "br" "EMPTY" } ] [ "<!ELEMENT br EMPTY>" string>xml-chunk second ] unit-test
+[ T{ element-decl f "p" "(#PCDATA|emph)*" } ] [ "<!ELEMENT p (#PCDATA|emph)*>" string>xml-chunk second ] unit-test
+[ T{ element-decl f "%name.para;" "%content.para;" } ] [ "<!ELEMENT %name.para; %content.para;>" string>xml-chunk second ] unit-test
+[ T{ element-decl f "container" "ANY" } ] [ "<!ELEMENT container ANY>" string>xml-chunk second ] unit-test
+[ T{ doctype-decl f "foo" } ] [ "<!DOCTYPE foo>" string>xml-chunk second ] unit-test
+[ T{ doctype-decl f "foo" } ] [ "<!DOCTYPE foo >" string>xml-chunk second ] unit-test
+[ T{ doctype-decl f "foo" T{ system-id f "blah.dtd" } } ] [ "<!DOCTYPE foo SYSTEM 'blah.dtd'>" string>xml-chunk second ] unit-test
+[ T{ doctype-decl f "foo" T{ system-id f "blah.dtd" } } ] [ "<!DOCTYPE foo SYSTEM \"blah.dtd\" >" string>xml-chunk second ] unit-test
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: xml io.encodings.utf8 io.files kernel tools.test ;
+IN: xml.tests
+
+[ ] [
+ "resource:basis/xmode/xmode.dtd" utf8 <file-reader>
+ read-xml-chunk drop
+] unit-test
USING: xml.errors xml.data xml.utilities xml.char-classes sets
xml.entities kernel state-parser kernel namespaces make strings
math math.parser sequences assocs arrays splitting combinators
-unicode.case accessors ;
+unicode.case accessors fry ascii ;
IN: xml.tokenize
! XML namespace processing: ns = namespace
: add-ns ( name -- )
dup space>> dup ns-stack get assoc-stack
- [ nip ] [ <nonexist-ns> throw ] if* >>url drop ;
+ [ nip ] [ nonexist-ns ] if* >>url drop ;
: push-ns ( hash -- )
ns-stack get push ;
: tag-ns ( name attrs-alist -- name attrs )
dup attrs>ns push-ns
- >r dup add-ns r> dup [ drop add-ns ] assoc-each <attrs> ;
+ [ dup add-ns ] dip dup [ drop add-ns ] assoc-each <attrs> ;
! Parsing names
get-char name-start? [
[ dup get-char name-char? not ] take-until nip
] [
- "Malformed name" <xml-string-error> throw
+ "Malformed name" xml-string-error
] if ;
: parse-name ( -- name )
: (parse-entity) ( string -- )
dup entities at [ , ] [
prolog-data get standalone>>
- [ <no-entity> throw ] [
+ [ no-entity ] [
dup extra-entities get at
- [ , ] [ <no-entity> throw ] ?if
+ [ , ] [ no-entity ] ?if
] if
] ?if ;
: parse-quot ( ch -- string )
parse-char get-char
- [ "XML file ends in a quote" <xml-string-error> throw ] unless ;
+ [ "XML file ends in a quote" xml-string-error ] unless ;
: parse-text ( -- string )
CHAR: < parse-char ;
get-char dup "'\"" member? [
next parse-quot
] [
- "Attribute lacks quote" <xml-string-error> throw
+ "Attribute lacks quote" xml-string-error
] if ;
: parse-attr ( -- )
: take-cdata ( -- string )
"[CDATA[" expect-string "]]>" take-string ;
+: take-element-decl ( -- element-decl )
+ pass-blank " " take-string pass-blank ">" take-string <element-decl> ;
+
+: take-attlist-decl ( -- doctype-decl )
+ pass-blank " " take-string pass-blank ">" take-string <attlist-decl> ;
+
+: take-until-one-of ( seps -- str sep )
+ '[ get-char _ member? ] take-until get-char ;
+
+: only-blanks ( str -- )
+ [ blank? ] all? [ bad-doctype-decl ] unless ;
+
+: take-system-literal ( -- str )
+ pass-blank get-char next {
+ { CHAR: ' [ "'" take-string ] }
+ { CHAR: " [ "\"" take-string ] }
+ } case ;
+
+: take-system-id ( -- system-id )
+ take-system-literal <system-id>
+ ">" take-string only-blanks ;
+
+: take-public-id ( -- public-id )
+ take-system-literal
+ take-system-literal <public-id>
+ ">" take-string only-blanks ;
+
+DEFER: direct
+
+: (take-internal-subset) ( -- )
+ pass-blank get-char {
+ { CHAR: ] [ next ] }
+ [ drop "<!" expect-string direct , (take-internal-subset) ]
+ } case ;
+
+: take-internal-subset ( -- seq )
+ [ (take-internal-subset) ] { } make ;
+
+: (take-external-id) ( token -- external-id )
+ pass-blank {
+ { "SYSTEM" [ take-system-id ] }
+ { "PUBLIC" [ take-public-id ] }
+ [ bad-external-id ]
+ } case ;
+
+: take-external-id ( -- external-id )
+ " " take-string (take-external-id) ;
+
+: take-doctype-decl ( -- doctype-decl )
+ pass-blank " >" take-until-one-of {
+ { CHAR: \s [
+ pass-blank get-char CHAR: [ = [
+ next take-internal-subset f swap
+ ">" take-string only-blanks
+ ] [
+ " >" take-until-one-of {
+ { CHAR: \s [ (take-external-id) ] }
+ { CHAR: > [ only-blanks f ] }
+ } case f
+ ] if
+ ] }
+ { CHAR: > [ f f ] }
+ } case <doctype-decl> ;
+
+: take-entity-def ( -- entity-name entity-def )
+ " " take-string pass-blank get-char {
+ { CHAR: ' [ take-system-literal ] }
+ { CHAR: " [ take-system-literal ] }
+ [ drop take-external-id ]
+ } case ;
+
+: take-entity-decl ( -- entity-decl )
+ pass-blank get-char {
+ { CHAR: % [ next pass-blank take-entity-def ] }
+ [ drop take-entity-def ]
+ } case
+ ">" take-string only-blanks <entity-decl> ;
+
: take-directive ( -- directive )
- CHAR: > take-char <directive> next ;
+ " " take-string {
+ { "ELEMENT" [ take-element-decl ] }
+ { "ATTLIST" [ take-attlist-decl ] }
+ { "DOCTYPE" [ take-doctype-decl ] }
+ { "ENTITY" [ take-entity-decl ] }
+ [ bad-directive ]
+ } case ;
: direct ( -- object )
get-char {
{
{ "yes" [ t ] }
{ "no" [ f ] }
- [ <not-yes/no> throw ]
+ [ not-yes/no ]
} case ;
: assure-no-extra ( seq -- )
T{ name f "" "encoding" f }
T{ name f "" "standalone" f }
} diff
- [ <extra-attrs> throw ] unless-empty ;
+ [ extra-attrs ] unless-empty ;
: good-version ( version -- version )
- dup { "1.0" "1.1" } member? [ <bad-version> throw ] unless ;
+ dup { "1.0" "1.1" } member? [ bad-version ] unless ;
: prolog-attrs ( alist -- prolog )
[ T{ name f "" "version" f } swap at
- [ good-version ] [ <versionless-prolog> throw ] if* ] keep
+ [ good-version ] [ versionless-prolog ] if* ] keep
[ T{ name f "" "encoding" f } swap at
"UTF-8" or ] keep
T{ name f "" "standalone" f } swap at
(parse-name) dup "xml" =
[ drop parse-prolog ] [
dup >lower "xml" =
- [ <capitalized-prolog> throw ]
+ [ capitalized-prolog ]
[ "?>" take-string append <instruction> ] if
] if ;
! See http://factorcode.org/license.txt for BSD license.
USING: accessors kernel namespaces sequences words io assocs
quotations strings parser lexer arrays xml.data xml.writer debugger
-splitting vectors sequences.deep combinators ;
+splitting vectors sequences.deep combinators fry ;
IN: xml.utilities
! * System for words specialized on tag names
: run-process ( tag word -- )
2dup "xtable" word-prop
- >r dup main>> r> at* [ 2nip call ] [
+ [ dup main>> ] dip at* [ 2nip call ] [
drop \ process-missing boa throw
] if ;
: PROCESS:
CREATE
dup H{ } clone "xtable" set-word-prop
- dup [ run-process ] curry define ; parsing
+ dup '[ _ run-process ] define ; parsing
: TAG:
scan scan-word
parse-definition
swap "xtable" word-prop
- rot "/" split [ >r 2dup r> swap set-at ] each 2drop ;
+ rot "/" split [ [ 2dup ] dip swap set-at ] each 2drop ;
parsing
! * Common utility functions
: build-tag* ( items name -- tag )
- assure-name swap >r f r> <tag> ;
+ assure-name swap f swap <tag> ;
: build-tag ( item name -- tag )
- >r 1array r> build-tag* ;
+ [ 1array ] dip build-tag* ;
: standard-prolog ( -- prolog )
T{ prolog f "1.0" "UTF-8" f } ;
dup tag? [ names-match? ] [ 2drop f ] if ;
: tags@ ( tag name -- children name )
- >r { } like r> assure-name ;
+ [ { } like ] dip assure-name ;
: deep-tag-named ( tag name/string -- matching-tag )
- assure-name [ swap tag-named? ] curry deep-find ;
+ assure-name '[ _ swap tag-named? ] deep-find ;
: deep-tags-named ( tag name/string -- tags-seq )
- tags@ [ swap tag-named? ] curry deep-filter ;
+ tags@ '[ _ swap tag-named? ] deep-filter ;
: tag-named ( tag name/string -- matching-tag )
! like get-name-tag but only looks at direct children,
rot dup tag? [ at = ] [ 3drop f ] if ;
: tag-with-attr ( tag attr-value attr-name -- matching-tag )
- assure-name [ tag-with-attr? ] 2curry find nip ;
+ assure-name '[ _ _ tag-with-attr? ] find nip ;
: tags-with-attr ( tag attr-value attr-name -- tags-seq )
- tags@ [ tag-with-attr? ] 2curry filter children>> ;
+ tags@ '[ _ _ tag-with-attr? ] filter children>> ;
: deep-tag-with-attr ( tag attr-value attr-name -- matching-tag )
- assure-name [ tag-with-attr? ] 2curry deep-find ;
+ assure-name '[ _ _ tag-with-attr? ] deep-find ;
: deep-tags-with-attr ( tag attr-value attr-name -- tags-seq )
- tags@ [ tag-with-attr? ] 2curry deep-filter ;
+ tags@ '[ _ _ tag-with-attr? ] deep-filter ;
: get-id ( tag id -- elem ) ! elem=tag.getElementById(id)
"id" deep-tag-with-attr ;
: deep-tags-named-with-attr ( tag tag-name attr-value attr-name -- tags )
- >r >r deep-tags-named r> r> tags-with-attr ;
+ [ deep-tags-named ] 2dip tags-with-attr ;
: assert-tag ( name name -- )
names-match? [ "Unexpected XML tag found" throw ] unless ;
[ swap V{ } like >>children drop ] if ;
: insert-child ( child tag -- )
- >r 1vector r> insert-children ;
+ [ 1vector ] dip insert-children ;
! See http://factorcode.org/license.txt for BSD license.\r
USING: hashtables kernel math namespaces sequences strings\r
assocs combinators io io.streams.string accessors\r
-xml.data wrap xml.entities unicode.categories ;\r
+xml.data wrap xml.entities unicode.categories fry ;\r
IN: xml.writer\r
\r
SYMBOL: xml-pprint?\r
" " indenter set-global\r
\r
: sensitive? ( tag -- ? )\r
- sensitive-tags get swap [ names-match? ] curry contains? ;\r
+ sensitive-tags get swap '[ _ names-match? ] contains? ;\r
\r
: indent-string ( -- string )\r
xml-pprint? get\r
"\"" write\r
] assoc-each ;\r
\r
-GENERIC: write-item ( object -- )\r
+GENERIC: write-xml-chunk ( object -- )\r
\r
-M: string write-item\r
+M: string write-xml-chunk\r
escape-string dup empty? not xml-pprint? get and\r
[ nl 80 indent-string indented-break ] when write ;\r
\r
: write-start-tag ( tag -- )\r
write-tag ">" write ;\r
\r
-M: contained-tag write-item\r
+M: contained-tag write-xml-chunk\r
write-tag "/>" write ;\r
\r
: write-children ( tag -- )\r
indent children>> ?filter-children\r
- [ write-item ] each unindent ;\r
+ [ write-xml-chunk ] each unindent ;\r
\r
: write-end-tag ( tag -- )\r
?indent "</" write print-name CHAR: > write1 ;\r
\r
-M: open-tag write-item\r
- xml-pprint? get >r\r
- {\r
- [ sensitive? not xml-pprint? get and xml-pprint? set ]\r
- [ write-start-tag ]\r
- [ write-children ]\r
- [ write-end-tag ]\r
- } cleave\r
- r> xml-pprint? set ;\r
-\r
-M: comment write-item\r
+M: open-tag write-xml-chunk\r
+ xml-pprint? get [\r
+ {\r
+ [ sensitive? not xml-pprint? get and xml-pprint? set ]\r
+ [ write-start-tag ]\r
+ [ write-children ]\r
+ [ write-end-tag ]\r
+ } cleave\r
+ ] dip xml-pprint? set ;\r
+\r
+M: comment write-xml-chunk\r
"<!--" write text>> write "-->" write ;\r
\r
-M: directive write-item\r
+M: element-decl write-xml-chunk\r
+ "<!ELEMENT " write\r
+ [ name>> write " " write ]\r
+ [ content-spec>> write ">" write ]\r
+ bi ;\r
+\r
+M: attlist-decl write-xml-chunk\r
+ "<!ATTLIST " write\r
+ [ name>> write " " write ]\r
+ [ att-defs>> write ">" write ]\r
+ bi ;\r
+\r
+M: entity-decl write-xml-chunk\r
+ "<!ENTITY " write\r
+ [ name>> write " " write ]\r
+ [ def>> write-xml-chunk ">" write ]\r
+ bi ;\r
+\r
+M: system-id write-xml-chunk\r
+ "SYSTEM '" write system-literal>> write "'" write ;\r
+\r
+M: public-id write-xml-chunk\r
+ "PUBLIC '" write\r
+ [ pubid-literal>> write "' '" write ]\r
+ [ system-literal>> write "'>" write ] bi ;\r
+\r
+M: doctype-decl write-xml-chunk\r
+ "<!DOCTYPE " write\r
+ [ name>> write " " write ]\r
+ [ external-id>> [ write-xml-chunk " " write ] when* ]\r
+ [\r
+ internal-subset>>\r
+ [ "[" write [ write-xml-chunk ] each "]" write ] when* ">" write\r
+ ] tri ;\r
+\r
+M: directive write-xml-chunk\r
"<!" write text>> write CHAR: > write1 ;\r
\r
-M: instruction write-item\r
+M: instruction write-xml-chunk\r
"<?" write text>> write "?>" write ;\r
\r
+M: sequence write-xml-chunk\r
+ [ write-xml-chunk ] each ;\r
+\r
: write-prolog ( xml -- )\r
"<?xml version=\"" write dup version>> write\r
"\" encoding=\"" write dup encoding>> write\r
standalone>> [ "\" standalone=\"yes" write ] when\r
"\"?>" write ;\r
\r
-: write-chunk ( seq -- )\r
- [ write-item ] each ;\r
-\r
: write-xml ( xml -- )\r
{\r
[ prolog>> write-prolog ]\r
- [ before>> write-chunk ]\r
- [ body>> write-item ]\r
- [ after>> write-chunk ]\r
+ [ before>> write-xml-chunk ]\r
+ [ body>> write-xml-chunk ]\r
+ [ after>> write-xml-chunk ]\r
} cleave ;\r
\r
-M: xml write-item\r
- body>> write-item ;\r
+M: xml write-xml-chunk\r
+ body>> write-xml-chunk ;\r
\r
: print-xml ( xml -- )\r
write-xml nl ;\r
{ $example "USING: prettyprint xml.data ;" "T{ name f \"rpc\" \"methodCall\" f } T{ name f f \"methodCall\" \"http://www.xmlrpc.org/\" } names-match? ." "t" }\r
{ $see-also name } ;\r
\r
-HELP: xml-chunk\r
+HELP: read-xml-chunk\r
{ $values { "stream" "an input stream" } { "seq" "a sequence of elements" } }\r
{ $description "rather than parse a document, as " { $link read-xml } " does, this word parses and returns a sequence of XML elements (tags, strings, etc), ie a document fragment. This is useful for pieces of XML which may have more than one main tag." }\r
-{ $see-also write-chunk read-xml } ;\r
+{ $see-also write-xml-chunk read-xml } ;\r
\r
HELP: get-id\r
{ $values { "tag" "an XML tag or document" } { "id" "a string" } { "elem" "an XML element or f" } }\r
{ $description "gets the next XML event from the given XML pull parser. Returns f upon exhaustion." }\r
{ $see-also pull-xml <pull-xml> pull-elem } ;\r
\r
-HELP: write-item\r
+HELP: write-xml-chunk\r
{ $values { "object" "an XML element" } }\r
{ $description "writes an XML element to " { $link output-stream } "." }\r
-{ $see-also write-chunk write-xml } ;\r
-\r
-HELP: write-chunk\r
-{ $values { "seq" "an XML document fragment" } }\r
-{ $description "writes an XML document fragment, ie a sequence of XML elements, to " { $link output-stream } "." }\r
-{ $see-also write-item write-xml } ;\r
+{ $see-also write-xml-chunk write-xml } ;\r
\r
HELP: deep-tag-named\r
{ $values { "tag" "an XML tag or document" } { "name/string" "an XML name or string representing a name" } { "matching-tag" tag } }\r
"The following words are used to read something into an XML document"\r
{ $subsection string>xml }\r
{ $subsection read-xml }\r
- { $subsection xml-chunk }\r
+ { $subsection read-xml-chunk }\r
+ { $subsection string>xml-chunk }\r
{ $subsection file>xml } ;\r
\r
ARTICLE: { "xml" "writing" } "Writing XML"\r
"These words are used in implementing prettyprint"\r
- { $subsection write-item }\r
- { $subsection write-chunk }\r
+ { $subsection write-xml-chunk }\r
"These words are used to print XML normally"\r
{ $subsection xml>string }\r
{ $subsection write-xml }\r
M: prolog process
xml-stack get V{ { f V{ "" } } } =
- [ <bad-prolog> throw ] unless drop ;
+ [ bad-prolog ] unless drop ;
M: instruction process
xml-stack get length 1 =
- [ <bad-instruction> throw ] unless
+ [ bad-instruction ] unless
add-child ;
M: directive process
xml-stack get dup length 1 =
swap first second [ tag? ] contains? not and
- [ <bad-directive> throw ] unless
+ [ misplaced-directive ] unless
add-child ;
M: contained process
M: opener process push-xml ;
: check-closer ( name opener -- name opener )
- dup [ <unopened> throw ] unless
+ dup [ unopened ] unless
2dup name>> =
- [ name>> swap <mismatched> throw ] unless ;
+ [ name>> swap mismatched ] unless ;
M: closer process
name>> pop-xml first2
- >r check-closer attrs>> r>
+ [ check-closer attrs>> ] dip
<tag> add-child ;
: init-xml-stack ( -- )
swap [ string? ] filter
[
dup [ blank? ] all?
- [ drop ] [ swap <pre/post-content> throw ] if
+ [ drop ] [ swap pre/post-content ] if
] each drop ;
: no-pre/post ( pre post -- pre post/* )
! this does *not* affect the contents of the stack
- >r dup t assert-blanks r>
- dup f assert-blanks ;
+ [ dup t assert-blanks ] [ dup f assert-blanks ] bi* ;
: no-post-tags ( post -- post/* )
! this does *not* affect the contents of the stack
- dup [ tag? ] contains? [ <multitags> throw ] when ;
+ dup [ tag? ] contains? [ multitags ] when ;
: assure-tags ( seq -- seq )
! this does *not* affect the contents of the stack
- [ <notags> throw ] unless* ;
+ [ notags ] unless* ;
: make-xml-doc ( prolog seq -- xml-doc )
dup [ tag? ] find
- >r assure-tags cut rest
- no-pre/post no-post-tags
- r> swap <xml> ;
+ [ assure-tags cut rest no-pre/post no-post-tags ] dip
+ swap <xml> ;
! * Views of XML
: (read-xml) ( -- )
[ process ] sax-loop ; inline
-: (xml-chunk) ( stream -- prolog seq )
+: (read-xml-chunk) ( stream -- prolog seq )
[
init-xml (read-xml)
- done? [ <unclosed> throw ] unless
+ done? [ unclosed ] unless
xml-stack get first second
prolog-data get swap
] state-parse ;
: read-xml ( stream -- xml )
#! Produces a tree of XML nodes
- (xml-chunk) make-xml-doc ;
+ (read-xml-chunk) make-xml-doc ;
-: xml-chunk ( stream -- seq )
- (xml-chunk) nip ;
+: read-xml-chunk ( stream -- seq )
+ (read-xml-chunk) nip ;
: string>xml ( string -- xml )
<string-reader> read-xml ;
+: string>xml-chunk ( string -- xml )
+ <string-reader> read-xml-chunk ;
+
: file>xml ( filename -- xml )
! Autodetect encoding!
utf8 <file-reader> read-xml ;
USING: accessors sequences assocs kernel quotations namespaces
-xml.data xml.utilities combinators macros parser lexer words ;
+xml.data xml.utilities combinators macros parser lexer words fry ;
IN: xmode.utilities
-: implies >r not r> or ; inline
+: implies [ not ] dip or ; inline
: child-tags ( tag -- seq ) children>> [ tag? ] filter ;
: map-find ( seq quot -- result elt )
f -rot
- [ nip ] swap [ dup ] 3compose find
- >r [ drop f ] unless r> ; inline
+ '[ nip @ dup ] find
+ [ [ drop f ] unless ] dip ; inline
: tag-init-form ( spec -- quot )
{
{ [ dup quotation? ] [ [ object get tag get ] prepose ] }
{ [ dup length 2 = ] [
- first2 [
- >r >r tag get children>string
- r> [ execute ] when* object get r> execute
- ] 2curry
+ first2 '[
+ tag get children>string
+ _ [ execute ] when* object get _ execute
+ ]
] }
{ [ dup length 3 = ] [
- first3 [
- >r >r tag get at
- r> [ execute ] when* object get r> execute
- ] 3curry
+ first3 '[
+ _ tag get at
+ _ [ execute ] when* object get _ execute
+ ]
] }
} cond ;
[ with-tag-initializer ] curry ;
: init-from-tag ( tag tuple specs -- tuple )
- over >r (init-from-tag) r> ; inline
+ over [ (init-from-tag) ] dip ; inline
SYMBOL: tag-handlers
SYMBOL: tag-handler-word
$ECHO "***Factor will compile NO_UI=1"
NO_UI=1
fi
- rm -f $GCC_TEST
- check_ret rm
- rm -f $GCC_OUT
- check_ret rm
+ $DELETE -f $GCC_TEST
+ check_ret $DELETE
+ $DELETE -f $GCC_OUT
+ check_ret $DELETE
$ECHO "found."
}
gcc -o $C_WORD $C_WORD.c
WORD=$(./$C_WORD)
check_ret $C_WORD
- rm -f $C_WORD*
+ $DELETE -f $C_WORD*
}
intel_macosx_word_size() {
set_factor_binary() {
case $OS in
- # winnt) FACTOR_BINARY=factor-nt;;
- # macosx) FACTOR_BINARY=./Factor.app/Contents/MacOS/factor;;
+ winnt) FACTOR_BINARY=factor.exe;;
*) FACTOR_BINARY=factor;;
esac
}
+set_factor_library() {
+ case $OS in
+ winnt) FACTOR_LIBRARY=factor.dll;;
+ macosx) FACTOR_LIBRARY=libfactor.dylib;;
+ *) FACTOR_LIBRARY=libfactor.a;;
+ esac
+}
+
+set_factor_image() {
+ FACTOR_IMAGE=factor.image
+}
+
echo_build_info() {
$ECHO OS=$OS
$ECHO ARCH=$ARCH
$ECHO WORD=$WORD
$ECHO FACTOR_BINARY=$FACTOR_BINARY
+ $ECHO FACTOR_LIBRARY=$FACTOR_LIBRARY
+ $ECHO FACTOR_IMAGE=$FACTOR_IMAGE
$ECHO MAKE_TARGET=$MAKE_TARGET
$ECHO BOOT_IMAGE=$BOOT_IMAGE
$ECHO MAKE_IMAGE_TARGET=$MAKE_IMAGE_TARGET
$ECHO DOWNLOADER=$DOWNLOADER
$ECHO CC=$CC
$ECHO MAKE=$MAKE
+ $ECHO COPY=$COPY
+ $ECHO DELETE=$DELETE
}
check_os_arch_word() {
find_architecture
find_word_size
set_factor_binary
+ set_factor_library
+ set_factor_image
set_build_info
set_downloader
set_gcc
check_ret cd
}
+set_copy() {
+ case $OS in
+ winnt) COPY=cp;;
+ *) COPY=cp;;
+ esac
+}
+
+set_delete() {
+ case $OS in
+ winnt) DELETE=rm;;
+ *) DELETE=rm;;
+ esac
+}
+
+backup_factor() {
+ $ECHO "Backing up factor..."
+ $COPY $FACTOR_BINARY $FACTOR_BINARY.bak
+ $COPY $FACTOR_LIBRARY $FACTOR_LIBRARY.bak
+ $COPY $BOOT_IMAGE $BOOT_IMAGE.bak
+ $COPY $FACTOR_IMAGE $FACTOR_IMAGE.bak
+ $ECHO "Done with backup."
+}
+
check_makefile_exists() {
if [[ ! -e "Makefile" ]] ; then
echo ""
update_boot_images() {
echo "Deleting old images..."
- rm checksums.txt* > /dev/null 2>&1
- rm $BOOT_IMAGE.* > /dev/null 2>&1
- rm temp/staging.*.image > /dev/null 2>&1
+ $DELETE checksums.txt* > /dev/null 2>&1
+ # delete boot images with one or two characters after the dot
+ $DELETE $BOOT_IMAGE.{?,??} > /dev/null 2>&1
+ $DELETE temp/staging.*.image > /dev/null 2>&1
if [[ -f $BOOT_IMAGE ]] ; then
get_url http://factorcode.org/images/latest/checksums.txt
factorcode_md5=`cat checksums.txt|grep $BOOT_IMAGE|cut -f2 -d' '`;
if [[ "$factorcode_md5" == "$disk_md5" ]] ; then
echo "Your disk boot image matches the one on factorcode.org."
else
- rm $BOOT_IMAGE > /dev/null 2>&1
+ $DELETE $BOOT_IMAGE > /dev/null 2>&1
get_boot_image;
fi
else
update() {
get_config_info
git_pull_factorcode
+ backup_factor
make_clean
make_factor
}
}
refresh_image() {
- ./$FACTOR_BINARY -script -e="USE: vocabs.loader refresh-all USE: memory save 0 USE: system exit"
+ ./$FACTOR_BINARY -script -e="USE: vocabs.loader USE: system refresh-all USE: memory save 0 exit"
check_ret factor
}
make_boot_image() {
- ./$FACTOR_BINARY -script -e="\"$MAKE_IMAGE_TARGET\" USE: bootstrap.image make-image save 0 USE: system exit"
+ ./$FACTOR_BINARY -script -e="\"$MAKE_IMAGE_TARGET\" USE: system USE: bootstrap.image make-image save 0 exit"
check_ret factor
}
parse_build_info $2
fi
+set_copy
+set_delete
+
case "$1" in
install) install ;;
install-x11) install_build_system_apt; install ;;
"Gives all Factor threads a chance to run."
} }
{ {
- { $code "void factor_sleep(long ms)" }
- "Gives all Factor threads a chance to run for " { $snippet "ms" } " milliseconds."
+ { $code "void factor_sleep(long us)" }
+ "Gives all Factor threads a chance to run for " { $snippet "us" } " microseconds."
} }
} ;
M: array clone (clone) ;
M: array length length>> ;
-M: array nth-unsafe >r >fixnum r> array-nth ;
-M: array set-nth-unsafe >r >fixnum r> set-array-nth ;
+M: array nth-unsafe [ >fixnum ] dip array-nth ;
+M: array set-nth-unsafe [ >fixnum ] dip set-array-nth ;
M: array resize resize-array ;
: >array ( seq -- array ) { } clone-like ;
-M: object new-sequence drop f <array> ;
+M: object new-sequence drop 0 <array> ;
-M: f new-sequence drop dup zero? [ drop f ] [ f <array> ] if ;
-
-M: array like drop dup array? [ >array ] unless ;
+M: f new-sequence drop dup zero? [ drop f ] [ 0 <array> ] if ;
M: array equal?
over array? [ sequence= ] [ 2drop f ] if ;
{ $subsection rename-at }
{ $subsection change-at }
{ $subsection at+ }
+{ $subsection inc-at }
{ $see-also set-at delete-at clear-assoc push-at } ;
ARTICLE: "assocs-conversions" "Associative mapping conversions"
{ $examples
{ $unchecked-example
": discount ( prices n -- newprices )"
- " [ - ] curry assoc-each ;"
+ " [ - ] curry assoc-map ;"
"H{ { \"bananas\" 5 } { \"apples\" 42 } { \"pears\" 17 } }"
"2 discount ."
"H{ { \"bananas\" 3 } { \"apples\" 39 } { \"pears\" 15 } }"
{ $description "Adds " { $snippet "n" } " to the value associated with " { $snippet "key" } "; if there is no value, stores " { $snippet "n" } ", thus behaving as if the value was 0." }
{ $side-effects "assoc" } ;
+HELP: inc-at
+{ $values { "key" object } { "assoc" assoc } }
+{ $description "Adds 1 to the value associated with " { $snippet "key" } "; if there is no value, stores 1." }
+{ $side-effects "assoc" } ;
+
HELP: >alist
{ $values { "assoc" assoc } { "newassoc" "an array of key/value pairs" } }
{ $contract "Converts an associative structure into an association list." }
IN: assocs.tests
USING: kernel math namespaces make tools.test vectors sequences
sequences.private hashtables io prettyprint assocs
-continuations float-arrays ;
+continuations specialized-arrays.double ;
[ t ] [ H{ } dup assoc-subset? ] unit-test
[ f ] [ H{ { 1 3 } } H{ } assoc-subset? ] unit-test
[
H{ { 1.0 1.0 } { 2.0 2.0 } }
] [
- F{ 1.0 2.0 } [ dup ] H{ } map>assoc
+ double-array{ 1.0 2.0 } [ dup ] H{ } map>assoc
] unit-test
[ { 3 } ] [
GENERIC: >alist ( assoc -- newassoc )
: (assoc-each) ( assoc quot -- seq quot' )
- >r >alist r> [ first2 ] prepose ; inline
+ [ >alist ] dip [ first2 ] prepose ; inline
: assoc-find ( assoc quot -- key value ? )
(assoc-each) find swap [ first2 t ] [ drop f f f ] if ; inline
(assoc-each) each ; inline
: assoc>map ( assoc quot exemplar -- seq )
- >r accumulator >r assoc-each r> r> like ; inline
+ [ accumulator [ assoc-each ] dip ] dip like ; inline
: assoc-map-as ( assoc quot exemplar -- newassoc )
- >r [ 2array ] compose V{ } assoc>map r> assoc-like ; inline
+ [ [ 2array ] compose V{ } assoc>map ] dip assoc-like ; inline
: assoc-map ( assoc quot -- newassoc )
over assoc-map-as ; inline
: assoc-push-if ( key value quot accum -- )
- >r 2keep r> roll
- [ >r 2array r> push ] [ 3drop ] if ; inline
+ [ 2keep rot ] dip swap
+ [ [ 2array ] dip push ] [ 3drop ] if ; inline
: assoc-pusher ( quot -- quot' accum )
V{ } clone [ [ assoc-push-if ] 2curry ] keep ; inline
+: assoc-filter-as ( assoc quot exemplar -- subassoc )
+ [ assoc-pusher [ assoc-each ] dip ] dip assoc-like ; inline
+
: assoc-filter ( assoc quot -- subassoc )
- over >r assoc-pusher >r assoc-each r> r> assoc-like ; inline
+ over assoc-filter-as ; inline
: assoc-contains? ( assoc quot -- ? )
assoc-find 2nip ; inline
3drop f
] [
3dup nth-unsafe at*
- [ >r 3drop r> ] [ drop >r 1- r> (assoc-stack) ] if
+ [ [ 3drop ] dip ] [ drop [ 1- ] dip (assoc-stack) ] if
] if ; inline recursive
: assoc-stack ( key seq -- value )
- dup length 1- swap (assoc-stack) ;
+ dup length 1- swap (assoc-stack) ; flushable
: assoc-subset? ( assoc1 assoc2 -- ? )
[ swapd at* [ = ] [ 2drop f ] if ] curry assoc-all? ;
: assoc-hashcode ( n assoc -- code )
[
- >r over r> hashcode* 2/ >r dupd hashcode* r> bitxor
+ [ over ] dip hashcode* 2/ [ dupd hashcode* ] dip bitxor
] { } assoc>map hashcode* ;
: assoc-intersect ( assoc1 assoc2 -- intersection )
swap [ swapd set-at ] curry assoc-each ;
: assoc-union ( assoc1 assoc2 -- union )
- 2dup [ assoc-size ] bi@ + pick new-assoc
- [ rot update ] keep [ swap update ] keep ;
+ [ [ [ assoc-size ] bi@ + ] [ drop ] 2bi new-assoc ] 2keep
+ [ dupd update ] bi@ ;
: assoc-combine ( seq -- union )
H{ } clone [ dupd update ] reduce ;
: cache ( key assoc quot -- value )
2over at* [
- >r 3drop r>
+ [ 3drop ] dip
] [
- drop pick rot >r >r call dup r> r> set-at
+ drop pick rot [ call dup ] 2dip set-at
] if ; inline
: change-at ( key assoc quot -- )
- [ >r at r> call ] 3keep drop set-at ; inline
+ [ [ at ] dip call ] 3keep drop set-at ; inline
+
+: at+ ( n key assoc -- ) [ 0 or + ] change-at ; inline
-: at+ ( n key assoc -- )
- [ 0 or + ] change-at ;
+: inc-at ( key assoc -- ) [ 1 ] 2dip at+ ; inline
: map>assoc ( seq quot exemplar -- assoc )
- >r [ 2array ] compose { } map-as r> assoc-like ; inline
+ [ [ 2array ] compose { } map-as ] dip assoc-like ; inline
: extract-keys ( seq assoc -- subassoc )
[ [ dupd at ] curry ] keep map>assoc ;
M: sequence set-at
2dup search-alist
[ 2nip set-second ]
- [ drop >r swap 2array r> push ] if ;
+ [ drop [ swap 2array ] dip push ] if ;
M: sequence new-assoc drop <vector> ;
M: sequence assoc-size length ;
M: sequence assoc-clone-like
- >r >alist r> clone-like ;
+ [ >alist ] dip clone-like ;
M: sequence assoc-like
- >r >alist r> like ;
+ [ >alist ] dip like ;
M: sequence >alist ;
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: alien arrays byte-arrays generic hashtables
-hashtables.private io kernel math math.order namespaces make
-parser sequences strings vectors words quotations assocs layouts
-classes classes.builtin classes.tuple classes.tuple.private
-kernel.private vocabs vocabs.loader source-files definitions
-slots classes.union classes.intersection classes.predicate
-compiler.units bootstrap.image.private io.files accessors
-combinators ;
+hashtables.private io kernel math math.private math.order
+namespaces make parser sequences strings vectors words
+quotations assocs layouts classes classes.builtin classes.tuple
+classes.tuple.private kernel.private vocabs vocabs.loader
+source-files definitions slots classes.union
+classes.intersection classes.predicate compiler.units
+bootstrap.image.private io.files accessors combinators ;
IN: bootstrap.primitives
"Creating primitives and basic runtime structures..." print flush
"alien.accessors"
"arrays"
"byte-arrays"
- "byte-vectors"
"classes.private"
"classes.tuple"
"classes.tuple.private"
} [ create-vocab drop ] each
! Builtin classes
-: define-builtin-predicate ( class -- )
- dup class>type [ builtin-instance? ] curry define-predicate ;
-
: lookup-type-number ( word -- n )
global [ target-word ] bind type-number ;
[ "slots" set-word-prop ] [ define-accessors ] 2bi ;
: define-builtin ( symbol slotspec -- )
- >r [ define-builtin-predicate ] keep
- r> define-builtin-slots ;
+ [ [ define-builtin-predicate ] keep ] dip define-builtin-slots ;
"fixnum" "math" create register-builtin
"bignum" "math" create register-builtin
! A predicate class used for declarations
"array-capacity" "sequences.private" create
"fixnum" "math" lookup
-0 bootstrap-max-array-capacity <fake-bignum> [ between? ] 2curry
+[
+ [ dup 0 fixnum>= ] %
+ bootstrap-max-array-capacity <fake-bignum> [ fixnum<= ] curry ,
+ [ [ drop f ] if ] %
+] [ ] make
define-predicate-class
+"array-capacity" "sequences.private" lookup
+[ >fixnum ] bootstrap-max-array-capacity <fake-bignum> [ fixnum-bitand ] curry append
+"coercer" set-word-prop
+
! Catch-all class for providing a default method.
"object" "kernel" create
[ f f { } intersection-class define-class ]
[ f "inline" set-word-prop ]
[ make-flushable ]
[ ]
- [ tuple-layout [ <tuple-boa> ] curry ]
+ [
+ [
+ callable instance-check-quot %
+ tuple-layout ,
+ \ <tuple-boa> ,
+ ] [ ] make
+ ]
} cleave
(( obj quot -- curry )) define-declared
[ f "inline" set-word-prop ]
[ make-flushable ]
[ ]
- [ tuple-layout [ <tuple-boa> ] curry ]
+ [
+ [
+ callable instance-check-quot [ dip ] curry %
+ callable instance-check-quot %
+ tuple-layout ,
+ \ <tuple-boa> ,
+ ] [ ] make
+ ]
} cleave
(( quot1 quot2 -- compose )) define-declared
{
{ "(execute)" "words.private" }
{ "(call)" "kernel.private" }
+ { "both-fixnums?" "math.private" }
{ "fixnum+fast" "math.private" }
{ "fixnum-fast" "math.private" }
{ "fixnum*fast" "math.private" }
{ "fixnum-bitnot" "math.private" }
{ "fixnum-mod" "math.private" }
{ "fixnum-shift-fast" "math.private" }
+ { "fixnum/i-fast" "math.private" }
+ { "fixnum/mod-fast" "math.private" }
{ "fixnum<" "math.private" }
{ "fixnum<=" "math.private" }
{ "fixnum>" "math.private" }
! Primitive words
: make-primitive ( word vocab n -- )
- >r create dup reset-word r>
+ [ create dup reset-word ] dip
[ do-primitive ] curry [ ] like define ;
{
{ "exit" "system" }
{ "data-room" "memory" }
{ "code-room" "memory" }
- { "millis" "system" }
+ { "micros" "system" }
{ "modify-code-heap" "compiler.units" }
{ "dlopen" "alien" }
{ "dlsym" "alien" }
{ "dlclose" "alien" }
{ "<byte-array>" "byte-arrays" }
+ { "(byte-array)" "byte-arrays" }
{ "<displaced-alien>" "alien" }
{ "alien-signed-cell" "alien.accessors" }
{ "set-alien-signed-cell" "alien.accessors" }
{ "alien-address" "alien" }
{ "set-slot" "slots.private" }
{ "string-nth" "strings.private" }
- { "set-string-nth" "strings.private" }
+ { "set-string-nth-fast" "strings.private" }
+ { "set-string-nth-slow" "strings.private" }
{ "resize-array" "arrays" }
{ "resize-string" "strings" }
{ "<array>" "arrays" }
{ "dll-valid?" "alien" }
{ "unimplemented" "kernel.private" }
{ "gc-reset" "memory" }
+ { "jit-compile" "quotations" }
+ { "load-locals" "locals.backend" }
}
-[ >r first2 r> make-primitive ] each-index
+[ [ first2 ] dip make-primitive ] each-index
! Bump build number
"build" "kernel" create build 1+ 1quotation define
"math.integers" require
"math.floats" require
"memory" require
-
+
"io.streams.c" require
"vocabs.loader" require
"<PRIVATE"
"BIN:"
"B{"
- "BV{"
"C:"
"CHAR:"
"DEFER:"
IN: byte-arrays.tests\r
-USING: tools.test byte-arrays ;\r
+USING: tools.test byte-arrays sequences kernel ;\r
\r
-[ B{ 1 2 3 0 0 0 } ] [ 6 B{ 1 2 3 } resize-byte-array ] unit-test\r
+[ 6 B{ 1 2 3 } ] [\r
+ 6 B{ 1 2 3 } resize-byte-array\r
+ [ length ] [ 3 head ] bi\r
+] unit-test\r
\r
[ B{ 1 2 } ] [ 2 B{ 1 2 3 4 5 6 7 8 9 } resize-byte-array ] unit-test\r
\r
M: byte-array nth-unsafe swap >fixnum alien-unsigned-1 ;
M: byte-array set-nth-unsafe swap >fixnum set-alien-unsigned-1 ;
: >byte-array ( seq -- byte-array ) B{ } clone-like ; inline
-M: byte-array like drop dup byte-array? [ >byte-array ] unless ;
-M: byte-array new-sequence drop <byte-array> ;
+M: byte-array new-sequence drop (byte-array) ;
M: byte-array equal?
over byte-array? [ sequence= ] [ 2drop f ] if ;
+++ /dev/null
-USING: arrays byte-arrays help.markup help.syntax kernel\r
-byte-vectors.private combinators ;\r
-IN: byte-vectors\r
-\r
-ARTICLE: "byte-vectors" "Byte vectors"\r
-"A byte vector is a resizable mutable sequence of unsigned bytes. Byte vector words are found in the " { $vocab-link "byte-vectors" } " vocabulary."\r
-$nl\r
-"Byte vectors form a class:"\r
-{ $subsection byte-vector }\r
-{ $subsection byte-vector? }\r
-"Creating byte vectors:"\r
-{ $subsection >byte-vector }\r
-{ $subsection <byte-vector> }\r
-"Literal syntax:"\r
-{ $subsection POSTPONE: BV{ }\r
-"If you don't care about initial capacity, a more elegant way to create a new byte vector is to write:"\r
-{ $code "BV{ } clone" } ;\r
-\r
-ABOUT: "byte-vectors"\r
-\r
-HELP: byte-vector\r
-{ $description "The class of resizable byte vectors. See " { $link "byte-vectors" } " for information." } ;\r
-\r
-HELP: <byte-vector>\r
-{ $values { "n" "a positive integer specifying initial capacity" } { "byte-vector" byte-vector } }\r
-{ $description "Creates a new byte vector that can hold " { $snippet "n" } " bytes before resizing." } ;\r
-\r
-HELP: >byte-vector\r
-{ $values { "seq" "a sequence" } { "byte-vector" byte-vector } }\r
-{ $description "Outputs a freshly-allocated byte vector with the same elements as a given sequence." }\r
-{ $errors "Throws an error if the sequence contains elements other than integers." } ;\r
-\r
-HELP: BV{\r
-{ $syntax "BV{ elements... }" }\r
-{ $values { "elements" "a list of bytes" } }\r
-{ $description "Marks the beginning of a literal byte vector. Literal byte vectors are terminated by " { $link POSTPONE: } } "." } \r
-{ $examples { $code "BV{ 1 2 3 12 }" } } ;\r
+++ /dev/null
-IN: byte-vectors.tests\r
-USING: tools.test byte-vectors vectors sequences kernel\r
-prettyprint ;\r
-\r
-[ 0 ] [ 123 <byte-vector> length ] unit-test\r
-\r
-: do-it\r
- 123 [ over push ] each ;\r
-\r
-[ t ] [\r
- 3 <byte-vector> do-it\r
- 3 <vector> do-it sequence=\r
-] unit-test\r
-\r
-[ t ] [ BV{ } byte-vector? ] unit-test\r
-\r
-[ "BV{ }" ] [ BV{ } unparse ] unit-test\r
+++ /dev/null
-! Copyright (C) 2008 Slava Pestov.\r
-! See http://factorcode.org/license.txt for BSD license.\r
-USING: arrays kernel kernel.private math sequences\r
-sequences.private growable byte-arrays ;\r
-IN: byte-vectors\r
-\r
-TUPLE: byte-vector\r
-{ underlying byte-array }\r
-{ length array-capacity } ;\r
-\r
-: <byte-vector> ( n -- byte-vector )\r
- <byte-array> 0 byte-vector boa ; inline\r
-\r
-: >byte-vector ( seq -- byte-vector )\r
- T{ byte-vector f B{ } 0 } clone-like ;\r
-\r
-M: byte-vector like\r
- drop dup byte-vector? [\r
- dup byte-array?\r
- [ dup length byte-vector boa ] [ >byte-vector ] if\r
- ] unless ;\r
-\r
-M: byte-vector new-sequence\r
- drop [ <byte-array> ] [ >fixnum ] bi byte-vector boa ;\r
-\r
-M: byte-vector equal?\r
- over byte-vector? [ sequence= ] [ 2drop f ] if ;\r
-\r
-M: byte-array new-resizable drop <byte-vector> ;\r
-\r
-INSTANCE: byte-vector growable\r
+++ /dev/null
-Growable byte arrays
+++ /dev/null
-collections
! Copyright (c) 2008 Slava Pestov
! See http://factorcode.org/license.txt for BSD license.
-USING: sequences math.parser io io.streams.byte-array
-io.encodings.binary io.files kernel ;
+USING: sequences math.parser io io.encodings.binary io.files
+kernel ;
IN: checksums
MIXIN: checksum
GENERIC: checksum-lines ( lines checksum -- value )
-M: checksum checksum-bytes >r binary <byte-reader> r> checksum-stream ;
+M: checksum checksum-stream
+ [ contents ] dip checksum-bytes ;
-M: checksum checksum-stream >r contents r> checksum-bytes ;
-
-M: checksum checksum-lines >r B{ CHAR: \n } join r> checksum-bytes ;
+M: checksum checksum-lines
+ [ B{ CHAR: \n } join ] dip checksum-bytes ;
: checksum-file ( path checksum -- value )
- >r binary <file-reader> r> checksum-stream ;
+ [ binary <file-reader> ] dip checksum-stream ;
: hex-string ( seq -- str )
[ >hex 2 CHAR: 0 pad-left ] { } map-as concat ;
256 [
8 [
- dup even? >r 2/ r> [ crc32-polynomial bitxor ] unless
+ [ 2/ ] [ even? ] bi [ crc32-polynomial bitxor ] unless
] times >bignum
] map 0 crc32-table copy
INSTANCE: crc32 checksum
-: init-crc32 drop >r HEX: ffffffff dup r> ; inline
+: init-crc32 drop [ HEX: ffffffff dup ] dip ; inline
: finish-crc32 bitxor 4 >be ; inline
\r
ARTICLE: "class-operations" "Class operations"\r
"Set-theoretic operations on classes:"\r
+{ $subsection class= }\r
{ $subsection class< }\r
{ $subsection class<= }\r
{ $subsection class-and }\r
\ flatten-class must-infer\r
\ flatten-builtin-class must-infer\r
\r
-: class-and* ( cls1 cls2 cls3 -- ? ) >r class-and r> class= ;\r
+: class-and* ( cls1 cls2 cls3 -- ? ) [ class-and ] dip class= ;\r
\r
-: class-or* ( cls1 cls2 cls3 -- ? ) >r class-or r> class= ;\r
+: class-or* ( cls1 cls2 cls3 -- ? ) [ class-or ] dip class= ;\r
\r
[ t ] [ object object object class-and* ] unit-test\r
[ t ] [ fixnum object fixnum class-and* ] unit-test\r
20 [ random-boolean-op ] [ ] replicate-as dup .\r
[ infer in>> [ random-boolean ] replicate dup . ] keep\r
\r
- [ >r [ ] each r> call ] 2keep\r
+ [ [ [ ] each ] dip call ] 2keep\r
\r
- >r [ boolean>class ] each r> [ boolean-op>class-op ] map call object class=\r
+ [ [ boolean>class ] each ] dip [ boolean-op>class-op ] map call object class=\r
\r
=\r
] unit-test\r
C: <anonymous-complement> anonymous-complement\r
\r
: 2cache ( key1 key2 assoc quot -- value )\r
- >r >r 2array r> [ first2 ] r> compose cache ; inline\r
+ [ 2array ] 2dip [ first2 ] prepose cache ; inline\r
\r
GENERIC: valid-class? ( obj -- ? )\r
\r
swap superclass dup [ swap class<= ] [ 2drop f ] if ;\r
\r
: left-anonymous-union<= ( first second -- ? )\r
- >r members>> r> [ class<= ] curry all? ;\r
+ [ members>> ] dip [ class<= ] curry all? ;\r
\r
: right-anonymous-union<= ( first second -- ? )\r
members>> [ class<= ] with contains? ;\r
\r
: left-anonymous-intersection<= ( first second -- ? )\r
- >r participants>> r> [ class<= ] curry contains? ;\r
+ [ participants>> ] dip [ class<= ] curry contains? ;\r
\r
: right-anonymous-intersection<= ( first second -- ? )\r
participants>> [ class<= ] with all? ;\r
} cond ;\r
\r
: left-anonymous-complement<= ( first second -- ? )\r
- >r normalize-complement r> class<= ;\r
+ [ normalize-complement ] dip class<= ;\r
\r
PREDICATE: nontrivial-anonymous-complement < anonymous-complement\r
class>> {\r
: sort-classes ( seq -- newseq )\r
[ [ name>> ] compare ] sort >vector\r
[ dup empty? not ]\r
- [ dup largest-class >r over delete-nth r> ]\r
+ [ dup largest-class [ over delete-nth ] dip ]\r
[ ] produce nip ;\r
\r
: min-class ( class seq -- class/f )\r
! See http://factorcode.org/license.txt for BSD license.
USING: accessors classes classes.algebra words kernel
kernel.private namespaces sequences math math.private
-combinators assocs ;
+combinators assocs quotations ;
IN: classes.builtin
SYMBOL: builtins
PREDICATE: builtin-class < class
"metaclass" word-prop builtin-class eq? ;
-: type>class ( n -- class ) builtins get-global nth ;
-
: class>type ( class -- n ) "type" word-prop ; foldable
+PREDICATE: lo-tag-class < builtin-class class>type 7 <= ;
+
+PREDICATE: hi-tag-class < builtin-class class>type 7 > ;
+
+: type>class ( n -- class ) builtins get-global nth ;
+
: bootstrap-type>class ( n -- class ) builtins get nth ;
M: hi-tag class hi-tag type>class ;
M: builtin-class rank-class drop 0 ;
-: builtin-instance? ( object n -- ? )
- #! 7 == tag-mask get
- #! 3 == hi-tag tag-number
- dup 7 fixnum<= [ swap tag eq? ] [
- swap dup tag 3 eq?
- [ hi-tag eq? ] [ 2drop f ] if
- ] if ; inline
+GENERIC: define-builtin-predicate ( class -- )
+
+M: lo-tag-class define-builtin-predicate
+ dup class>type [ eq? ] curry [ tag ] prepend define-predicate ;
+
+M: hi-tag-class define-builtin-predicate
+ dup class>type [ eq? ] curry [ hi-tag ] prepend 1quotation
+ [ dup tag 3 eq? ] [ [ drop f ] if ] surround
+ define-predicate ;
+
+M: lo-tag-class instance? [ tag ] [ class>type ] bi* eq? ;
-M: builtin-class instance?
- class>type builtin-instance? ;
+M: hi-tag-class instance?
+ over tag 3 eq? [ [ hi-tag ] [ class>type ] bi* eq? ] [ 2drop f ] if ;
M: builtin-class (flatten-class) dup set ;
[ drop t ]
] [
unclip "predicate" word-prop swap [
- "predicate" word-prop [ dup ] swap [ not ] 3append
+ "predicate" word-prop [ dup ] [ not ] surround
[ drop f ]
] { } map>assoc alist>quot
] if-empty ;
M: intersection-class update-class define-intersection-predicate ;
: define-intersection-class ( class participants -- )
- [ f f rot intersection-class define-class ]
+ [ [ f f ] dip intersection-class define-class ]
[ drop update-classes ]
2bi ;
bi
] if ;
-TUPLE: check-mixin-class mixin ;
+TUPLE: check-mixin-class class ;
: check-mixin-class ( mixin -- mixin )
dup mixin-class? [
{ $subsection POSTPONE: C: }
"By convention, construction logic is encapsulated in a word named after the tuple class surrounded in angle brackets; for example, the constructor word for a " { $snippet "point" } " class might be named " { $snippet "<point>" } "."
$nl
-"Constructors play a part in enforcing the invariant that slot values must always match slot declarations. The " { $link new } " word fills in the tuple will initial values, and " { $link boa } " ensures that the values on the stack match the corresponding slot declarations. See " { $link "tuple-declarations" } "."
+"Constructors play a part in enforcing the invariant that slot values must always match slot declarations. The " { $link new } " word fills in the tuple with initial values, and " { $link boa } " ensures that the values on the stack match the corresponding slot declarations. See " { $link "tuple-declarations" } "."
$nl
"All tuple construction should be done through constructor words, and construction primitives should be encapsulated and never called outside of the vocabulary where the class is defined, because this encourages looser coupling. For example, a constructor word could be changed to use memoization instead of always constructing a new instance, or it could be changed to construt a different class, without breaking callers."
$nl
"{ alpha integer initial: 1 } ;"
""
"! The following two are equivalent"
- "C: <rgba> rgba"
+ "C: <rgba> color"
": <rgba> color boa ;"
""
"! We can define constructors which call other constructors"
- ": <rgb> 1 <rgba> ;"
+ ": <rgb> ( r g b -- color ) 1 <rgba> ;"
""
"! The following two are equivalent; note the initial value"
": <color> ( -- color ) color new ;"
ARTICLE: "tuple-examples" "Tuple examples"
"An example:"
-{ $code "TUPLE: employee name salary position ;" }
+{ $code "TUPLE: employee name position salary ;" }
"This defines a class word named " { $snippet "employee" } ", a predicate " { $snippet "employee?" } ", and the following slot accessors:"
{ $table
{ "Reader" "Writer" "Setter" "Changer" }
" checks counter check boa ;"
""
": biweekly-paycheck ( employee -- check )"
- " dup name>> swap salary>> 26 / <check> ;"
+ " [ name>> ] [ salary>> 26 / ] bi <check> ;"
}
"An example of using a changer:"
{ $code
[ t ] [ "forget-accessors-test" "classes.tuple.tests" lookup class? ] unit-test
: accessor-exists? ( class name -- ? )
- >r "forget-accessors-test" "classes.tuple.tests" lookup r>
+ [ "forget-accessors-test" "classes.tuple.tests" lookup ] dip
">>" append "accessors" lookup method >boolean ;
[ t ] [ "x" accessor-exists? ] unit-test
: tuple>array ( tuple -- array )
prepare-tuple>array
- >r copy-tuple-slots r>
+ [ copy-tuple-slots ] dip
first prefix ;
: tuple-slots ( tuple -- seq )
2drop f
] if ; inline
-: tuple-instance-1? ( object class -- ? )
- swap dup tuple? [
- layout-of 7 slot eq?
- ] [ 2drop f ] if ; inline
+: tuple-predicate-quot/1 ( class -- quot )
+ #! Fast path for tuples with no superclass
+ [ ] curry [ layout-of 7 slot ] [ eq? ] surround 1quotation
+ [ dup tuple? ] [ [ drop f ] if ] surround ;
: tuple-instance? ( object class offset -- ? )
rot dup tuple? [
: layout-class-offset ( echelon -- n )
2 * 5 + ;
+: tuple-predicate-quot ( class echelon -- quot )
+ layout-class-offset [ tuple-instance? ] 2curry ;
+
: echelon-of ( class -- n )
tuple-layout third ;
: define-tuple-predicate ( class -- )
dup dup echelon-of {
- { 1 [ [ tuple-instance-1? ] curry ] }
- [ layout-class-offset [ tuple-instance? ] 2curry ]
+ { 1 [ tuple-predicate-quot/1 ] }
+ [ tuple-predicate-quot ]
} case define-predicate ;
: class-size ( class -- n )
[
\ dup ,
[ "predicate" word-prop % ]
- [ [ bad-slot-value ] curry , ] bi
+ [ [ literalize , \ bad-slot-value , ] [ ] make , ] bi
\ unless ,
] [ ] make ;
: update-slot ( old-values n class initial -- value )
pick [
- >r >r swap nth dup r> instance? r> swap
+ [ [ swap nth dup ] dip instance? ] dip swap
[ drop ] [ nip ] if
- ] [ >r 3drop r> ] if ;
+ ] [ [ 3drop ] dip ] if ;
: apply-slot-permutation ( old-values triples -- new-values )
[ first3 update-slot ] with map ;
class-usages [ tuple-class? ] filter ;
: each-subclass ( class quot -- )
- >r subclasses r> each ; inline
+ [ subclasses ] dip each ; inline
: redefine-tuple-class ( class superclass slots -- )
[
3bi ;
: tuple-class-unchanged? ( class superclass slots -- ? )
- rot tuck [ superclass = ] [ "slots" word-prop = ] 2bi* and ;
+ [ over ] dip
+ [ [ superclass ] [ bootstrap-word ] bi* = ]
+ [ [ "slots" word-prop ] dip = ] 2bi* and ;
: valid-superclass? ( class -- ? )
[ tuple-class? ] [ tuple eq? ] bi or ;
M: tuple hashcode*
[
[ class hashcode ] [ tuple-size ] [ ] tri
- >r rot r> [
+ [ rot ] dip [
swapd array-nth hashcode* sequence-hashcode-step
] 2curry each
] recursive-hashcode ;
ARTICLE: "combinators" "Additional combinators"
"The " { $vocab-link "combinators" } " vocabulary provides a few useful combinators."
$nl
-"A looping combinator:"
-{ $subsection while }
"Generalization of " { $link bi } " and " { $link tri } ":"
{ $subsection cleave }
"Generalization of " { $link 2bi } " and " { $link 2tri } ":"
$nl
"A combinator which can help with implementing methods on " { $link hashcode* } ":"
{ $subsection recursive-hashcode }
-{ $subsection "assertions" }
{ $subsection "combinators-quot" }
{ $see-also "quotations" "dataflow" } ;
-ARTICLE: "assertions" "Assertions"
-"Some words to make assertions easier to enforce:"
-{ $subsection assert }
-{ $subsection assert= }
-"Runtime stack depth checking:"
-{ $subsection assert-depth } ;
-
ABOUT: "combinators"
HELP: cleave
{ $code
"! Equivalent"
"{ [ p ] [ q ] [ r ] [ s ] } spread"
- ">r >r >r p r> q r> r r> s"
+ "[ [ [ p ] dip q ] dip r ] dip s"
}
} ;
{ $values { "n" "a fixnum" } { "array" "an array of quotations" } }
{ $description "Calls the " { $snippet "n" } "th quotation in the array." }
{ $warning "This word is in the " { $vocab-link "kernel.private" } " vocabulary because it is an implementation detail used by the generic word system to accelerate method dispatch. It does not perform type or bounds checks, and user code should not need to call it directly." } ;
-
-HELP: assert-depth
-{ $values { "quot" "a quotation" } }
-{ $description "Runs a quotation. Throws an error if the total number of elements on the stack is not the same before and after the quotation runs." } ;
! spread
: spread>quot ( seq -- quot )
- [ ] [
- [ dup empty? [ [ >r ] swap [ r> ] 3append ] unless ] dip
- append
- ] reduce ;
+ [ ] [ [ dup empty? [ [ dip ] curry ] unless ] dip append ] reduce ;
: spread ( objs... seq -- )
spread>quot call ;
[ rot \ if 3array append [ ] like ] assoc-each ;
: cond>quot ( assoc -- quot )
- [ dup callable? [ [ t ] swap 2array ] when ] map
+ [ dup pair? [ [ t ] swap 2array ] unless ] map
reverse [ no-cond ] swap alist>quot ;
! case
drop [ swap adjoin ] curry each
] [
[
- >r 2dup r> hashcode pick length rem rot nth adjoin
+ [ 2dup ] dip hashcode pick length rem rot nth adjoin
] each 2drop
] if ;
next-power-of-2 swap [ nip clone ] curry map ;
: distribute-buckets ( alist initial quot -- buckets )
- swapd [ >r dup first r> call 2array ] curry map
+ swapd [ [ dup first ] dip call 2array ] curry map
[ length <buckets> dup ] keep
[ first2 (distribute-buckets) ] with each ; inline
: hash-case-table ( default assoc -- array )
V{ } [ 1array ] distribute-buckets
- [ [ >r literalize r> ] assoc-map linear-case-quot ] with map ;
+ [ [ [ literalize ] dip ] assoc-map linear-case-quot ] with map ;
: hash-dispatch-quot ( table -- quot )
[ length 1- [ fixnum-bitand ] curry ] keep
{ [ dup [ length 4 <= ] [ [ word? ] contains? ] bi or ] [ drop linear-case-quot ] }
{ [ dup contiguous-range? ] [ drop dispatch-case-quot ] }
{ [ dup [ wrapper? ] contains? not ] [ drop hash-case-quot ] }
- { [ dup [ wrapper? ] all? ] [ drop [ >r wrapped>> r> ] assoc-map hash-case-quot ] }
+ { [ dup [ wrapper? ] all? ] [ drop [ [ wrapped>> ] dip ] assoc-map hash-case-quot ] }
[ drop linear-case-quot ]
} cond ;
-! assert-depth
-: trim-datastacks ( seq1 seq2 -- seq1' seq2' )
- 2dup [ length ] bi@ min tuck tail >r tail r> ;
-
-ERROR: relative-underflow stack ;
-
-ERROR: relative-overflow stack ;
-
-: assert-depth ( quot -- )
- >r datastack r> dip >r datastack r>
- 2dup [ length ] compare {
- { +lt+ [ trim-datastacks nip relative-underflow ] }
- { +eq+ [ 2drop ] }
- { +gt+ [ trim-datastacks drop relative-overflow ] }
- } case ; inline
-
! recursive-hashcode
: recursive-hashcode ( n obj quot -- code )
pick 0 <= [ 3drop 0 ] [ rot 1- -rot call ] if ; inline
: errors-of-type ( type -- assoc )
compiler-errors get-global
- swap [ >r nip compiler-error-type r> eq? ] curry
+ swap [ [ nip compiler-error-type ] dip eq? ] curry
assoc-filter ;
: compiler-errors. ( type -- )
{ $subsection continue-with }
"Continuations as control-flow:"
{ $subsection attempt-all }
+{ $subsection retry }
{ $subsection with-return }
"Reflecting the datastack:"
{ $subsection with-datastack }
+{ $subsection assert-depth }
"Continuations serve as the building block for a number of higher-level abstractions, such as " { $link "errors" } " and " { $link "threads" } "."
{ $subsection "continuations.private" } ;
{ $example "USING: continuations math prettyprint ;" "{ 3 7 } [ + ] with-datastack ." "{ 10 }" }
} ;
+HELP: assert-depth
+{ $values { "quot" "a quotation" } }
+{ $description "Runs a quotation. Throws an error if the quotation attempts to take input values from the stack, or leave outputs on the stack." } ;
+
HELP: <continuation>
{ $description "Constructs a new continuation." }
{ $notes "User code should call " { $link continuation } " instead." } ;
}
} ;
+HELP: retry
+{ $values
+ { "quot" quotation } { "n" null }
+}
+{ $description "Tries the quotation up to " { $snippet "n" } " times until it returns true. Retries the quotation if an exception is thrown or if the quotation returns " { $link f } ". The quotation is expected to have side effects that may fail, such as generating a random name for a new file until successful." }
+{ $examples
+ { $unchecked-example "USING: continuations math prettyprint ;"
+ "[ 5 random 0 = ] retry t"
+ "t"
+ }
+} ;
+
+{ attempt-all retry } related-words
+
HELP: return
{ $description "Returns early from a quotation by reifying the continuation captured by " { $link with-return } " ; execution is resumed starting immediately after " { $link with-return } "." } ;
#! ( value f r:capture r:restore )
#! Execution begins right after the call to 'continuation'.
#! The 'restore' branch is taken.
- >r >r dummy-1 continuation r> r> [ dummy-2 ] prepose ?if ; inline
+ [ dummy-1 continuation ] 2dip [ dummy-2 ] prepose ?if ; inline
: callcc0 ( quot -- ) [ drop ] ifcc ; inline
set-catchstack
set-namestack
set-retainstack
- >r set-datastack r>
+ [ set-datastack ] dip
set-callstack ;
: (continue-with) ( obj continuation -- )
set-catchstack
set-namestack
set-retainstack
- >r set-datastack drop 4 getenv f 4 setenv f r>
+ [ set-datastack drop 4 getenv f 4 setenv f ] dip
set-callstack ;
PRIVATE>
] 3 (throw)
] callcc1 2nip ;
+: assert-depth ( quot -- )
+ { } swap with-datastack { } assert= ; inline
+
GENERIC: compute-restarts ( error -- seq )
<PRIVATE
c> continue-with ;
: recover ( try recovery -- )
- >r [ swap >c call c> drop ] curry r> ifcc ; inline
+ [ [ swap >c call c> drop ] curry ] dip ifcc ; inline
: ignore-errors ( quot -- )
[ drop ] recover ; inline
: cleanup ( try cleanup-always cleanup-error -- )
- over >r compose [ dip rethrow ] curry
- recover r> call ; inline
+ [ compose [ dip rethrow ] curry recover ] [ drop ] 2bi call ; inline
ERROR: attempt-all-error ;
] { } make peek swap [ rethrow ] when
] if ; inline
+: retry ( quot: ( -- ? ) n -- ) swap [ drop ] prepose attempt-all ; inline
+
TUPLE: condition error restarts continuation ;
C: <condition> condition ( error restarts cc -- condition )
M: string effect>string ;
M: word effect>string name>> ;
M: integer effect>string number>string ;
-M: pair effect>string first2 [ effect>string ] bi@ ": " swap 3append ;
+M: pair effect>string first2 [ effect>string ] bi@ ": " glue ;
: stack-picture ( seq -- string )
dup integer? [ "object" <repetition> ] when
{ sort-classes order } related-words
HELP: (call-next-method)
-{ $values { "class" class } { "generic" generic } }
+{ $values { "method" method-body } }
{ $description "Low-level word implementing " { $link POSTPONE: call-next-method } "." }
{ $notes "In most cases, " { $link POSTPONE: call-next-method } " should be used instead." } ;
+
+HELP: no-next-method
+{ $error-description "Thrown by " { $link POSTPONE: call-next-method } " if the current method is already the least specific method." }
+{ $examples
+ "The following code throws this error:"
+ { $code
+ "GENERIC: error-test ( object -- )"
+ ""
+ "M: number error-test 3 + call-next-method ;"
+ ""
+ "M: integer error-test recip call-next-method ;"
+ ""
+ "123 error-test"
+ }
+ "This results in the method on " { $link integer } " being called, which then calls the method on " { $link number } ". The latter then calls " { $link POSTPONE: call-next-method } ", however there is no method less specific than the method on " { $link number } " and so an error is thrown."
+} ;
GENERIC: next-method-quot* ( class generic combination -- quot )
-: next-method-quot ( class generic -- quot )
+: next-method-quot ( method -- quot )
next-method-quot-cache get [
- dup "combination" word-prop next-method-quot*
- ] 2cache ;
+ [ "method-class" word-prop ]
+ [
+ "method-generic" word-prop
+ dup "combination" word-prop
+ ] bi next-method-quot*
+ ] cache ;
+
+ERROR: no-next-method method ;
-: (call-next-method) ( class generic -- )
- next-method-quot call ;
+: (call-next-method) ( method -- )
+ dup next-method-quot [ call ] [ no-next-method ] ?if ;
TUPLE: check-method class generic ;
3tri ; inline
: method-word-name ( class word -- string )
- [ name>> ] bi@ "=>" swap 3append ;
+ [ name>> ] bi@ "=>" glue ;
PREDICATE: method-body < word
"method-generic" word-prop >boolean ;
HELP: math-method
{ $values { "word" generic } { "class1" class } { "class2" class } { "quot" quotation } }
{ $description "Generates a definition for " { $snippet "word" } " when the two inputs are instances of " { $snippet "class1" } " and " { $snippet "class2" } ", respectively." }
-{ $examples { $example "USING: generic.math math prettyprint ;" "\\ + fixnum float math-method ." "[ [ >float ] dip float=>+ ]" } } ;
+{ $examples { $example "USING: generic.math math prettyprint ;" "\\ + fixnum float math-method ." "[ { fixnum float } declare [ >float ] dip float=>+ ]" } } ;
HELP: math-class
{ $class-description "The class of subtypes of " { $link number } " which are not " { $link null } "." } ;
: math-class-max ( class1 class2 -- class )
[ math-class<=> ] most ;
-: math-class-min ( class1 class2 -- class )
- [ swap math-class<=> ] most ;
-
: (math-upgrade) ( max class -- quot )
dupd = [ drop [ ] ] [ "coercer" word-prop [ ] or ] if ;
: math-upgrade ( class1 class2 -- quot )
[ math-class-max ] 2keep
- >r over r> (math-upgrade) >r (math-upgrade)
- dup empty? [ [ dip ] curry [ ] like ] unless
- r> append ;
+ [ over ] dip (math-upgrade) [
+ (math-upgrade)
+ dup empty? [ [ dip ] curry [ ] like ] unless
+ ] dip append ;
ERROR: no-math-method left right generic ;
: math-method ( word class1 class2 -- quot )
2dup and [
- 2dup math-upgrade >r
- math-class-max over order min-class applicable-method
- r> prepend
+ [
+ 2dup 2array , \ declare ,
+ 2dup math-upgrade %
+ math-class-max over order min-class applicable-method %
+ ] [ ] make
] [
2drop object-method
] if ;
: math-vtable ( picker quot -- quot )
[
- swap picker set
- picker get , [ tag 0 eq? ] %
- num-tags get swap [ bootstrap-type>class ] prepose map
- unclip ,
- [
- picker get , [ tag 1 fixnum-fast ] % , \ dispatch ,
- ] [ ] make , \ if ,
+ [ , \ tag , ]
+ [ num-tags get swap [ bootstrap-type>class ] prepose map , ] bi*
+ \ dispatch ,
] [ ] make ; inline
TUPLE: math-combination ;
M: math-combination perform-combination
drop
dup
- \ over [
- dup math-class? [
- \ dup [ >r 2dup r> math-method ] math-vtable
- ] [
- over object-method
- ] if nip
- ] math-vtable nip define ;
+ [
+ [ 2dup both-fixnums? ] %
+ dup fixnum bootstrap-word dup math-method ,
+ \ over [
+ dup math-class? [
+ \ dup [ [ 2dup ] dip math-method ] math-vtable
+ ] [
+ over object-method
+ ] if nip
+ ] math-vtable nip ,
+ \ if ,
+ ] [ ] make define ;
PREDICATE: math-generic < generic ( word -- ? )
"combination" word-prop math-combination? ;
: CREATE-METHOD ( -- method )
scan-word bootstrap-word scan-word create-method-in ;
-SYMBOL: current-class
-SYMBOL: current-generic
-
-: with-method-definition ( quot -- parsed )
- [
- [
- [ "method-class" word-prop current-class set ]
- [ "method-generic" word-prop current-generic set ]
- [ ] tri
- ] dip call
- ] with-scope ; inline
+SYMBOL: current-method
+
+: with-method-definition ( method quot -- )
+ over current-method set call current-method off ; inline
: (M:) ( method def -- )
CREATE-METHOD [ parse-definition ] with-method-definition ;
[ over assumed [ engine>quot ] with-variable ] assoc-map ;
: if-small? ( assoc true false -- )
- >r >r dup assoc-size 4 <= r> r> if ; inline
+ [ dup assoc-size 4 <= ] 2dip if ; inline
: linear-dispatch-quot ( alist -- quot )
default get [ drop ] prepend swap
{ 0 [ [ dup ] ] }
{ 1 [ [ over ] ] }
{ 2 [ [ pick ] ] }
- [ 1- (picker) [ >r ] swap [ r> swap ] 3append ]
+ [ 1- (picker) [ dip swap ] curry ]
} case ;
: picker ( -- quot ) \ (dispatch#) get (picker) ;
C: <predicate-dispatch-engine> predicate-dispatch-engine
: class-predicates ( assoc -- assoc )
- [ >r "predicate" word-prop picker prepend r> ] assoc-map ;
+ [ [ "predicate" word-prop picker prepend ] dip ] assoc-map ;
: keep-going? ( assoc -- ? )
assumed get swap second first class<= ;
USING: classes.private generic.standard.engines namespaces make
arrays assocs sequences.private quotations kernel.private
math slots.private math.private kernel accessors words
-layouts sorting sequences ;
+layouts sorting sequences combinators ;
IN: generic.standard.engines.tag
TUPLE: lo-tag-dispatch-engine methods ;
: sort-tags ( assoc -- alist ) >alist sort-keys reverse ;
+: tag-dispatch-test ( tag# -- quot )
+ picker [ tag ] append swap [ eq? ] curry append ;
+
+: tag-dispatch-quot ( alist -- quot )
+ [ default get ] dip
+ [ [ tag-dispatch-test ] dip ] assoc-map
+ alist>quot ;
+
M: lo-tag-dispatch-engine engine>quot
methods>> engines>quots*
- [ >r lo-tag-number r> ] assoc-map
+ [ [ lo-tag-number ] dip ] assoc-map
[
- picker % [ tag ] % [
- sort-tags linear-dispatch-quot
- ] [
- num-tags get direct-dispatch-quot
- ] if-small? %
+ [ sort-tags tag-dispatch-quot ]
+ [ picker % [ tag ] % num-tags get direct-dispatch-quot ]
+ if-small? %
] [ ] make ;
TUPLE: hi-tag-dispatch-engine methods ;
M: hi-tag-dispatch-engine engine>quot
methods>> engines>quots*
- [ >r hi-tag-number r> ] assoc-map
+ [ [ hi-tag-number ] dip ] assoc-map
[
picker % hi-tag-quot % [
sort-tags linear-dispatch-quot
] [
num-tags get , \ fixnum-fast ,
- [ >r num-tags get - r> ] assoc-map
+ [ [ num-tags get - ] dip ] assoc-map
num-hi-tags direct-dispatch-quot
] if-small? %
] [ ] make ;
{ standard-combination hook-combination } related-words
-HELP: no-next-method
-{ $error-description "Thrown by " { $link POSTPONE: call-next-method } " if the current method is already the least specific method." }
-{ $examples
- "The following code throws this error:"
- { $code
- "GENERIC: error-test ( object -- )"
- ""
- "M: number error-test 3 + call-next-method ;"
- ""
- "M: integer error-test recip call-next-method ;"
- ""
- "123 error-test"
- }
- "This results in the method on " { $link integer } " being called, which then calls the method on " { $link number } ". The latter then calls " { $link POSTPONE: call-next-method } ", however there is no method less specific than the method on " { $link number } " and so an error is thrown."
-} ;
-
HELP: inconsistent-next-method
{ $error-description "Thrown by " { $link POSTPONE: call-next-method } " if the values on the stack are not compatible with the current method." }
{ $examples
IN: generic.standard.tests
USING: tools.test math math.functions math.constants
-generic.standard strings sequences arrays kernel accessors
-words float-arrays byte-arrays bit-arrays parser namespaces make
-quotations stack-checker vectors growable hashtables sbufs
-prettyprint byte-vectors bit-vectors float-vectors definitions
-generic sets graphs assocs ;
+generic.standard strings sequences arrays kernel accessors words
+specialized-arrays.double byte-arrays bit-arrays parser
+namespaces make quotations stack-checker vectors growable
+hashtables sbufs prettyprint byte-vectors bit-vectors
+specialized-vectors.double definitions generic sets graphs assocs ;
GENERIC: lo-tag-test ( obj -- obj' )
[ "integer" ] [ 3 big-mix-test ] unit-test
[ "float" ] [ 5.0 big-mix-test ] unit-test
[ "complex" ] [ -1 sqrt big-mix-test ] unit-test
-[ "sequence" ] [ F{ 1.0 2.0 3.0 } big-mix-test ] unit-test
+[ "sequence" ] [ double-array{ 1.0 2.0 3.0 } big-mix-test ] unit-test
[ "sequence" ] [ B{ 1 2 3 } big-mix-test ] unit-test
[ "sequence" ] [ ?{ t f t } big-mix-test ] unit-test
[ "sequence" ] [ SBUF" hello world" big-mix-test ] unit-test
[ "sequence" ] [ V{ "a" "b" } big-mix-test ] unit-test
[ "sequence" ] [ BV{ 1 2 } big-mix-test ] unit-test
[ "sequence" ] [ ?V{ t t f f } big-mix-test ] unit-test
-[ "sequence" ] [ FV{ -0.3 4.6 } big-mix-test ] unit-test
+[ "sequence" ] [ double-vector{ -0.3 4.6 } big-mix-test ] unit-test
[ "string" ] [ "hello" big-mix-test ] unit-test
[ "rectangle" ] [ 1 2 <rectangle> big-mix-test ] unit-test
[ "parallelogram" ] [ 10 4 3 <parallelogram> big-mix-test ] unit-test
M: array small-lo-tag drop "array" ;
-M: float-array small-lo-tag drop "float-array" ;
+M: double-array small-lo-tag drop "double-array" ;
M: byte-array small-lo-tag drop "byte-array" ;
[ "fixnum" ] [ 3 small-lo-tag ] unit-test
-[ "float-array" ] [ F{ 1.0 } small-lo-tag ] unit-test
+[ "double-array" ] [ double-array{ 1.0 } small-lo-tag ] unit-test
! Testing next-method
TUPLE: person ;
[ T{ inconsistent-next-method f ceo salary } = ] must-fail-with
[ intern boa salary ]
-[ T{ no-next-method f intern salary } = ] must-fail-with
+[ no-next-method? ] must-fail-with
! Weird shit
TUPLE: a ;
] change-at ;
: flatten-method ( class method assoc -- )
- >r >r dup flatten-class keys swap r> r> [
- >r spin r> push-method
+ [ dup flatten-class keys swap ] 2dip [
+ [ spin ] dip push-method
] 3curry each ;
: flatten-methods ( assoc -- assoc' )
ERROR: inconsistent-next-method class generic ;
-ERROR: no-next-method class generic ;
-
-: single-next-method-quot ( class generic -- quot )
- [
- [ drop "predicate" word-prop % ]
+: single-next-method-quot ( class generic -- quot/f )
+ 2dup next-method dup [
[
- 2dup next-method
- [ 2nip 1quotation ]
- [ [ no-next-method ] 2curry [ ] like ] if* ,
- ]
- [ [ inconsistent-next-method ] 2curry , ]
- 2tri
- \ if ,
- ] [ ] make ;
+ pick "predicate" word-prop %
+ 1quotation ,
+ [ inconsistent-next-method ] 2curry ,
+ \ if ,
+ ] [ ] make
+ ] [ 3drop f ] if ;
: single-effective-method ( obj word -- method )
[ [ order [ instance? ] with find-last nip ] keep method ]
T{ standard-combination f 0 } define-generic ;
: with-standard ( combination quot -- quot' )
- >r #>> (dispatch#) r> with-variable ; inline
+ [ #>> (dispatch#) ] dip with-variable ; inline
M: standard-generic extra-values drop 0 ;
M: standard-combination next-method-quot*
[
- single-next-method-quot picker prepend
+ single-next-method-quot
+ dup [ picker prepend ] when
] with-standard ;
M: standard-generic effective-method
: with-hook ( combination quot -- quot' )
0 (dispatch#) [
- dip var>> [ get ] curry prepend
+ [ hook-combination ] dip with-variable
] with-variable ; inline
+: prepend-hook-var ( quot -- quot' )
+ hook-combination get var>> [ get ] curry prepend ;
+
M: hook-combination dispatch# drop 0 ;
M: hook-combination method-declaration 2drop [ ] ;
single-effective-method ;
M: hook-combination make-default-method
- [ error-method ] with-hook ;
+ [ error-method prepend-hook-var ] with-hook ;
M: hook-combination perform-combination
- [ drop ] [ [ single-combination ] with-hook ] 2bi define ;
+ [ drop ] [
+ [ single-combination prepend-hook-var ] with-hook
+ ] 2bi define ;
M: hook-combination next-method-quot*
- [ single-next-method-quot ] with-hook ;
+ [
+ single-next-method-quot
+ dup [ prepend-hook-var ] when
+ ] with-hook ;
M: simple-generic definer drop \ GENERIC: f ;
}
"The underlying sequence must implement a generic word:"
{ $subsection resize }
-{ $link "vectors" } ", " { $link "byte-vectors" } " and " { $link "sbufs" } " are implemented using the resizable sequence facility." ;
+{ $link "vectors" } " and " { $link "sbufs" } " are implemented using the resizable sequence facility." ;
ABOUT: "growable"
growable-check
2dup length >= [
2dup capacity >= [ over new-size over expand ] when
- >r >fixnum r>
+ [ >fixnum ] dip
over 1 fixnum+fast over (>>length)
] [
- >r >fixnum r>
+ [ >fixnum ] dip
] if ; inline
M: growable set-nth ensure set-nth-unsafe ;
[ H{ { -1 4 } { -3 16 } { -5 36 } } ] [
H{ { 1 2 } { 3 4 } { 5 6 } }
- [ >r neg r> sq ] assoc-map
+ [ [ neg ] dip sq ] assoc-map
] unit-test
! Bug discovered by littledan
length>> 1 fixnum-fast fixnum-bitand ; inline
: hash@ ( key array -- i )
- >r hashcode >fixnum dup fixnum+fast r> wrap ; inline
+ [ hashcode >fixnum dup fixnum+fast ] dip wrap ; inline
: probe ( array i -- array i )
2 fixnum+fast over wrap ; inline
0 >>count 0 >>deleted drop ; inline
: reset-hash ( n hash -- )
- swap <hash-array> >>array init-hash ;
+ swap <hash-array> >>array init-hash ; inline
: (new-key@) ( key keys i -- keys n empty? )
3dup swap array-nth dup ((empty)) eq? [
M: hashtable delete-at ( key hash -- )
tuck key@ [
- >r >r ((tombstone)) dup r> r> set-nth-pair
+ [ ((tombstone)) dup ] 2dip set-nth-pair
hash-deleted+
] [
3drop
[ count>> ] [ deleted>> ] bi - ;
: rehash ( hash -- )
- dup >alist >r
+ dup >alist [
dup clear-assoc
- r> (rehash) ;
+ ] dip (rehash) ;
M: hashtable set-at ( value key hash -- )
dup ?grow-hash
: push-unsafe ( elt seq -- )
[ length ] keep
[ underlying>> set-array-nth ]
- [ >r 1+ r> (>>length) ]
+ [ [ 1 fixnum+fast { array-capacity } declare ] dip (>>length) ]
2bi ; inline
PRIVATE>
M: hashtable >alist
[ array>> [ length 2/ ] keep ] [ assoc-size <vector> ] bi [
[
- >r
- >r 1 fixnum-shift-fast r>
- [ array-nth ] [ >r 1 fixnum+fast r> array-nth ] 2bi r>
+ [
+ [ 1 fixnum-shift-fast ] dip
+ [ array-nth ] [ [ 1 fixnum+fast ] dip array-nth ] 2bi
+ ] dip
pick tombstone? [ 3drop ] [ [ 2array ] dip push-unsafe ] if
] 2curry each
] keep { } like ;
byte-arrays ;
HELP: io-multiplex
-{ $values { "ms" "a non-negative integer" } }
-{ $contract "Waits up to " { $snippet "ms" } " milliseconds for pending I/O requests to complete." } ;
+{ $values { "us" "a non-negative integer" } }
+{ $contract "Waits up to " { $snippet "us" } " microseconds for pending I/O requests to complete." } ;
HELP: init-io
{ $contract "Initializes the I/O system. Called on startup." } ;
SINGLETON: c-io-backend
-c-io-backend io-backend set-global
+io-backend global [ c-io-backend or ] change-at
HOOK: init-io io-backend ( -- )
[ utf8 <encoder> output-stream set-global ]
[ utf8 <encoder> error-stream set-global ] tri* ;
-HOOK: io-multiplex io-backend ( ms -- )
+HOOK: io-multiplex io-backend ( us -- )
HOOK: normalize-directory io-backend ( str -- newstr )
-USING: help.markup help.syntax ;
+USING: help.markup help.syntax io quotations ;
IN: io.encodings
-ABOUT: "io.encodings"
-
-ARTICLE: "io.encodings" "I/O encodings"
-"Bytes can't be understood in isolation as text. They must be interpreted under a certain encoding. Factor provides utilities for dealing with encoded text by declaring that a stream has a particular encoding, and utilities to encode and decode strings."
-{ $subsection "encodings-descriptors" }
-{ $subsection "encodings-constructors" }
-{ $subsection "io.encodings.string" }
-"New types of encodings can be defined:"
-{ $subsection "encodings-protocol" } ;
-
-ARTICLE: "encodings-constructors" "Manually constructing an encoded stream"
-"The following words can be used to construct encoded streams. Note that they are usually not used directly, but rather by the stream constructors themselves. Most stream constructors take an encoding descriptor as a parameter and internally call these constructors."
-{ $subsection <encoder> }
-{ $subsection <decoder> } ;
-
HELP: <encoder>
{ $values { "stream" "an output stream" }
{ "encoding" "an encoding descriptor" }
{ $description "Wraps the given stream in a new stream using the given encoding for all input. The encoding descriptor can either be a class or an instance of something conforming to the " { $link "encodings-protocol" } "." }
$low-level-note ;
+HELP: decode-char
+{ $values { "stream" "an underlying input stream" }
+ { "encoding" "An encoding descriptor tuple" } { "char/f" "a code point or " { $link f } } }
+{ $contract "Reads a single code point from the underlying stream, interpreting it by the encoding. Returns " { $link f } " if the stream is reached." }
+$low-level-note ;
+
+HELP: encode-char
+{ $values { "char" "a character" }
+ { "stream" "an underlying output stream" }
+ { "encoding" "an encoding descriptor" } }
+{ $contract "Writes the code point to the underlying stream in the given encoding." }
+$low-level-note ;
+
+{ encode-char decode-char } related-words
+
+HELP: decode-input
+{ $values
+ { "encoding" "an encoding descriptor" }
+}
+{ $description "Changes the encoding of the current input stream stored in the " { $link input-stream } " variable." } ;
+
+HELP: encode-output
+{ $values
+ { "encoding" "an encoding descriptor" }
+}
+{ $description "Changes the encoding of the current output stream stored in the " { $link output-stream } " variable." } ;
+
+HELP: re-decode
+{ $values
+ { "stream" "a stream" } { "encoding" "an encoding descriptor" }
+ { "newstream" "a new stream" }
+}
+{ $description "Creates a new decoding stream with the supplied encoding descriptor from an existing stream by calling the " { $link <decoder> } " word." } ;
+
+HELP: re-encode
+{ $values
+ { "stream" "a stream" } { "encoding" "an encoding descriptor" }
+ { "newstream" "a new stream" }
+}
+{ $description "Creates a new encoding stream with the supplied encoding descriptor from an existing stream by calling the " { $link <encoder> } " word." } ;
+
+{ re-decode re-encode } related-words
+
+HELP: with-decoded-input
+{ $values
+ { "encoding" "an encoding descriptor" } { "quot" quotation }
+}
+{ $description "Creates a new decoding stream with the given encoding descriptor and calls the quotation with this stream set to the " { $link input-stream } " variable. The original decoder stream is restored after the quotation returns and the stream is kept open for future input operations." } ;
+
+HELP: with-encoded-output
+{ $values
+ { "encoding" "an encoding descriptor" } { "quot" quotation }
+}
+{ $description "Creates a new encoder with the given encoding descriptor and calls the quotation using this encoder. The original encoder object is restored after the quotation returns and the stream is kept open for future output operations." } ;
+
+HELP: replacement-char
+{ $description "A code point that replaces input that could not be decoded. The presence of this character in the decoded data usually signifies an error." } ;
+
ARTICLE: "encodings-descriptors" "Encoding descriptors"
-"An encoding descriptor is something which can be used for input or output streams to encode or decode files. It must conform to the " { $link "encodings-protocol" } ". Encodings which you can use are defined in the following vocabularies:"
+"An encoding descriptor is something which can be used for input or output streams to encode or decode bytes stored in a certain representation. It must conform to the " { $link "encodings-protocol" } ". Encodings which you can use are defined in the following vocabularies:"
{ $subsection "io.encodings.binary" }
{ $subsection "io.encodings.utf8" }
{ $subsection "io.encodings.utf16" }
{ $subsection encode-char }
{ $see-also "encodings-introduction" } ;
-HELP: decode-char
-{ $values { "stream" "an underlying input stream" }
- { "encoding" "An encoding descriptor tuple" } { "char/f" "a code point or " { $link f } } }
-{ $contract "Reads a single code point from the underlying stream, interpreting it by the encoding." }
-$low-level-note ;
+ARTICLE: "encodings-constructors" "Manually constructing an encoded stream"
+"The following words can be used to construct encoded streams. Note that they are usually not used directly, but rather by the stream constructors themselves. Most stream constructors take an encoding descriptor as a parameter and call these constructors internally."
+{ $subsection <encoder> }
+{ $subsection <decoder> } ;
-HELP: encode-char
-{ $values { "char" "a character" }
- { "stream" "an underlying output stream" }
- { "encoding" "an encoding descriptor" } }
-{ $contract "Writes the code point in the encoding to the underlying stream given." }
-$low-level-note ;
+ARTICLE: "io.encodings" "I/O encodings"
+"The " { $vocab-link "io.encodings" } " vocabulary provides utilities for encoding and decoding bytes that represent text. Both strings and streams may be encoded."
+{ $subsection "encodings-descriptors" }
+{ $subsection "encodings-constructors" }
+{ $subsection "io.encodings.string" }
+"New types of encodings can be defined:"
+{ $subsection "encodings-protocol" }
+"Setting encodings on the current streams:"
+{ $subsection encode-output }
+{ $subsection decode-input }
+"Setting encodings on streams:"
+{ $subsection re-encode }
+{ $subsection re-decode }
+"Combinators to change the encoding:"
+{ $subsection with-encoded-output }
+{ $subsection with-decoded-input } ;
-{ encode-char decode-char } related-words
+ABOUT: "io.encodings"
: ((read-until)) ( buf quot: ( -- char stop? ) -- string/f sep/f )
dup call
- [ >r drop "" like r> ]
+ [ [ drop "" like ] dip ]
[ pick push ((read-until)) ] if ; inline recursive
: (read-until) ( quot -- string/f sep/f )
[ "resource:core/bootstrap/stage2.factor" (normalize-path) ]
unit-test
] with-scope
+
+[ t ] [ "/" file-system-info file-system-info? ] unit-test
+[ t ] [ file-systems [ file-system-info? ] all? ] unit-test
<file-reader> lines ;
: with-file-reader ( path encoding quot -- )
- >r <file-reader> r> with-input-stream ; inline
+ [ <file-reader> ] dip with-input-stream ; inline
: file-contents ( path encoding -- str )
<file-reader> contents ;
: with-file-writer ( path encoding quot -- )
- >r <file-writer> r> with-output-stream ; inline
+ [ <file-writer> ] dip with-output-stream ; inline
: set-file-lines ( seq path encoding -- )
[ [ print ] each ] with-file-writer ;
[ write ] with-file-writer ;
: with-file-appender ( path encoding quot -- )
- >r <file-appender> r> with-output-stream ; inline
+ [ <file-appender> ] dip with-output-stream ; inline
! Pathnames
: path-separator? ( ch -- ? ) os windows? "/\\" "/" ? member? ;
{ [ dup head.? ] [ rest trim-left-separators append-path ] }
{ [ dup head..? ] [
2 tail trim-left-separators
- >r parent-directory r> append-path
+ [ parent-directory ] dip append-path
] }
{ [ over absolute-path? over first path-separator? and ] [
- >r 2 head r> append
+ [ 2 head ] dip append
] }
[
- >r trim-right-separators "/" r>
+ [ trim-right-separators "/" ] dip
trim-left-separators 3append
]
} cond ;
] unless ;
: file-extension ( filename -- extension )
- "." last-split1 nip ;
+ "." split1-last nip ;
! File info
TUPLE: file-info type size permissions created modified
HOOK: read-link io-backend ( symlink -- path )
: copy-link ( target symlink -- )
- >r read-link r> make-link ;
+ [ read-link ] dip make-link ;
SYMBOL: +regular-file+
SYMBOL: +directory+
SYMBOL: +block-device+
SYMBOL: +fifo+
SYMBOL: +socket+
+SYMBOL: +whiteout+
SYMBOL: +unknown+
! File metadata
HOOK: file-systems os ( -- array )
-TUPLE: file-system-info device-name mount-point type free-space ;
+TUPLE: file-system-info device-name mount-point type
+available-space free-space used-space total-space ;
HOOK: file-system-info os ( path -- file-system-info )
(normalize-path) current-directory set ;
: with-directory ( path quot -- )
- >r (normalize-path) current-directory r> with-variable ; inline
+ [ (normalize-path) current-directory ] dip with-variable ; inline
! Creating directories
HOOK: make-directory io-backend ( path -- )
HELP: output-stream
{ $var-description "Holds an output stream for various implicit stream operations. Rebound using " { $link with-output-stream } " and " { $link with-output-stream* } "." } ;
+HELP: error-stream
+{ $var-description "Holds an error stream." } ;
+
HELP: readln
{ $values { "str/f" "a string or " { $link f } } }
{ $description "Reads a line of input from " { $link input-stream } ". Outputs " { $link f } " on stream exhaustion." }
{ $values { "stream" "an input stream" } { "seq" "a sequence of strings" } }
{ $description "Reads lines of text until the stream is exhausted, collecting them in a sequence of strings." } ;
+HELP: each-line
+{ $values { "quot" { $quotation "( str -- )" } } }
+{ $description "Calls the quotatin with successive lines of text, until the current " { $link input-stream } " is exhausted." } ;
+
HELP: contents
{ $values { "stream" "an input stream" } { "str" string } }
{ $description "Reads the entire contents of a stream into a string." }
$nl
"First, a simple composition of " { $link stream-write } " and " { $link stream-nl } ":"
{ $subsection stream-print }
+"Processing lines one by one:"
+{ $subsection each-line }
"Sluring an entire stream into memory all at once:"
{ $subsection lines }
{ $subsection contents }
! Make sure we use correct to_c_string form when writing
[ ] [ "\0" write ] unit-test
+[ ] [
+ "It seems Jobs has lost his grasp on reality again.\n"
+ "separator-test.txt" temp-file latin1 set-file-contents
+] unit-test
+
[
{
{ "It seems " CHAR: J }
}
] [
[
- "resource:core/io/test/separator-test.txt"
+ "separator-test.txt" temp-file
latin1 <file-reader> [
"J" read-until 2array ,
"i" read-until 2array ,
[ ] cleanup ; inline
: tabular-output ( style quot -- )
- swap >r { } make r> output-stream get stream-write-table ; inline
+ swap [ { } make ] dip output-stream get stream-write-table ; inline
: with-row ( quot -- )
{ } make , ; inline
] if ; inline
: with-nesting ( style quot -- )
- >r output-stream get make-block-stream
- r> with-output-stream ; inline
+ [ output-stream get make-block-stream ] dip
+ with-output-stream ; inline
: print ( string -- ) output-stream get stream-print ;
: lines ( stream -- seq )
[ [ readln dup ] [ ] [ drop ] produce ] with-input-stream ;
+: each-line ( quot -- )
+ [ [ readln dup ] ] dip [ drop ] while ; inline
+
: contents ( stream -- str )
[
[ 65536 read dup ] [ ] [ drop ] produce concat f like
+++ /dev/null
-USING: help.syntax help.markup io byte-arrays quotations ;
-IN: io.streams.byte-array
-
-ABOUT: "io.streams.byte-array"
-
-ARTICLE: "io.streams.byte-array" "Byte-array streams"
-"Byte array streams:"
-{ $subsection <byte-reader> }
-{ $subsection <byte-writer> }
-"Utility combinators:"
-{ $subsection with-byte-reader }
-{ $subsection with-byte-writer } ;
-
-HELP: <byte-reader>
-{ $values { "byte-array" byte-array }
- { "encoding" "an encoding descriptor" }
- { "stream" "a new byte reader" } }
-{ $description "Creates an input stream reading from a byte array using an encoding." } ;
-
-HELP: <byte-writer>
-{ $values { "encoding" "an encoding descriptor" }
- { "stream" "a new byte writer" } }
-{ $description "Creates an output stream writing data to a byte array using an encoding." } ;
-
-HELP: with-byte-reader
-{ $values { "encoding" "an encoding descriptor" }
- { "quot" quotation } { "byte-array" byte-array } }
-{ $description "Calls the quotation in a new dynamic scope with " { $link input-stream } " rebound to an input stream for reading from a byte array using an encoding." } ;
-
-HELP: with-byte-writer
-{ $values { "encoding" "an encoding descriptor" }
- { "quot" quotation }
- { "byte-array" byte-array } }
-{ $description "Calls the quotation in a new dynamic scope with " { $link output-stream } " rebound to an output stream writing data to a byte array using an encoding." } ;
+++ /dev/null
-USING: tools.test io.streams.byte-array io.encodings.binary
-io.encodings.utf8 io kernel arrays strings ;
-
-[ B{ 1 2 3 } ] [ binary [ { 1 2 3 } write ] with-byte-writer ] unit-test
-[ B{ 1 2 3 } ] [ { 1 2 3 } binary [ 3 read ] with-byte-reader ] unit-test
-
-[ B{ BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 BIN: 11101111 BIN: 10000000 BIN: 10111111 BIN: 11011111 BIN: 10000000 CHAR: x } ]
-[ { BIN: 101111111000000111111 BIN: 1111000000111111 BIN: 11111000000 CHAR: x } utf8 [ write ] with-byte-writer ] unit-test
-[ { BIN: 101111111000000111111 } t ] [ { BIN: 11110101 BIN: 10111111 BIN: 10000000 BIN: 10111111 } utf8 <byte-reader> contents dup >array swap string? ] unit-test
+++ /dev/null
-USING: byte-arrays byte-vectors kernel io.encodings io.streams.string
-sequences io namespaces io.encodings.private accessors ;
-IN: io.streams.byte-array
-
-: <byte-writer> ( encoding -- stream )
- 512 <byte-vector> swap <encoder> ;
-
-: with-byte-writer ( encoding quot -- byte-array )
- >r <byte-writer> r> [ output-stream get ] compose with-output-stream*
- dup encoder? [ stream>> ] when >byte-array ; inline
-
-: <byte-reader> ( byte-array encoding -- stream )
- >r >byte-vector dup reverse-here r> <decoder> ;
-
-: with-byte-reader ( byte-array encoding quot -- )
- >r <byte-reader> r> with-input-stream* ; inline
{ $errors "Throws an error if the input operation failed." } ;
HELP: stdin-handle
-{ $values { "in" "a C FILE* handle" } }
+{ $values { "alien" "a C FILE* handle" } }
{ $description "Outputs the console standard input file handle." } ;
HELP: stdout-handle
-{ $values { "out" "a C FILE* handle" } }
+{ $values { "alien" "a C FILE* handle" } }
{ $description "Outputs the console standard output file handle." } ;
HELP: stderr-handle
-{ $values { "out" "a C FILE* handle" } }
+{ $values { "alien" "a C FILE* handle" } }
{ $description "Outputs the console standard error file handle." } ;
M: c-io-backend init-io ;
-: stdin-handle 11 getenv ;
-: stdout-handle 12 getenv ;
-: stderr-handle 61 getenv ;
+: stdin-handle ( -- alien ) 11 getenv ;
+: stdout-handle ( -- alien ) 12 getenv ;
+: stderr-handle ( -- alien ) 61 getenv ;
: init-c-stdio ( -- stdin stdout stderr )
stdin-handle <c-reader>
M: c-io-backend (init-stdio) init-c-stdio ;
-M: c-io-backend io-multiplex 60 60 * 1000 * or (sleep) ;
+M: c-io-backend io-multiplex 60 60 * 1000 * 1000 * or (sleep) ;
M: c-io-backend (file-reader)
"rb" fopen <c-reader> ;
#! print stuff from contexts where the I/O system would
#! otherwise not work (tools.deploy.shaker, the I/O
#! multiplexer thread).
- "\r\n" append >byte-array
+ "\n" append >byte-array
stdout-handle fwrite
stdout-handle fflush ;
[ style>> ] [ stream>> ] bi stream-format ;
M: style-stream stream-write1
- >r 1string r> stream-write ;
+ [ 1string ] dip stream-write ;
M: style-stream make-span-stream
do-nested-style make-span-stream ;
] unless ;
: map-last ( seq quot -- seq )
- >r dup length <reversed> [ zero? ] r> compose 2map ; inline
+ [ dup length <reversed> ] dip [ 0 = ] prepose 2map ; inline
PRIVATE>
>sbuf dup reverse-here null-encoding <decoder> ;
: with-string-reader ( str quot -- )
- >r <string-reader> r> with-input-stream ; inline
+ [ <string-reader> ] dip with-input-stream ; inline
INSTANCE: growable plain-writer
+++ /dev/null
-It seems Jobs has lost his grasp on reality again.
HELP: roll $shuffle ;
HELP: -roll $shuffle ;
-HELP: >r ( x -- )
-{ $values { "x" object } } { $description "Moves the top of the data stack to the retain stack." } ;
-
-HELP: r> ( -- x )
-{ $values { "x" object } } { $description "Moves the top of the retain stack to the data stack." } ;
-
HELP: datastack ( -- ds )
{ $values { "ds" array } }
{ $description "Outputs an array containing a copy of the data stack contents right before the call to this word, with the top of the stack at the end of the array." } ;
{ $description "Calls a quotation while hiding the top three stack elements." } ;
HELP: keep
-{ $values { "quot" { $quotation "( x -- )" } } { "x" object } }
-{ $description "Call a quotation with a value on the stack, restoring the value when the quotation returns." } ;
+{ $values { "quot" { $quotation "( x -- ... )" } } { "x" object } }
+{ $description "Call a quotation with a value on the stack, restoring the value when the quotation returns." }
+{ $examples
+ { $example "USING: arrays kernel prettyprint ;" "2 \"greetings\" [ <array> ] keep 2array ." "{ { \"greetings\" \"greetings\" } \"greetings\" }" }
+} ;
HELP: 2keep
-{ $values { "quot" { $quotation "( x y -- )" } } { "x" object } { "y" object } }
+{ $values { "quot" { $quotation "( x y -- ... )" } } { "x" object } { "y" object } }
{ $description "Call a quotation with two values on the stack, restoring the values when the quotation returns." } ;
HELP: 3keep
-{ $values { "quot" { $quotation "( x y z -- )" } } { "x" object } { "y" object } { "z" object } }
+{ $values { "quot" { $quotation "( x y z -- ... )" } } { "x" object } { "y" object } { "z" object } }
{ $description "Call a quotation with three values on the stack, restoring the values when the quotation returns." } ;
HELP: bi
"The following two lines are equivalent:"
{ $code
"[ p ] [ q ] bi*"
- ">r p r> q"
+ "[ p ] dip q"
}
} ;
"The following two lines are equivalent:"
{ $code
"[ p ] [ q ] 2bi*"
- ">r >r p r> r> q"
+ "[ p ] 2dip q"
}
} ;
"The following two lines are equivalent:"
{ $code
"[ p ] [ q ] [ r ] tri*"
- ">r >r p r> q r> r"
+ "[ [ p ] dip q ] dip r"
}
} ;
HELP: bi@
-{ $values { "x" object } { "y" object } { "quot" { $quotation "( obj -- )" } } }
+{ $values { "x" object } { "y" object } { "quot" { $quotation "( obj -- ... )" } } }
{ $description "Applies the quotation to " { $snippet "x" } ", then to " { $snippet "y" } "." }
{ $examples
"The following two lines are equivalent:"
{ $code
"[ p ] bi@"
- ">r p r> p"
+ "[ p ] dip p"
}
"The following two lines are also equivalent:"
{ $code
} ;
HELP: 2bi@
-{ $values { "w" object } { "x" object } { "y" object } { "z" object } { "quot" { $quotation "( obj1 obj2 -- )" } } }
+{ $values { "w" object } { "x" object } { "y" object } { "z" object } { "quot" { $quotation "( obj1 obj2 -- ... )" } } }
{ $description "Applies the quotation to " { $snippet "w" } " and " { $snippet "x" } ", then to " { $snippet "y" } " and " { $snippet "z" } "." }
{ $examples
"The following two lines are equivalent:"
{ $code
"[ p ] 2bi@"
- ">r >r p r> r> p"
+ "[ p ] 2dip p"
}
"The following two lines are also equivalent:"
{ $code
} ;
HELP: tri@
-{ $values { "x" object } { "y" object } { "z" object } { "quot" { $quotation "( obj -- )" } } }
+{ $values { "x" object } { "y" object } { "z" object } { "quot" { $quotation "( obj -- ... )" } } }
{ $description "Applies the quotation to " { $snippet "x" } ", then to " { $snippet "y" } ", and finally to " { $snippet "z" } "." }
{ $examples
"The following two lines are equivalent:"
{ $code
"[ p ] tri@"
- ">r >r p r> p r> p"
+ "[ [ p ] dip p ] dip p"
}
"The following two lines are also equivalent:"
{ $code
"The " { $snippet "cond" } " value is removed from the stack before the quotation is called." } ;
HELP: if*
-{ $values { "?" "a generalized boolean" } { "true" { $quotation "( cond -- )" } } { "false" quotation } }
+{ $values { "?" "a generalized boolean" } { "true" { $quotation "( cond -- ... )" } } { "false" quotation } }
{ $description "Alternative conditional form that preserves the " { $snippet "cond" } " value if it is true."
$nl
"If the condition is true, it is retained on the stack before the " { $snippet "true" } " quotation is called. Otherwise, the condition is removed from the stack and the " { $snippet "false" } " quotation is called."
{ $code "X [ Y ] [ Z ] if*" "X dup [ Y ] [ drop Z ] if" } } ;
HELP: when*
-{ $values { "?" "a generalized boolean" } { "true" { $quotation "( cond -- )" } } }
+{ $values { "?" "a generalized boolean" } { "true" { $quotation "( cond -- ... )" } } }
{ $description "Variant of " { $link if* } " with no false quotation."
$nl
"The following two lines are equivalent:"
{ $code "X [ Y ] unless*" "X dup [ ] [ drop Y ] if" } } ;
HELP: ?if
-{ $values { "default" object } { "cond" "a generalized boolean" } { "true" { $quotation "( cond -- )" } } { "false" { $quotation "( default -- )" } } }
+{ $values { "default" object } { "cond" "a generalized boolean" } { "true" { $quotation "( cond -- ... )" } } { "false" { $quotation "( default -- ... )" } } }
{ $description "If the condition is " { $link f } ", the " { $snippet "false" } " quotation is called with the " { $snippet "default" } " value on the stack. Otherwise, the " { $snippet "true" } " quotation is called with the condition on the stack." }
{ $notes
"The following two lines are equivalent:"
{ $values { "quot1" callable } { "quot2" callable } { "compose" compose } }
{ $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot1" } " followed by " { $snippet "quot2" } "." }
{ $notes
- "The two quotations must leave the retain stack in the same state on exit as it was on entry, so the following code is not allowed:"
- { $code
- "[ 3 >r ] [ r> . ] compose"
- }
- "Except for this restriction, the following two lines are equivalent:"
+ "The following two lines are equivalent:"
{ $code
"compose call"
"append call"
{ compose prepose } related-words
-HELP: 3compose
-{ $values { "quot1" callable } { "quot2" callable } { "quot3" callable } { "compose" compose } }
-{ $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot1" } ", " { $snippet "quot2" } " and then " { $snippet "quot3" } "." }
-{ $notes
- "The three quotations must leave the retain stack in the same state on exit as it was on entry, so for example, the following code is not allowed:"
- { $code
- "[ >r ] swap [ r> ] 3compose"
- }
- "The correct way to achieve the effect of the above is the following:"
- { $code
- "[ dip ] curry"
- }
- "Excepting the retain stack restriction, the following two lines are equivalent:"
- { $code
- "3compose call"
- "3append call"
- }
- "However, " { $link 3compose } " runs in constant time, and the compiler is able to compile code which calls composed quotations."
-} ;
-
HELP: dip
-{ $values { "obj" object } { "quot" quotation } }
+{ $values { "x" object } { "quot" quotation } }
{ $description "Calls " { $snippet "quot" } " with " { $snippet "obj" } " hidden on the retain stack." }
-{ $notes "The following are equivalent:"
- { $code ">r foo bar r>" }
- { $code "[ foo bar ] dip" }
+{ $examples
+ { $example "USING: arrays kernel math prettyprint ;" "10 20 30 [ / ] dip 2array ." "{ 1/2 30 }" }
} ;
HELP: 2dip
-{ $values { "obj1" object } { "obj2" object } { "quot" quotation } }
-{ $description "Calls " { $snippet "quot" } " with " { $snippet "obj1" } " and " { $snippet "obj2" } " hidden on the retain stack." }
+{ $values { "x" object } { "y" object } { "quot" quotation } }
+{ $description "Calls " { $snippet "quot" } " with " { $snippet "x" } " and " { $snippet "y" } " hidden on the retain stack." }
{ $notes "The following are equivalent:"
- { $code ">r >r foo bar r> r>" }
+ { $code "[ [ foo bar ] dip ] dip" }
{ $code "[ foo bar ] 2dip" }
} ;
HELP: 3dip
-{ $values { "obj1" object } { "obj2" object } { "obj3" object } { "quot" quotation } }
+{ $values { "x" object } { "y" object } { "z" object } { "quot" quotation } }
{ $description "Calls " { $snippet "quot" } " with " { $snippet "obj1" } ", " { $snippet "obj2" } " and " { $snippet "obj3" } " hidden on the retain stack." }
{ $notes "The following are equivalent:"
- { $code ">r >r >r foo bar r> r> r>" }
+ { $code "[ [ [ foo bar ] dip ] dip ] dip" }
{ $code "[ foo bar ] 3dip" }
} ;
HELP: while
{ $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
-{ $description "Repeatedly calls " { $snippet "pred" } ". If it yields " { $link f } ", iteration stops, otherwise " { $snippet "body" } " is called. After iteration stops, " { $snippet "tail" } " is called." }
-{ $notes "In most cases, tail recursion should be used, because it is simpler both in terms of implementation and conceptually. However in some cases this combinator expresses intent better and should be used."
-$nl
-"Strictly speaking, the " { $snippet "tail" } " is not necessary, since the following are equivalent:"
-{ $code
- "[ P ] [ Q ] [ T ] while"
- "[ P ] [ Q ] [ ] while T"
-}
-"However, depending on the stack effects of " { $snippet "pred" } " and " { $snippet "quot" } ", the " { $snippet "tail" } " quotation might need to be non-empty in order to balance out the stack effect of branches for stack effect inference." } ;
+{ $description "Calls " { $snippet "body" } " until " { $snippet "pred" } " returns " { $link f } "." } ;
+
+HELP: until
+{ $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
+{ $description "Calls " { $snippet "body" } " until " { $snippet "pred" } " returns " { $link t } "." } ;
+
+HELP: do
+{ $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
+{ $description "Executes one iteration of a " { $link while } " or " { $link until } " loop." } ;
HELP: loop
{ $values
"3\n10\n6\n2\n9\n5\n1\n8\n4\n0\n7" }
} ;
+ARTICLE: "looping-combinators" "Looping combinators"
+"In most cases, loops should be written using high-level combinators (such as " { $link "sequences-combinators" } ") or tail recursion. However, sometimes, the best way to express intent is with a loop."
+{ $subsection while }
+{ $subsection until }
+"The above two combinators take a " { $snippet "tail" } " quotation. Strictly speaking, the " { $snippet "tail" } " is not necessary, since the following are equivalent:"
+{ $code
+ "[ P ] [ Q ] [ T ] while"
+ "[ P ] [ Q ] [ ] while T"
+}
+"However, depending on the stack effects of " { $snippet "pred" } " and " { $snippet "quot" } ", the " { $snippet "tail" } " quotation might need to be non-empty in order to balance out the stack effect of branches for stack effect inference."
+$nl
+"To execute one iteration of a loop, use the following word:"
+{ $subsection do }
+"This word is intended as a modifier. The normal " { $link while } " loop never executes the body if the predicate returns first on the first iteration. To ensure the body executes at least once, use " { $link do } ":"
+{ $code
+ "[ P ] [ Q ] [ T ] do while"
+}
+"A simpler looping combinator which executes a single quotation until it returns " { $link f } ":"
+{ $subsection loop } ;
+
HELP: assert
{ $values { "got" "the obtained value" } { "expect" "the expected value" } }
{ $description "Throws an " { $link assert } " error." }
{ $subsection -rot }
{ $subsection spin }
{ $subsection roll }
-{ $subsection -roll }
-"Sometimes an additional storage area is needed to hold objects. The " { $emphasis "retain stack" } " is an auxilliary stack for this purpose. Objects can be moved between the data and retain stacks using the following two words:"
-{ $subsection >r }
-{ $subsection r> }
-"The top of the data stack is ``hidden'' between " { $link >r } " and " { $link r> } ":"
-{ $example "1 2 3 >r .s r>" "1\n2" }
-"Usages of " { $link >r } " and " { $link r> } " must be balanced within a single quotation; quotations are not permitted to pop retain stack elements they did not push, or leave elements on the retain stack after returning."
-$nl
-"The " { $link "inference" } " tool checks retain stack usage. The " { $link "slip-keep-combinators" } " combinators abstract out common retain stack usage patterns." ;
+{ $subsection -roll } ;
ARTICLE: "cleave-shuffle-equivalence" "Expressing shuffle words with cleave combinators"
"Cleave combinators are defined in terms of shuffle words, and mappings from certain shuffle idioms to cleave combinators are discussed in the documentation for " { $link bi } ", " { $link 2bi } ", " { $link 3bi } ", " { $link tri } ", " { $link 2tri } " and " { $link 3tri } "."
{ $subsection tri* }
"Technically, the spread combinators are redundant because they can be simulated using shuffle words and other combinators, and in addition, they do not reduce token counts by much, if at all. However, they can make code more readable by expressing intention and exploiting any inherent symmetry. For example, a piece of code which performs three operations on three related values can be written in one of two ways:"
{ $code
- "! First alternative; uses retain stack explicitly"
- ">r >r 1 +"
- "r> 1 -"
- "r> 2 *"
+ "! First alternative; uses dip"
+ "[ [ 1 + ] dip 1 - ] dip 2 *"
"! Second alternative: uses tri*"
- "[ 1 + ]"
- "[ 1 - ]"
- "[ 2 * ] tri*"
+ "[ 1 + ] [ 1 - ] [ 2 * ] tri*"
}
-
-$nl
"A generalization of the above combinators to any number of quotations can be found in " { $link "combinators" } "."
{ $subsection "spread-shuffle-equivalence" } ;
{ $subsection both? }
{ $subsection either? } ;
-ARTICLE: "slip-keep-combinators" "The dip, slip and keep combinators"
+ARTICLE: "slip-keep-combinators" "Retain stack combinators"
+"Sometimes an additional storage area is needed to hold objects. The " { $emphasis "retain stack" } " is an auxilliary stack for this purpose. Objects can be moved between the data and retain stacks using a set of combinators."
+$nl
"The dip combinators invoke the quotation at the top of the stack, hiding the values underneath:"
{ $subsection dip }
{ $subsection 2dip }
{ $subsection 3curry }
{ $subsection with }
{ $subsection compose }
-{ $subsection 3compose }
{ $subsection prepose }
"Quotations also implement the sequence protocol, and can be manipulated with sequence words; see " { $link "quotations" } "." ;
"These words are used to implement combinators. Note that combinator definitions must be followed by the " { $link POSTPONE: inline } " declaration in order to compile in the optimizing compiler; for example:"
{ $code
": keep ( x quot -- x )"
- " over >r call r> ; inline"
+ " over [ call ] dip ; inline"
}
"Word inlining is documented in " { $link "declarations" } "." ;
"An object can be cloned; the clone has distinct identity but equal value:"
{ $subsection clone } ;
+ARTICLE: "assertions" "Assertions"
+"Some words to make assertions easier to enforce:"
+{ $subsection assert }
+{ $subsection assert= } ;
+
ARTICLE: "dataflow" "Data and control flow"
{ $subsection "evaluator" }
{ $subsection "words" }
{ $subsection "booleans" }
{ $subsection "shuffle-words" }
"A central concept in Factor is that of a " { $emphasis "combinator" } ", which is a word taking code as input."
+$nl
+"Data flow combinators:"
+{ $subsection "slip-keep-combinators" }
{ $subsection "cleave-combinators" }
{ $subsection "spread-combinators" }
{ $subsection "apply-combinators" }
-{ $subsection "slip-keep-combinators" }
+"Control flow combinators:"
{ $subsection "conditionals" }
+{ $subsection "looping-combinators" }
+"Additional combinators:"
{ $subsection "compositional-combinators" }
{ $subsection "combinators" }
+"More combinators are defined for working on data structures, such as " { $link "sequences-combinators" } " and " { $link "assocs-combinators" } "."
+$nl
"Advanced topics:"
+{ $subsection "assertions" }
{ $subsection "implementing-combinators" }
{ $subsection "errors" }
{ $subsection "continuations" } ;
USING: arrays byte-arrays kernel kernel.private math memory
namespaces sequences tools.test math.private quotations
continuations prettyprint io.streams.string debugger assocs
-sequences.private ;
+sequences.private accessors ;
IN: kernel.tests
[ 0 ] [ f size ] unit-test
! Regression
: (loop) ( a b c d -- )
- >r pick r> swap >r pick r> swap
- < [ >r >r >r 1+ r> r> r> (loop) ] [ 2drop 2drop ] if ; inline
+ [ pick ] dip swap [ pick ] dip swap
+ < [ [ 1+ ] 3dip (loop) ] [ 2drop 2drop ] if ; inline
: loop ( obj obj -- )
- H{ } values swap >r dup length swap r> 0 -roll (loop) ;
+ H{ } values swap [ dup length swap ] dip 0 -roll (loop) ;
[ loop ] must-fail
[ [ sq ] tri@ ] must-infer
[ 4 ] [ 1 { [ 1 ] [ 2 ] } dispatch sq ] unit-test
+
+! Test traceback accuracy
+: last-frame ( -- pair )
+ error-continuation get call>> callstack>array 4 head* 2 tail* ;
+
+[
+ { [ 1 2 [ 3 throw ] call 4 ] 3 }
+] [
+ [ [ 1 2 [ 3 throw ] call 4 ] call ] ignore-errors
+ last-frame
+] unit-test
+
+[
+ { [ 1 2 [ 3 throw ] dip 4 ] 3 }
+] [
+ [ [ 1 2 [ 3 throw ] dip 4 ] call ] ignore-errors
+ last-frame
+] unit-test
+
+[
+ { [ 1 2 3 throw [ ] call 4 ] 3 }
+] [
+ [ [ 1 2 3 throw [ ] call 4 ] call ] ignore-errors
+ last-frame
+] unit-test
+
+[
+ { [ 1 2 3 throw [ ] dip 4 ] 3 }
+] [
+ [ [ 1 2 3 throw [ ] dip 4 ] call ] ignore-errors
+ last-frame
+] unit-test
+
+[
+ { [ 1 2 3 throw [ ] [ ] if 4 ] 3 }
+] [
+ [ [ 1 2 3 throw [ ] [ ] if 4 ] call ] ignore-errors
+ last-frame
+] unit-test
USING: kernel.private slots.private classes.tuple.private ;
IN: kernel
+DEFER: dip
+DEFER: 2dip
+DEFER: 3dip
+
! Stack stuff
: spin ( x y z -- z y x ) swap rot ; inline
-: roll ( x y z t -- y z t x ) >r rot r> swap ; inline
+: roll ( x y z t -- y z t x ) [ rot ] dip swap ; inline
-: -roll ( x y z t -- t x y z ) swap >r -rot r> ; inline
+: -roll ( x y z t -- t x y z ) swap [ -rot ] dip ; inline
: 2over ( x y z -- x y z x y ) pick pick ; inline
: ?if ( default cond true false -- )
pick [ roll 2drop call ] [ 2nip call ] if ; inline
-! Slippers
-: slip ( quot x -- x ) >r call r> ; inline
+! Slippers and dippers.
+! Not declared inline because the compiler special-cases them
+
+: slip ( quot x -- x )
+ #! 'slip' and 'dip' can be defined in terms of each other
+ #! because the JIT special-cases a 'dip' preceeded by
+ #! a literal quotation.
+ [ call ] dip ;
-: 2slip ( quot x y -- x y ) >r >r call r> r> ; inline
+: 2slip ( quot x y -- x y )
+ #! '2slip' and '2dip' can be defined in terms of each other
+ #! because the JIT special-cases a '2dip' preceeded by
+ #! a literal quotation.
+ [ call ] 2dip ;
-: 3slip ( quot x y z -- x y z ) >r >r >r call r> r> r> ; inline
+: 3slip ( quot x y z -- x y z )
+ #! '3slip' and '3dip' can be defined in terms of each other
+ #! because the JIT special-cases a '3dip' preceeded by
+ #! a literal quotation.
+ [ call ] 3dip ;
-: dip ( obj quot -- obj ) swap slip ; inline
+: dip ( x quot -- x ) swap slip ;
-: 2dip ( obj1 obj2 quot -- obj1 obj2 ) -rot 2slip ; inline
+: 2dip ( x y quot -- x y ) -rot 2slip ;
-: 3dip ( obj1 obj2 obj3 quot -- obj1 obj2 obj3 ) -roll 3slip ; inline
+: 3dip ( x y z quot -- x y z ) -roll 3slip ;
! Keepers
: keep ( x quot -- x ) over slip ; inline
-: 2keep ( x y quot -- x y ) 2over 2slip ; inline
+: 2keep ( x y quot -- x y ) [ 2dup ] dip 2dip ; inline
-: 3keep ( x y z quot -- x y z ) >r 3dup r> -roll 3slip ; inline
+: 3keep ( x y z quot -- x y z ) [ 3dup ] dip 3dip ; inline
! Cleavers
: bi ( x p q -- )
- >r keep r> call ; inline
+ [ keep ] dip call ; inline
: tri ( x p q r -- )
- >r >r keep r> keep r> call ; inline
+ [ [ keep ] dip keep ] dip call ; inline
! Double cleavers
: 2bi ( x y p q -- )
- >r 2keep r> call ; inline
+ [ 2keep ] dip call ; inline
: 2tri ( x y p q r -- )
- >r >r 2keep r> 2keep r> call ; inline
+ [ [ 2keep ] dip 2keep ] dip call ; inline
! Triple cleavers
: 3bi ( x y z p q -- )
- >r 3keep r> call ; inline
+ [ 3keep ] dip call ; inline
: 3tri ( x y z p q r -- )
- >r >r 3keep r> 3keep r> call ; inline
+ [ [ 3keep ] dip 3keep ] dip call ; inline
! Spreaders
: bi* ( x y p q -- )
- >r dip r> call ; inline
+ [ dip ] dip call ; inline
: tri* ( x y z p q r -- )
- >r >r 2dip r> dip r> call ; inline
+ [ [ 2dip ] dip dip ] dip call ; inline
! Double spreaders
: 2bi* ( w x y z p q -- )
- >r 2dip r> call ; inline
+ [ 2dip ] dip call ; inline
! Appliers
: bi@ ( x y quot -- )
: 2bi@ ( w x y z quot -- )
dup 2bi* ; inline
-: loop ( pred: ( -- ? ) -- )
- dup slip swap [ loop ] [ drop ] if ; inline recursive
-
-: while ( pred: ( -- ? ) body: ( -- ) tail: ( -- ) -- )
- >r >r dup slip r> r> roll
- [ >r tuck 2slip r> while ]
- [ 2nip call ] if ; inline recursive
-
! Object protocol
GENERIC: hashcode* ( depth obj -- code )
M: identity-tuple equal? 2drop f ;
+USE: math.private
: = ( obj1 obj2 -- ? )
- 2dup eq? [ 2drop t ] [ equal? ] if ; inline
+ 2dup eq? [ 2drop t ] [
+ 2dup both-fixnums? [ 2drop f ] [ equal? ] if
+ ] if ; inline
GENERIC: clone ( obj -- cloned )
: prepose ( quot1 quot2 -- compose )
swap compose ; inline
-: 3compose ( quot1 quot2 quot3 -- compose )
- compose compose ; inline
-
! Booleans
: not ( obj -- ? ) [ f ] [ t ] if ; inline
: either? ( x y quot -- ? ) bi@ or ; inline
: most ( x y quot -- z )
- >r 2dup r> call [ drop ] [ nip ] if ; inline
+ [ 2dup ] dip call [ drop ] [ nip ] if ; inline
+
+! Loops
+: loop ( pred: ( -- ? ) -- )
+ dup slip swap [ loop ] [ drop ] if ; inline recursive
+
+: do ( pred body tail -- pred body tail )
+ over 3dip ; inline
+
+: while ( pred: ( -- ? ) body: ( -- ) tail: ( -- ) -- )
+ [ pick 3dip [ do while ] 3curry ] keep if ; inline recursive
+
+: until ( pred: ( -- ? ) body: ( -- ) tail: ( -- ) -- )
+ [ [ not ] compose ] 2dip while ; inline
! Error handling -- defined early so that other files can
! throw errors before continuations are loaded
lexer new-lexer ;
: skip ( i seq ? -- n )
- >r tuck r>
+ [ tuck ] dip
[ swap CHAR: \s eq? xor ] curry find-from drop
[ ] [ length ] ?if ;
: unexpected-eof ( word -- * ) f unexpected ;
+: expect ( token -- )
+ scan
+ [ 2dup = [ 2drop ] [ unexpected ] if ]
+ [ unexpected-eof ]
+ if* ;
+
: (parse-tokens) ( accum end -- accum )
scan 2dup = [
2drop
"Rational numbers represent " { $emphasis "exact" } " quantities. On the other hand, a floating point number is an " { $emphasis "approximation" } ". While rationals can grow to any required precision, floating point numbers are fixed-width, and manipulating them is usually faster than manipulating ratios or bignums (but slower than manipulating fixnums). Floating point numbers are often used to represent irrational numbers, which have no exact representation as a ratio of two integers."
$nl
"Introducing a floating point number in a computation forces the result to be expressed in floating point."
-{ $example "5/4 1/2 + ." "7/4" }
+{ $example "5/4 1/2 + ." "1+3/4" }
{ $example "5/4 0.5 + ." "1.75" }
"Integers and rationals can be converted to floats:"
{ $subsection >float }
[ 0 ] [ 1/0. >bignum ] unit-test
[ t ] [ 64 [ 2^ 0.5 * ] map [ < ] monotonic? ] unit-test
+
+[ 5 ] [ 10.5 1.9 /i ] unit-test
M: float * float* ;
M: float / float/f ;
M: float /f float/f ;
+M: float /i float/f >integer ;
M: float mod float-mod ;
M: real abs dup 0 < [ neg ] when ;
M: fixnum - fixnum- ;
M: fixnum * fixnum* ;
M: fixnum /i fixnum/i ;
-M: fixnum /f >r >float r> >float float/f ;
+M: fixnum /f [ >float ] dip >float float/f ;
M: fixnum mod fixnum-mod ;
M: fixnum bit? neg shift 1 bitand 0 > ;
-: (fixnum-log2) ( accum n -- accum )
- dup 1 number= [ drop ] [ >r 1+ r> 2/ (fixnum-log2) ] if ;
- inline recursive
+: fixnum-log2 ( x -- n )
+ 0 swap [ dup 1 eq? ] [ [ 1+ ] [ 2/ ] bi* ] [ ] until drop ;
-M: fixnum (log2) 0 swap (fixnum-log2) ;
+M: fixnum (log2) fixnum-log2 ;
M: bignum >fixnum bignum>fixnum ;
M: bignum >bignum ;
M: bignum bitand bignum-bitand ;
M: bignum bitor bignum-bitor ;
M: bignum bitxor bignum-bitxor ;
-M: bignum shift bignum-shift ;
+M: bignum shift >fixnum bignum-shift ;
M: bignum bitnot bignum-bitnot ;
M: bignum bit? bignum-bit? ;
: pre-scale ( num den -- scale shifted-num scaled-den )
2dup [ log2 ] bi@ -
- tuck [ neg 54 + shift ] [ >r scale-denonimator r> + ] 2bi*
+ tuck [ neg 54 + shift ] [ [ scale-denonimator ] dip + ] 2bi*
-rot ; inline
! Second step: loop
: /f-loop ( scale mantissa den -- scale' fraction-and-guard rem )
[ 2dup /i log2 53 > ]
- [ >r shift-mantissa r> ]
+ [ [ shift-mantissa ] dip ]
[ ] while /mod ; inline
! Third step: post-scaling
52 2^ 1- bitand 1022 52 shift bitor bits>double ; inline
: scale-float ( scale mantissa -- float' )
- >r dup 0 < [ neg 2^ recip ] [ 2^ ] if r> * ; inline
+ [ dup 0 < [ neg 2^ recip ] [ 2^ ] if ] dip * ; inline
: post-scale ( scale mantissa -- n )
2/ dup log2 52 > [ shift-mantissa ] when
HELP: 1+
{ $values { "x" number } { "y" number } }
{ $description
- "Increments a number by 1. The following two lines are equivalent, but the first is more efficient:"
+ "Increments a number by 1. The following two lines are equivalent:"
{ $code "1+" "1 +" }
+ "There is no difference in behavior or efficiency."
} ;
HELP: 1-
{ $values { "x" number } { "y" number } }
{ $description
- "Decrements a number by 1. The following two lines are equivalent, but the first is more efficient:"
+ "Decrements a number by 1. The following two lines are equivalent:"
{ $code "1-" "1 -" }
+ "There is no difference in behavior or efficiency."
} ;
HELP: ?1+
{ $subsection 2/ }
{ $subsection 2^ }
{ $subsection bit? }
+"The " { $vocab-link "math.bitwise" } " vocabulary implements additional bitwise integer operations."
{ $see-also "conditionals" } ;
ARTICLE: "arithmetic" "Arithmetic"
"log2 expects positive inputs" throw
] [
(log2)
- ] if ; foldable
+ ] if ; inline
: zero? ( x -- ? ) 0 number= ; inline
: 1+ ( x -- y ) 1 + ; inline
drop f
] if ;
-: (next-power-of-2) ( i n -- n )
- 2dup >= [
- drop
- ] [
- >r 1 shift r> (next-power-of-2)
- ] if ;
-
-: next-power-of-2 ( m -- n ) 2 swap (next-power-of-2) ; foldable
+: next-power-of-2 ( m -- n )
+ dup 2 <= [ drop 2 ] [ 1- log2 1+ 2^ ] if ; inline
: power-of-2? ( n -- ? )
dup 0 <= [ drop f ] [ dup 1- bitand zero? ] if ; foldable
: iterate-prep 0 -rot ; inline
-: if-iterate? >r >r 2over < r> r> if ; inline
+: if-iterate? [ 2over < ] 2dip if ; inline
: iterate-step ( i n quot -- i n quot )
#! Apply quot to i, keep i and quot, hide n.
- swap >r 2dup 2slip r> swap ; inline
+ swap [ 2dup 2slip ] dip swap ; inline
-: iterate-next >r >r 1+ r> r> ; inline
+: iterate-next [ 1+ ] 2dip ; inline
PRIVATE>
2dup 2slip rot [
drop
] [
- >r 1- r> find-last-integer
+ [ 1- ] dip find-last-integer
] if
] if ; inline recursive
: (base>) ( str -- n ) radix get base> ;
: whole-part ( str -- m n )
- sign split1 >r (base>) r>
+ sign split1 [ (base>) ] dip
dup [ (base>) ] [ drop 0 swap ] if ;
: string>ratio ( str -- a/b )
"-" ?head dup negative? set swap
- "/" split1 (base>) >r whole-part r>
+ "/" split1 (base>) [ whole-part ] dip
3dup and and [ / + swap [ neg ] when ] [ 2drop 2drop f ] if ;
: valid-digits? ( seq -- ? )
[
[ numerator (>base) ]
[ denominator (>base) ] bi
- "/" swap 3append
+ "/" glue
] bi* append
negative? get [ CHAR: - prefix ] when
] with-radix ;
{
{
[ CHAR: e over member? ]
- [ "e" split1 >r fix-float "e" r> 3append ]
+ [ "e" split1 [ fix-float "e" ] dip 3append ]
} {
[ CHAR: . over member? ]
[ ]
} } ;
ARTICLE: "images" "Images"
-"The current image can be saved; the image contains a complete dump of all data and code in the current Factor instance:"
+"Factor has the ability to save the entire state of the system into an " { $emphasis "image file" } ". The image contains a complete dump of all data and code in the current Factor instance."
{ $subsection save }
{ $subsection save-image }
{ $subsection save-image-and-exit }
"To start Factor with a custom image, use the " { $snippet "-i=" { $emphasis "image" } } " command line switch; see " { $link "runtime-cli-args" } "."
$nl
+"One reason to save a custom image is if you find yourself loading the same libraries in every Factor session; some libraries take a little while to compile, so saving an image with those libraries loaded can save you a lot of time."
+$nl
+"For example, to save an image with the web framework loaded,"
+{ $code "USE: furnace" "save" }
"New images can be created from scratch:"
{ $subsection "bootstrap.image" }
-{ $see-also "tools.memory" "tools.deploy" } ;
+"The " { $link "tools.deploy" } " tool creates stripped-down images containing just enough code to run a single application."
+{ $see-also "tools.memory" } ;
ABOUT: "images"
USING: generic kernel kernel.private math memory prettyprint io
sequences tools.test words namespaces layouts classes
-classes.builtin arrays quotations ;
+classes.builtin arrays quotations io.launcher system ;
IN: memory.tests
+! LOL
+[ ] [
+ vm
+ "-i=" image append
+ "-generations=2"
+ "-e=USING: memory io prettyprint system ; input-stream gc . 0 exit"
+ 4array try-process
+] unit-test
+
[ [ ] instances ] must-infer
! Code GC wasn't kicking in when needed
IN: memory
: (each-object) ( quot: ( obj -- ) -- )
- [ next-object dup ] swap [ drop ] while ; inline
+ next-object dup [
+ swap [ call ] keep (each-object)
+ ] [ 2drop ] if ; inline recursive
: each-object ( quot -- )
begin-scan [ (each-object) ] [ end-scan ] [ ] cleanup ; inline
PRIVATE>
-: namespace ( -- namespace ) namestack* peek ;
+: namespace ( -- namespace ) namestack* peek ; inline
: namestack ( -- namestack ) namestack* clone ;
: set-namestack ( namestack -- ) >vector 0 setenv ;
: global ( -- g ) 21 getenv { hashtable } declare ; inline
: init-namespaces ( -- ) global 1array set-namestack ;
-: get ( variable -- value ) namestack* assoc-stack ; flushable
+: get ( variable -- value ) namestack* assoc-stack ; inline
: set ( value variable -- ) namespace set-at ;
: on ( variable -- ) t swap set ; inline
: off ( variable -- ) f swap set ; inline
: get-global ( variable -- value ) global at ;
: set-global ( value variable -- ) global set-at ;
-: change ( variable quot -- ) >r dup get r> rot slip set ; inline
+: change ( variable quot -- ) [ [ get ] keep ] dip dip set ; inline
: +@ ( n variable -- ) [ 0 or + ] change ;
: inc ( variable -- ) 1 swap +@ ; inline
: dec ( variable -- ) -1 swap +@ ; inline
: bind ( ns quot -- ) swap >n call ndrop ; inline
-: counter ( variable -- n ) global [ dup inc get ] bind ;
+: counter ( variable -- n ) global [ 0 or 1+ dup ] change-at ;
: make-assoc ( quot exemplar -- hash )
20 swap new-assoc [ >n call ndrop ] keep ; inline
H{ } clone >n call ndrop ; inline
: with-variable ( value key quot -- )
- >r associate >n r> call ndrop ; inline
+ [ associate >n ] dip call ndrop ; inline
}
"The " { $vocab-link "qualified" } " vocabulary contains some tools for helping with shadowing." ;
-ARTICLE: "vocabulary-search-errors" "Word lookup errors"
-"If the parser cannot not find a word in the current vocabulary search path, it attempts to look for the word in all loaded vocabularies. Then, one of three things happen:"
-{ $list
- { "If there are no words having this name at all, an error is thrown and parsing stops." }
- { "If there are vocabularies which contain words with this name, a restartable error is thrown, with a restart for each vocabulary in question. The restarts add the vocabulary to the search path and continue parsing." }
-}
-"When writing a new vocabulary, one approach is to ignore " { $link POSTPONE: USING: } " declarations altogether, then to load the vocabulary and observe any parser notes and restarts and use this information to write the correct " { $link POSTPONE: USING: } " declaration." ;
+ARTICLE: "vocabulary-search-errors" "Word lookup errors"
+"If the parser cannot not find a word in the current vocabulary search path, it attempts to look for the word in all loaded vocabularies."
+$nl
+"If " { $link auto-use? } " mode is off, a restartable error is thrown with a restart for each vocabulary in question, together with a restart which defers the word in the current vocabulary, as if " { $link POSTPONE: DEFER: } " was used."
+$nl
+"If " { $link auto-use? } " mode is on and only one vocabulary has a word with this name, the vocabulary is added to the search path and parsing continues."
+$nl
+"If any restarts were invoked, or if " { $link auto-use? } " is on, the parser will print the correct " { $link POSTPONE: USING: } " after parsing completes. This form can be copy and pasted back into the source file."
+{ $subsection auto-use? } ;
ARTICLE: "vocabulary-search" "Vocabulary search path"
"When the parser reads a token, it attempts to look up a word named by that token. The lookup is performed by searching each vocabulary in the search path, in order."
{ $description "Throws a " { $link staging-violation } " error." }
{ $error-description "Thrown by the parser if a parsing word is used in the same compilation unit as where it was defined; see " { $link "compilation-units" } "." }
{ $notes "One possible workaround is to use the " { $link POSTPONE: << } " word to execute code at parse time. However, executing words defined in the same source file at parse time is still prohibited." } ;
+
+HELP: auto-use?
+{ $var-description "If set to a true value, the behavior of the parser when encountering an unknown word name is changed. If only one loaded vocabulary has a word with this name, instead of throwing an error, the parser adds the vocabulary to the search path and prints a parse note. Off by default." }
+{ $notes "This feature is intended to help during development. To generate a " { $link POSTPONE: USING: } " form automatically, enable " { $link auto-use? } ", load the source file, and copy and paste the " { $link POSTPONE: USING: } " form printed by the parser back into the file, then disable " { $link auto-use? } ". See " { $link "vocabulary-search-errors" } "." } ;
io.streams.string namespaces classes effects source-files
assocs sequences strings io.files definitions continuations
sorting classes.tuple compiler.units debugger vocabs
-vocabs.loader accessors eval combinators ;
+vocabs.loader accessors eval combinators lexer ;
IN: parser.tests
+\ run-file must-infer
+
[
[ 1 [ 2 [ 3 ] 4 ] 5 ]
[ "1\n[\n2\n[\n3\n]\n4\n]\n5" eval ]
] times
[ "resource:core/parser/test/assert-depth.factor" run-file ]
-[ stack>> { 1 2 3 } sequence= ]
+[ got>> { 1 2 3 } sequence= ]
must-fail-with
2 [
"USE: this-better-not-exist" eval
] must-fail
-[ ": foo ;" eval ] [ error>> no-current-vocab? ] must-fail-with
+[ ": foo ;" eval ] [ error>> error>> no-current-vocab? ] must-fail-with
[ 92 ] [ "CHAR: \\" eval ] unit-test
[ 92 ] [ "CHAR: \\\\" eval ] unit-test
[ t ] [ "staging-problem-test-2" "parser.tests" lookup >boolean ] unit-test
-[ "DEFER: blah" eval ] [ error>> no-current-vocab? ] must-fail-with
+[ "DEFER: blah" eval ] [ error>> error>> no-current-vocab? ] must-fail-with
[
"IN: parser.tests : blah ; parsing FORGET: blah" eval
[ "IN: parser.tests USE: kernel TUPLE: blah < tuple ; : blah ; TUPLE: blah < tuple ; : blah ;" eval ]
[ error>> error>> def>> \ blah eq? ] must-fail-with
+
+[ ] [ f lexer set f file set "Hello world" note. ] unit-test
+
+[ "CHAR: \\u9999999999999" eval ] must-fail
: location ( -- loc )
file get lexer get line>> 2dup and
- [ >r path>> r> 2array ] [ 2drop f ] if ;
+ [ [ path>> ] dip 2array ] [ 2drop f ] if ;
: save-location ( definition -- )
location remember-definition ;
: note. ( str -- )
parser-notes? [
file get [ path>> write ":" write ] when*
- lexer get line>> number>string write ": " write
+ lexer get [ line>> number>string write ": " write ] when*
"Note: " write dup print
] when drop ;
M: parsing-word stack-effect drop (( parsed -- parsed )) ;
-ERROR: no-current-vocab ;
+TUPLE: no-current-vocab ;
+
+: no-current-vocab ( -- vocab )
+ \ no-current-vocab boa
+ { { "Define words in scratchpad vocabulary" "scratchpad" } }
+ throw-restarts dup set-in ;
: current-vocab ( -- str )
in get [ no-current-vocab ] unless* ;
: CREATE-WORD ( -- word ) CREATE dup reset-generic ;
-: word-restarts ( possibilities -- restarts )
- natural-sort [
- [
- "Use the " swap vocabulary>> " vocabulary" 3append
- ] keep
- ] { } map>assoc ;
+: word-restarts ( name possibilities -- restarts )
+ natural-sort
+ [ [ vocabulary>> "Use the " " vocabulary" surround ] keep ] { } map>assoc
+ swap "Defer word in current vocabulary" swap 2array
+ suffix ;
ERROR: no-word-error name ;
+: <no-word-error> ( name possibilities -- error restarts )
+ [ drop \ no-word-error boa ] [ word-restarts ] 2bi ;
+
+SYMBOL: amended-use
+
+SYMBOL: auto-use?
+
+: no-word-restarted ( restart-value -- word )
+ dup word? [
+ dup vocabulary>>
+ [ (use+) ]
+ [ amended-use get dup [ push ] [ 2drop ] if ]
+ [ "Added ``" "'' vocabulary to search path" surround note. ]
+ tri
+ ] [ create-in ] if ;
+
: no-word ( name -- newword )
- dup \ no-word-error boa
- swap words-named [ forward-reference? not ] filter
- word-restarts throw-restarts
- dup vocabulary>> (use+) ;
+ dup words-named [ forward-reference? not ] filter
+ dup length 1 = auto-use? get and
+ [ nip first no-word-restarted ]
+ [ <no-word-error> throw-restarts no-word-restarted ]
+ if ;
: check-forward ( str word -- word/f )
dup forward-reference? [
} cond ;
: (parse-until) ( accum end -- accum )
- dup >r parse-step [ r> (parse-until) ] [ r> drop ] if ;
+ [ parse-step ] keep swap [ (parse-until) ] [ drop ] if ;
: parse-until ( end -- vec )
100 <vector> swap (parse-until) ;
: parsed ( accum obj -- accum ) over push ;
: (parse-lines) ( lexer -- quot )
- [ f parse-until >quotation ] with-lexer ;
+ [
+ f parse-until >quotation
+ ] with-lexer ;
: parse-lines ( lines -- quot )
lexer-factory get call (parse-lines) ;
: parse-literal ( accum end quot -- accum )
- >r parse-until r> call parsed ; inline
+ [ parse-until ] dip call parsed ; inline
: parse-definition ( -- quot )
\ ; parse-until >quotation ;
call
] with-scope ; inline
+SYMBOL: print-use-hook
+
+print-use-hook global [ [ ] or ] change-at
+!
: parse-fresh ( lines -- quot )
- [ parse-lines ] with-file-vocabs ;
+ [
+ V{ } clone amended-use set
+ parse-lines
+ amended-use get empty? [ print-use-hook get call ] unless
+ ] with-file-vocabs ;
: parsing-file ( file -- )
- "quiet" get [
- drop
- ] [
- "Loading " write print flush
- ] if ;
+ "quiet" get [ drop ] [ "Loading " write print flush ] if ;
: filter-moved ( assoc1 assoc2 -- seq )
swap assoc-diff [
] with-compilation-unit ;
: parse-file-restarts ( file -- restarts )
- "Load " swap " again" 3append t 2array 1array ;
+ "Load " " again" surround t 2array 1array ;
: parse-file ( file -- quot )
[
] recover ;
: run-file ( file -- )
- [ dup parse-file call ] assert-depth drop ;
+ [ parse-file call ] curry assert-depth ;
: ?run-file ( path -- )
dup exists? [ run-file ] [ drop ] if ;
[ [ "hi" ] ] [ "hi" 1quotation ] unit-test
-! [ 1 \ + curry ] must-fail
+[ 1 \ + curry ] must-fail
M: curry length quot>> length 1+ ;
M: curry nth
- over zero? [ nip obj>> literalize ] [ >r 1- r> quot>> nth ] if ;
+ over 0 =
+ [ nip obj>> literalize ]
+ [ [ 1- ] dip quot>> nth ]
+ if ;
INSTANCE: curry immutable-sequence
M: string new-resizable drop <sbuf> ;
M: string like
+ #! If we have a string, we're done.
+ #! If we have an sbuf, and it's at full capacity, we're done.
+ #! Otherwise, call resize-string, which is a relatively
+ #! fast primitive.
drop dup string? [
dup sbuf? [
- dup length over underlying>> length eq? [
- underlying>> dup reset-string-hashcode
- ] [
- >string
- ] if
- ] [
- >string
- ] if
+ [ length ] [ underlying>> ] bi
+ 2dup length eq?
+ [ nip dup reset-string-hashcode ] [ resize-string ] if
+ ] [ >string ] if
] unless ;
INSTANCE: sbuf growable
USING: arrays help.markup help.syntax math
sequences.private vectors strings kernel math.order layouts
-quotations ;
+quotations generic.standard ;
IN: sequences
HELP: sequence
HELP: set-length
{ $values { "n" "a non-negative integer" } { "seq" "a resizable sequence" } }
-{ $contract "Resizes the sequence. Not all sequences are resizable." }
-{ $errors "Throws a " { $link bounds-error } " if the new length is negative." }
+{ $contract "Resizes a sequence. The initial contents of the new area is undefined." }
+{ $errors "Throws a " { $link no-method } " error if the sequence is not resizable, and a " { $link bounds-error } " if the new length is negative." }
{ $side-effects "seq" } ;
HELP: lengthen
HELP: new-sequence
{ $values { "len" "a non-negative integer" } { "seq" sequence } { "newseq" "a mutable sequence" } }
-{ $contract "Outputs a mutable sequence of length " { $snippet "n" } " which can hold the elements of " { $snippet "seq" } "." } ;
+{ $contract "Outputs a mutable sequence of length " { $snippet "n" } " which can hold the elements of " { $snippet "seq" } ". The initial contents of the sequence are undefined." } ;
HELP: new-resizable
{ $values { "len" "a non-negative integer" } { "seq" sequence } { "newseq" "a resizable mutable sequence" } }
{ $description "Applies " { $snippet "quot" } " to each element in turn, also invoking " { $snippet "between" } " in-between each pair of elements." }
{ $example "USING: io sequences ;" "{ \"a\" \"b\" \"c\" } [ \"X\" write ] [ write ] interleave" "aXbXc" } ;
-HELP: cache-nth
-{ $values { "i" "a non-negative integer" } { "seq" "a mutable sequence" } { "quot" { $quotation "( i -- elt )" } } { "elt" object } }
-{ $description "If the sequence does not contain at least " { $snippet "i" } " elements or if the " { $snippet "i" } "th element of the sequence is " { $link f } ", calls the quotation to produce a new value, and stores it back into the sequence. Otherwise, this word outputs the " { $snippet "i" } "th element of the sequence." }
-{ $side-effects "seq" } ;
-
HELP: index
{ $values { "obj" object } { "seq" sequence } { "n" "an index" } }
{ $description "Outputs the index of the first element in the sequence equal to " { $snippet "obj" } ". If no element is found, outputs " { $link f } "." } ;
}
} ;
+HELP: surround
+{ $values { "seq1" sequence } { "seq2" sequence } { "seq3" sequence } { "newseq" sequence } }
+{ $description "Outputs a new sequence with " { $snippet "seq1" } " inserted between " { $snippet "seq2" } " and " { $snippet "seq3" } "." }
+{ $examples
+ { $example "USING: sequences prettyprint ;"
+ "\"sssssh\" \"(\" \")\" surround ."
+ "\"(sssssh)\""
+ }
+} ;
+
+HELP: glue
+{ $values { "seq1" sequence } { "seq2" sequence } { "seq3" sequence } { "newseq" sequence } }
+{ $description "Outputs a new sequence with " { $snippet "seq3" } " inserted between " { $snippet "seq1" } " and " { $snippet "seq2" } "." }
+{ $examples
+ { $example "USING: sequences prettyprint ;"
+ "\"a\" \"b\" \",\" glue ."
+ "\"a,b\""
+ }
+} ;
+
HELP: subseq
{ $values { "from" "a non-negative integer" } { "to" "a non-negative integer" } { "seq" sequence } { "subseq" "a new sequence" } }
{ $description "Outputs a new sequence consisting of all elements starting from and including " { $snippet "from" } ", and up to but not including " { $snippet "to" } "." }
{ $subsection append }
{ $subsection prepend }
{ $subsection 3append }
+{ $subsection surround }
+{ $subsection glue }
{ $subsection concat }
{ $subsection join }
"A pair of words useful for aligning strings:"
"Changing elements:"
{ $subsection change-each }
{ $subsection change-nth }
-{ $subsection cache-nth }
"Deleting elements:"
{ $subsection delete }
{ $subsection delq }
[ V{ "a" "b" } V{ } ] [ { "X" "a" "b" } { "X" } drop-prefix [ >vector ] bi@ ] unit-test
-[ 1 4 9 16 16 V{ f 1 4 9 16 } ] [
- V{ } clone "cache-test" set
- 1 "cache-test" get [ sq ] cache-nth
- 2 "cache-test" get [ sq ] cache-nth
- 3 "cache-test" get [ sq ] cache-nth
- 4 "cache-test" get [ sq ] cache-nth
- 4 "cache-test" get [ "wrong" ] cache-nth
- "cache-test" get
-] unit-test
-
[ 1 ] [ 0.5 { 1 2 3 } nth ] unit-test
! Pathological case
[ { 1 3 "X" 5 7 } ] [ "X" 2 { 1 3 5 7 } insert-nth ] unit-test
[ V{ 0 2 } ] [ "a" { "a" "b" "a" } indices ] unit-test
+
+[ "a,b" ] [ "a" "b" "," glue ] unit-test
+[ "(abc)" ] [ "abc" "(" ")" surround ] unit-test
GENERIC: clone-like ( seq exemplar -- newseq ) flushable
: new-like ( len exemplar quot -- seq )
- over >r >r new-sequence r> call r> like ; inline
+ over [ [ new-sequence ] dip call ] dip like ; inline
M: sequence like drop ;
INSTANCE: integer immutable-sequence
+: first-unsafe
+ 0 swap nth-unsafe ; inline
+
: first2-unsafe
- [ 0 swap nth-unsafe 1 ] [ nth-unsafe ] bi ; inline
+ [ first-unsafe ] [ 1 swap nth-unsafe ] bi ; inline
: first3-unsafe
- [ first2-unsafe 2 ] [ nth-unsafe ] bi ; inline
+ [ first2-unsafe ] [ 2 swap nth-unsafe ] bi ; inline
: first4-unsafe
- [ first3-unsafe 3 ] [ nth-unsafe ] bi ; inline
+ [ first3-unsafe ] [ 3 swap nth-unsafe ] bi ; inline
: exchange-unsafe ( m n seq -- )
- [ tuck nth-unsafe >r nth-unsafe r> ] 3keep tuck
- >r >r set-nth-unsafe r> r> set-nth-unsafe ; inline
+ [ tuck [ nth-unsafe ] 2bi@ ]
+ [ tuck [ set-nth-unsafe ] 2bi@ ] 3bi ; inline
: (head) ( seq n -- from to seq ) 0 spin ; inline
: (tail) ( seq n -- from to seq ) over length rot ; inline
-: from-end >r dup length r> - ; inline
+: from-end [ dup length ] dip - ; inline
: (2sequence)
tuck 1 swap set-nth-unsafe
{ seq read-only } ;
: collapse-slice ( m n slice -- m' n' seq )
- [ from>> ] [ seq>> ] bi >r tuck + >r + r> r> ; inline
+ [ from>> ] [ seq>> ] bi [ tuck [ + ] 2bi@ ] dip ; inline
-ERROR: slice-error reason ;
+ERROR: slice-error from to seq reason ;
: check-slice ( from to seq -- from to seq )
pick 0 < [ "start < 0" slice-error ] when
: prepare-subseq ( from to seq -- dst i src j n )
#! The check-length call forces partial dispatch
- [ >r swap - r> new-sequence dup 0 ] 3keep
+ [ [ swap - ] dip new-sequence dup 0 ] 3keep
-rot drop roll length check-length ; inline
: check-copy ( src n dst -- )
over 0 < [ bounds-error ] when
- >r swap length + r> lengthen ; inline
+ [ swap length + ] dip lengthen ; inline
PRIVATE>
: copy ( src i dst -- )
#! The check-length call forces partial dispatch
- pick length check-length >r 3dup check-copy spin 0 r>
+ pick length check-length [ 3dup check-copy spin 0 ] dip
(copy) drop ; inline
M: sequence clone-like
- >r dup length r> new-sequence [ 0 swap copy ] keep ;
+ [ dup length ] dip new-sequence [ 0 swap copy ] keep ;
M: immutable-sequence clone-like like ;
<PRIVATE
-: ((append)) ( seq1 seq2 accum -- accum )
- [ >r over length r> copy ]
- [ 0 swap copy ]
+: (append) ( seq1 seq2 accum -- accum )
+ [ [ over length ] dip copy ]
+ [ 0 swap copy ]
[ ] tri ; inline
-: (append) ( seq1 seq2 exemplar -- newseq )
- >r over length over length + r>
- [ ((append)) ] new-like ; inline
+PRIVATE>
-: (3append) ( seq1 seq2 seq3 exemplar -- newseq )
- >r pick length pick length pick length + + r> [
- [ >r pick length pick length + r> copy ]
- [ ((append)) ] bi
- ] new-like ; inline
+: append-as ( seq1 seq2 exemplar -- newseq )
+ [ over length over length + ] dip
+ [ (append) ] new-like ; inline
-PRIVATE>
+: 3append-as ( seq1 seq2 seq3 exemplar -- newseq )
+ [ pick length pick length pick length + + ] dip [
+ [ [ pick length pick length + ] dip copy ]
+ [ (append) ] bi
+ ] new-like ; inline
-: append ( seq1 seq2 -- newseq ) over (append) ;
+: append ( seq1 seq2 -- newseq ) over append-as ;
: prepend ( seq1 seq2 -- newseq ) swap append ; inline
-: 3append ( seq1 seq2 seq3 -- newseq ) pick (3append) ;
+: 3append ( seq1 seq2 seq3 -- newseq ) pick 3append-as ;
+
+: surround ( seq1 seq2 seq3 -- newseq ) swapd 3append ; inline
+
+: glue ( seq1 seq2 seq3 -- newseq ) swap 3append ; inline
: change-nth ( i seq quot -- )
- [ >r nth r> call ] 3keep drop set-nth ; inline
+ [ [ nth ] dip call ] 3keep drop set-nth ; inline
: min-length ( seq1 seq2 -- n ) [ length ] bi@ min ; inline
<PRIVATE
: (each) ( seq quot -- n quot' )
- >r dup length swap [ nth-unsafe ] curry r> compose ; inline
+ [ dup length swap [ nth-unsafe ] curry ] dip compose ; inline
: (collect) ( quot into -- quot' )
- [ >r keep r> set-nth-unsafe ] 2curry ; inline
+ [ [ keep ] dip set-nth-unsafe ] 2curry ; inline
: collect ( n quot into -- )
(collect) each-integer ; inline
: map-into ( seq quot into -- )
- >r (each) r> collect ; inline
+ [ (each) ] dip collect ; inline
: 2nth-unsafe ( n seq1 seq2 -- elt1 elt2 )
- >r over r> nth-unsafe >r nth-unsafe r> ; inline
+ [ over ] dip [ nth-unsafe ] 2bi@ ; inline
: (2each) ( seq1 seq2 quot -- n quot' )
- >r [ min-length ] 2keep r>
- [ >r 2nth-unsafe r> call ] 3curry ; inline
+ [ [ min-length ] 2keep ] dip
+ [ [ 2nth-unsafe ] dip call ] 3curry ; inline
: 2map-into ( seq1 seq2 quot into -- newseq )
- >r (2each) r> collect ; inline
+ [ (2each) ] dip collect ; inline
: finish-find ( i seq -- i elt )
over [ dupd nth-unsafe ] [ drop f ] if ; inline
: (find) ( seq quot quot' -- i elt )
- pick >r >r (each) r> call r> finish-find ; inline
+ pick [ [ (each) ] dip call ] dip finish-find ; inline
: (find-from) ( n seq quot quot' -- i elt )
[ 2dup bounds-check? ] 2dip
swapd each ; inline
: map-as ( seq quot exemplar -- newseq )
- >r over length r> [ [ map-into ] keep ] new-like ; inline
+ [ over length ] dip [ [ map-into ] keep ] new-like ; inline
: map ( seq quot -- newseq )
over map-as ; inline
[ drop ] prepose map ; inline
: replicate-as ( seq quot exemplar -- newseq )
- >r [ drop ] prepose r> map-as ; inline
+ [ [ drop ] prepose ] dip map-as ; inline
: change-each ( seq quot -- )
over map-into ; inline
(2each) each-integer ; inline
: 2reverse-each ( seq1 seq2 quot -- )
- >r [ <reversed> ] bi@ r> 2each ; inline
+ [ [ <reversed> ] bi@ ] dip 2each ; inline
: 2reduce ( seq1 seq2 identity quot -- result )
- >r -rot r> 2each ; inline
+ [ -rot ] dip 2each ; inline
: 2map-as ( seq1 seq2 quot exemplar -- newseq )
- >r 2over min-length r>
+ [ 2over min-length ] dip
[ [ 2map-into ] keep ] new-like ; inline
: 2map ( seq1 seq2 quot -- newseq )
[ nip find-last-integer ] (find-from) ; inline
: find-last ( seq quot -- i elt )
- [ >r 1- r> find-last-integer ] (find) ; inline
+ [ [ 1- ] dip find-last-integer ] (find) ; inline
: all? ( seq quot -- ? )
(each) all-integers? ; inline
: push-if ( elt quot accum -- )
- >r keep r> rot [ push ] [ 2drop ] if ; inline
+ [ keep ] dip rot [ push ] [ 2drop ] if ; inline
: pusher ( quot -- quot accum )
V{ } clone [ [ push-if ] 2curry ] keep ; inline
: filter ( seq quot -- subseq )
- over >r pusher >r each r> r> like ; inline
+ over [ pusher [ each ] dip ] dip like ; inline
: push-either ( elt quot accum1 accum2 -- )
- >r >r keep swap r> r> ? push ; inline
+ [ keep swap ] 2dip ? push ; inline
: 2pusher ( quot -- quot accum1 accum2 )
V{ } clone V{ } clone [ [ push-either ] 3curry ] 2keep ; inline
: partition ( seq quot -- trueseq falseseq )
- over >r 2pusher >r >r each r> r> r> tuck [ like ] 2bi@ ; inline
+ over [ 2pusher [ each ] 2dip ] dip tuck [ like ] 2bi@ ; inline
: monotonic? ( seq quot -- ? )
- >r dup length 1- swap r> (monotonic) all? ; inline
+ [ dup length 1- swap ] dip (monotonic) all? ; inline
: interleave ( seq between quot -- )
- [ (interleave) ] 2curry >r dup length swap r> 2each ; inline
+ [ (interleave) ] 2curry [ dup length swap ] dip 2each ; inline
: accumulator ( quot -- quot' vec )
V{ } clone [ [ push ] curry compose ] keep ; inline
: produce-as ( pred quot tail exemplar -- seq )
- >r swap accumulator >r swap while r> r> like ; inline
+ [ swap accumulator [ swap while ] dip ] dip like ; inline
: produce ( pred quot tail -- seq )
{ } produce-as ; inline
: follow ( obj quot -- seq )
- >r [ dup ] r> [ keep ] curry [ ] produce nip ; inline
+ [ dup ] swap [ keep ] curry [ ] produce nip ; inline
: prepare-index ( seq quot -- seq n quot )
- >r dup length r> ; inline
+ [ dup length ] dip ; inline
: each-index ( seq quot -- )
prepare-index 2each ; inline
: harvest ( seq -- newseq )
[ empty? not ] filter ;
-: cache-nth ( i seq quot -- elt )
- 2over ?nth dup [
- >r 3drop r>
- ] [
- drop swap >r over >r call dup r> r> set-nth
- ] if ; inline
-
: mismatch ( seq1 seq2 -- i )
[ min-length ] 2keep
[ 2nth-unsafe = not ] 2curry
: sequence-hashcode-step ( oldhash newpart -- newhash )
>fixnum swap [
- dup -2 fixnum-shift-fast swap 5 fixnum-shift-fast
+ [ -2 fixnum-shift-fast ] [ 5 fixnum-shift-fast ] bi
fixnum+fast fixnum+fast
] keep fixnum-bitxor ; inline
: sequence-hashcode ( n seq -- x )
- 0 -rot [ hashcode* sequence-hashcode-step ] with each ; inline
+ [ 0 ] 2dip [ hashcode* sequence-hashcode-step ] with each ; inline
M: reversed equal? over reversed? [ sequence= ] [ 2drop f ] if ;
[ eq? not ] with filter-here ;
: prefix ( seq elt -- newseq )
- over >r over length 1+ r> [
+ over [ over length 1+ ] dip [
[ 0 swap set-nth-unsafe ] keep
[ 1 swap copy ] keep
] new-like ;
: suffix ( seq elt -- newseq )
- over >r over length 1+ r> [
- [ >r over length r> set-nth-unsafe ] keep
+ over [ over length 1+ ] dip [
+ [ [ over length ] dip set-nth-unsafe ] keep
[ 0 swap copy ] keep
] new-like ;
2over = [
2drop 2drop
] [
- [ >r 2over + pick r> move >r 1+ r> ] keep
+ [ [ 2over + pick ] dip move [ 1+ ] dip ] keep
move-backward
] if ;
2over = [
2drop 2drop
] [
- [ >r pick >r dup dup r> + swap r> move 1- ] keep
+ [ [ pick [ dup dup ] dip + swap ] dip move 1- ] keep
move-forward
] if ;
: (open-slice) ( shift from to seq ? -- )
[
- >r [ 1- ] bi@ r> move-forward
+ [ [ 1- ] bi@ ] dip move-forward
] [
- >r >r over - r> r> move-backward
+ [ over - ] 2dip move-backward
] if ;
PRIVATE>
pick 0 = [
3drop
] [
- pick over length + over >r >r
- pick 0 > >r [ length ] keep r> (open-slice)
- r> r> set-length
+ pick over length + over
+ [ pick 0 > [ [ length ] keep ] dip (open-slice) ] 2dip
+ set-length
] if ;
: delete-slice ( from to seq -- )
- check-slice >r over >r - r> r> open-slice ;
+ check-slice [ over [ - ] dip ] dip open-slice ;
: delete-nth ( n seq -- )
- >r dup 1+ r> delete-slice ;
+ [ dup 1+ ] dip delete-slice ;
: replace-slice ( new from to seq -- )
- [ >r >r dup pick length + r> - over r> open-slice ] keep
+ [ [ [ dup pick length + ] dip - over ] dip open-slice ] keep
copy ;
: remove-nth ( n seq -- seq' )
: reverse-here ( seq -- )
dup length dup 2/ [
- >r 2dup r>
+ [ 2dup ] dip
tuck - 1- rot exchange-unsafe
] each 2drop ;
<PRIVATE
: joined-length ( seq glue -- n )
- >r dup sum-lengths swap length 1 [-] r> length * + ;
+ [ dup sum-lengths swap length 1 [-] ] dip length * + ;
PRIVATE>
] dip compose if ; inline
: pad-left ( seq n elt -- padded )
- [ swap dup (append) ] padding ;
+ [ swap dup append-as ] padding ;
: pad-right ( seq n elt -- padded )
[ append ] padding ;
>fixnum {
[ drop nip ]
[ 2drop first ]
- [ >r drop first2 r> call ]
- [ >r drop first3 r> bi@ ]
+ [ [ drop first2 ] dip call ]
+ [ [ drop first3 ] dip bi@ ]
} dispatch
] [
drop
- >r >r halves r> r>
+ [ halves ] 2dip
[ [ binary-reduce ] 2curry bi@ ] keep
call
] if ; inline recursive
: (start) ( subseq seq n -- subseq seq ? )
pick length [
- >r 3dup r> [ + swap nth-unsafe ] keep rot nth-unsafe =
+ [ 3dup ] dip [ + swap nth-unsafe ] keep rot nth-unsafe =
] all? nip ; inline
PRIVATE>
: start* ( subseq seq n -- i )
pick length pick length swap - 1+
[ (start) ] find-from
- swap >r 3drop r> ;
+ swap [ 3drop ] dip ;
: start ( subseq seq -- i ) 0 start* ; inline
: drop-prefix ( seq1 seq2 -- slice1 slice2 )
2dup mismatch [ 2dup min-length ] unless*
- tuck tail-slice >r tail-slice r> ;
+ tuck [ tail-slice ] 2bi@ ;
: unclip ( seq -- rest first )
- [ rest ] [ first ] bi ;
+ [ rest ] [ first-unsafe ] bi ;
: unclip-last ( seq -- butlast last )
[ but-last ] [ peek ] bi ;
: unclip-slice ( seq -- rest-slice first )
- [ rest-slice ] [ first ] bi ; inline
+ [ rest-slice ] [ first-unsafe ] bi ; inline
: 2unclip-slice ( seq1 seq2 -- rest-slice1 rest-slice2 first1 first2 )
[ unclip-slice ] bi@ swapd ; inline
inline
: trim-left-slice ( seq quot -- slice )
- over >r [ not ] compose find drop r> swap
+ over [ [ not ] compose find drop ] dip swap
[ tail-slice ] [ dup length tail-slice ] if* ; inline
: trim-left ( seq quot -- newseq )
over [ trim-left-slice ] dip like ; inline
: trim-right-slice ( seq quot -- slice )
- over >r [ not ] compose find-last drop r> swap
+ over [ [ not ] compose find-last drop ] dip swap
[ 1+ head-slice ] [ 0 head-slice ] if* ; inline
: trim-right ( seq quot -- newseq )
: supremum ( seq -- n ) dup first [ max ] reduce ;
-: flip ( matrix -- newmatrix )
- dup empty? [
- dup [ length ] map infimum
- swap [ [ nth-unsafe ] with { } map-as ] curry { } map-as
- ] unless ;
-
: sigma ( seq quot -- n ) [ + ] compose 0 swap reduce ; inline
: count ( seq quot -- n ) [ 1 0 ? ] compose sigma ; inline
+
+! We hand-optimize flip to such a degree because type hints
+! cannot express that an array is an array of arrays yet, and
+! this word happens to be performance-critical since the compiler
+! itself uses it. Optimizing it like this reduced compile time.
+<PRIVATE
+
+: generic-flip ( matrix -- newmatrix )
+ [ dup first length [ length min ] reduce ] keep
+ [ [ nth-unsafe ] with { } map-as ] curry { } map-as ; inline
+
+USE: arrays
+
+: array-length ( array -- len )
+ { array } declare length>> ; inline
+
+: array-flip ( matrix -- newmatrix )
+ { array } declare
+ [ dup first array-length [ array-length min ] reduce ] keep
+ [ [ array-nth ] with { } map-as ] curry { } map-as ;
+
+PRIVATE>
+
+: flip ( matrix -- newmatrix )
+ dup empty? [
+ dup array? [
+ dup [ array? ] all?
+ [ array-flip ] [ generic-flip ] if
+ ] [ generic-flip ] if
+ ] unless ;
USING: arrays byte-arrays kernel kernel.private math namespaces
make sequences strings words effects generic generic.standard
classes classes.algebra slots.private combinators accessors
-words sequences.private assocs alien ;
+words sequences.private assocs alien quotations ;
IN: slots
TUPLE: slot-spec name offset class initial read-only ;
3bi ;
: create-accessor ( name effect -- word )
- >r "accessors" create dup r>
+ [ "accessors" create dup ] dip
"declared-effect" set-word-prop ;
: reader-quot ( slot-spec -- quot )
define-typecheck ;
: writer-word ( name -- word )
- "(>>" swap ")" 3append (( value object -- )) create-accessor
+ "(>>" ")" surround (( value object -- )) create-accessor
dup t "writer" set-word-prop ;
ERROR: bad-slot-value value class ;
offset>> , \ set-slot , ;
: writer-quot/coerce ( slot-spec -- )
- [ \ >r , class>> "coercer" word-prop % \ r> , ]
+ [ class>> "coercer" word-prop [ dip ] curry % ]
[ offset>> , \ set-slot , ]
bi ;
bi ;
: writer-quot/fixnum ( slot-spec -- )
- [ >r >fixnum r> ] % writer-quot/check ;
+ [ [ >fixnum ] dip ] % writer-quot/check ;
: writer-quot ( slot-spec -- quot )
[
: define-changer ( name -- )
dup changer-word dup deferred? [
[
- [ over >r >r ] %
- over reader-word ,
- [ r> call r> swap ] %
+ \ over ,
+ over reader-word 1quotation
+ [ dip call ] curry [ dip swap ] curry %
swap setter-word ,
] [ ] make define-inline
] [ 2drop ] if ;
swap
peel-off-name
peel-off-class
- [ dup empty? not ] [ peel-off-attributes ] [ ] while drop
+ [ dup empty? ] [ peel-off-attributes ] [ ] until drop
check-initial-value ;
M: slot-spec make-slot
: dump ( from to seq accum -- )
#! Optimize common case where to - from = 1, 2, or 3.
- >r >r 2dup swap - r> r> pick 1 =
- [ >r >r 2drop r> nth-unsafe r> push ] [
+ [ 2dup swap - ] 2dip pick 1 =
+ [ [ [ 2drop ] dip nth-unsafe ] dip push ] [
pick 2 = [
- >r >r 2drop dup 1+
- r> [ nth-unsafe ] curry bi@
- r> [ push ] curry bi@
+ [
+ [ 2drop dup 1+ ] dip
+ [ nth-unsafe ] curry bi@
+ ] dip [ push ] curry bi@
] [
pick 3 = [
- >r >r 2drop dup 1+ dup 1+
- r> [ nth-unsafe ] curry tri@
- r> [ push ] curry tri@
- ] [
- >r nip subseq r> push-all
- ] if
+ [
+ [ 2drop dup 1+ dup 1+ ] dip
+ [ nth-unsafe ] curry tri@
+ ] dip [ push ] curry tri@
+ ] [ [ nip subseq ] dip push-all ] if
] if
] if ; inline
SYMBOL: file
-TUPLE: source-file-error file error ;
+TUPLE: source-file-error error file ;
: <source-file-error> ( msg -- error )
\ source-file-error new
{ $subsection ?tail }
{ $subsection ?tail-slice }
{ $subsection split1 }
+{ $subsection split1-slice }
+{ $subsection split1-last }
+{ $subsection split1-last-slice }
{ $subsection split }
"Splitting a string into lines:"
{ $subsection string-lines } ;
{ $values { "seq" "a sequence" } { "subseq" "a sequence" } { "before" "a new sequence" } { "after" "a new sequence" } }
{ $description "Splits " { $snippet "seq" } " at the first occurrence of " { $snippet "subseq" } ", and outputs the pieces before and after the split. If " { $snippet "subseq" } " does not occur in " { $snippet "seq" } ", then " { $snippet "before" } " is just " { $snippet "seq" } " and " { $snippet "after" } " is " { $link f } "." } ;
-HELP: last-split1
+HELP: split1-slice
+{ $values { "seq" "a sequence" } { "subseq" "a sequence" } { "before-slice" slice } { "after-slice" slice } }
+{ $description "Splits " { $snippet "seq" } " at the first occurrence of " { $snippet "subseq" } ", and outputs the pieces before and after the split as slices. If " { $snippet "subseq" } " does not occur in " { $snippet "seq" } ", then " { $snippet "before" } " is just " { $snippet "seq" } " and " { $snippet "after" } " is " { $link f } "." } ;
+
+HELP: split1-last
{ $values { "seq" "a sequence" } { "subseq" "a sequence" } { "before" "a new sequence" } { "after" "a new sequence" } }
{ $description "Splits " { $snippet "seq" } " at the last occurrence of " { $snippet "subseq" } ", and outputs the pieces before and after the split. If " { $snippet "subseq" } " does not occur in " { $snippet "seq" } ", then " { $snippet "before" } " is just " { $snippet "seq" } " and " { $snippet "after" } " is " { $link f } "." } ;
-{ split1 last-split1 } related-words
+HELP: split1-last-slice
+{ $values { "seq" "a sequence" } { "subseq" "a sequence" } { "before-slice" slice } { "after-slice" slice } }
+{ $description "Splits " { $snippet "seq" } " at the last occurrence of " { $snippet "subseq" } ", and outputs the pieces before and after the split as slices. If " { $snippet "subseq" } " does not occur in " { $snippet "seq" } ", then " { $snippet "before" } " is just " { $snippet "seq" } " and " { $snippet "after" } " is " { $link f } "." } ;
+
+{ split1 split1-slice split1-last split1-last-slice } related-words
HELP: split
{ $values { "seq" "a sequence" } { "separators" "a sequence" } { "pieces" "a new array" } }
-USING: splitting tools.test kernel sequences arrays ;
+USING: splitting tools.test kernel sequences arrays strings ;
IN: splitting.tests
[ "hello" "world ." ] [ "hello world ." " " split1 ] unit-test
[ "goodbye" f ] [ "goodbye" " " split1 ] unit-test
[ "" "" ] [ "great" "great" split1 ] unit-test
-[ "hello world" "." ] [ "hello world ." " " last-split1 ] unit-test
-[ "hello-+world" "." ] [ "hello-+world-+." "-+" last-split1 ] unit-test
-[ "goodbye" f ] [ "goodbye" " " last-split1 ] unit-test
-[ "" "" ] [ "great" "great" last-split1 ] unit-test
+[ "hello world" "." ] [ "hello world ." " " split1-last ] unit-test
+[ "hello-+world" "." ] [ "hello-+world-+." "-+" split1-last ] unit-test
+[ "goodbye" f ] [ "goodbye" " " split1-last ] unit-test
+[ "" "" ] [ "great" "great" split1-last ] unit-test
+
+[ "hello world" "." ] [ "hello world ." " " split1-last-slice [ >string ] bi@ ] unit-test
+[ "hello-+world" "." ] [ "hello-+world-+." "-+" split1-last-slice [ >string ] bi@ ] unit-test
+[ "goodbye" f ] [ "goodbye" " " split1-last-slice [ >string ] dip ] unit-test
+[ "" f ] [ "great" "great" split1-last-slice [ >string ] dip ] unit-test
[ "and end" t ] [ "Beginning and end" "Beginning " ?head ] unit-test
[ "Beginning and end" f ] [ "Beginning and end" "Beginning x" ?head ] unit-test
: split1 ( seq subseq -- before after )
dup pick start dup [
- [ >r over r> head -rot length ] keep + tail
+ [ [ over ] dip head -rot length ] keep + tail
] [
2drop f
] if ;
-: last-split1 ( seq subseq -- before after )
+: split1-slice ( seq subseq -- before-slice after-slice )
+ dup pick start dup [
+ [ [ over ] dip head-slice -rot length ] keep + tail-slice
+ ] [
+ 2drop f
+ ] if ;
+
+: split1-last ( seq subseq -- before after )
[ <reversed> ] bi@ split1 [ reverse ] bi@
dup [ swap ] when ;
+: split1-last-slice ( seq subseq -- before-slice after-slice )
+ [ <reversed> ] bi@ split1-slice [ <reversed> ] bi@
+ [ f ] [ swap ] if-empty ;
+
: (split) ( separators n seq -- )
3dup rot [ member? ] curry find-from drop
[ [ swap subseq , ] 2keep 1+ swap (split) ]
--- /dev/null
+IN: strings.parser.tests
+USING: strings.parser tools.test ;
+
+[ "Hello\n\rworld" ] [ "Hello\\n\\rworld" unescape-string ] unit-test
: unicode-escape ( str -- ch str' )
"{" ?head-slice [
CHAR: } over index cut-slice
- >r >string name>char-hook get call r>
+ [ >string name>char-hook get call ] dip
rest-slice
] [
- 6 cut-slice >r hex> r>
+ 6 cut-slice [ hex> ] dip
] if ;
: next-escape ( str -- ch str' )
: (parse-string) ( str -- m )
dup [ "\"\\" member? ] find dup [
- >r cut-slice >r % r> rest-slice r>
+ [ cut-slice [ % ] dip rest-slice ] dip
dup CHAR: " = [
drop from>>
] [
- drop next-escape >r , r> (parse-string)
+ drop next-escape [ , ] dip (parse-string)
] if
] [
"Unterminated string" throw
lexer get [
[ swap tail-slice (parse-string) ] "" make swap
] change-lexer-column ;
+
+: (unescape-string) ( str -- str' )
+ dup [ CHAR: \\ = ] find [
+ cut-slice [ % ] dip rest-slice
+ next-escape [ , ] dip
+ (unescape-string)
+ ] [
+ drop %
+ ] if ;
+
+: unescape-string ( str -- str' )
+ [ (unescape-string) ] "" make ;
: rehash-string ( str -- )
1 over sequence-hashcode swap set-string-hashcode ; inline
+: set-string-nth ( ch n str -- )
+ pick HEX: 7f fixnum<=
+ [ set-string-nth-fast ] [ set-string-nth-slow ] if ; inline
+
PRIVATE>
M: string equal?
] if ;
M: string hashcode*
- nip dup string-hashcode [ ]
- [ dup rehash-string string-hashcode ] ?if ;
+ nip
+ dup string-hashcode
+ [ ] [ dup rehash-string string-hashcode ] ?if ;
M: string length
length>> ;
M: string nth-unsafe
- >r >fixnum r> string-nth ;
+ [ >fixnum ] dip string-nth ;
M: string set-nth-unsafe
dup reset-string-hashcode
- >r >fixnum >r >fixnum r> r> set-string-nth ;
+ [ >fixnum ] [ >fixnum ] [ ] tri* set-string-nth ;
M: string clone
(clone) [ clone ] change-aux ;
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: accessors alien arrays byte-arrays byte-vectors
-definitions generic hashtables kernel math namespaces parser
-lexer sequences strings strings.parser sbufs vectors
-words quotations io assocs splitting classes.tuple
-generic.standard generic.math generic.parser classes io.files
-vocabs classes.parser classes.union
-classes.intersection classes.mixin classes.predicate
-classes.singleton classes.tuple.parser compiler.units
-combinators effects.parser slots ;
+USING: accessors alien arrays byte-arrays definitions generic
+hashtables kernel math namespaces parser lexer sequences strings
+strings.parser sbufs vectors words quotations io assocs
+splitting classes.tuple generic.standard generic.math
+generic.parser classes io.files vocabs classes.parser
+classes.union classes.intersection classes.mixin
+classes.predicate classes.singleton classes.tuple.parser
+compiler.units combinators effects.parser slots ;
IN: bootstrap.syntax
! These words are defined as a top-level form, instead of with
"syntax" lookup t "delimiter" set-word-prop ;
: define-syntax ( name quot -- )
- >r "syntax" lookup dup r> define t "parsing" set-word-prop ;
+ [ "syntax" lookup dup ] dip define make-parsing ;
[
{ "]" "}" ";" ">>" } [ define-delimiter ] each
"CHAR:" [
scan {
{ [ dup length 1 = ] [ first ] }
- { [ "\\" ?head ] [ next-escape drop ] }
+ { [ "\\" ?head ] [ next-escape >string "" assert= ] }
[ name>char-hook get call ]
} cond parsed
] define-syntax
"{" [ \ } [ >array ] parse-literal ] define-syntax
"V{" [ \ } [ >vector ] parse-literal ] define-syntax
"B{" [ \ } [ >byte-array ] parse-literal ] define-syntax
- "BV{" [ \ } [ >byte-vector ] parse-literal ] define-syntax
"H{" [ \ } [ >hashtable ] parse-literal ] define-syntax
"T{" [ parse-tuple-literal parsed ] define-syntax
"W{" [ \ } [ first <wrapper> ] parse-literal ] define-syntax
"foldable" [ word make-foldable ] define-syntax
"flushable" [ word make-flushable ] define-syntax
"delimiter" [ word t "delimiter" set-word-prop ] define-syntax
- "parsing" [ word t "parsing" set-word-prop ] define-syntax
+ "parsing" [ word make-parsing ] define-syntax
"SYMBOL:" [
CREATE-WORD define-symbol
] define-syntax
"INSTANCE:" [
- location >r
- scan-word scan-word 2dup add-mixin-instance
- <mixin-instance> r> remember-definition
+ location [
+ scan-word scan-word 2dup add-mixin-instance
+ <mixin-instance>
+ ] dip remember-definition
] define-syntax
"PREDICATE:" [
] define-syntax
"call-next-method" [
- current-class get current-generic get
- 2dup [ word? ] both? [
- [ literalize parsed ] bi@
+ current-method get [
+ literalize parsed
\ (call-next-method) parsed
] [
not-in-a-method-error
- ] if
+ ] if*
] define-syntax
"initial:" "syntax" lookup define-symbol
{ $subsection vm }
{ $subsection image }
"Getting the current time:"
+{ $subsection micros }
{ $subsection millis }
"Exiting the Factor VM:"
{ $subsection exit } ;
{ $values { "n" "an integer exit code" } }
{ $description "Exits the Factor process." } ;
-HELP: millis ( -- n )
-{ $values { "n" integer } }
+HELP: micros ( -- us )
+{ $values { "us" integer } }
+{ $description "Outputs the number of microseconds ellapsed since midnight January 1, 1970." }
+{ $notes "This is a low-level word. The " { $vocab-link "calendar" } " vocabulary provides features for date/time arithmetic and formatting." } ;
+
+HELP: millis ( -- ms )
+{ $values { "ms" integer } }
{ $description "Outputs the number of milliseconds ellapsed since midnight January 1, 1970." }
{ $notes "This is a low-level word. The " { $vocab-link "calendar" } " vocabulary provides features for date/time arithmetic and formatting." } ;
] "system" add-init-hook
: embedded? ( -- ? ) 15 getenv ;
+
+: millis ( -- ms ) micros 1000 /i ;
[ t ] [
V{ 1 2 3 4 } dup underlying>> length
- >r clone underlying>> length r>
+ [ clone underlying>> length ] dip
=
] unit-test
[ 4 ] [ 5 V{ 1 2 3 4 5 } index ] unit-test
[ t ] [
- 100 >array dup >vector <reversed> >array >r reverse r> =
+ 100 >array dup >vector <reversed> >array [ reverse ] dip =
] unit-test
[ fixnum ] [ 1 >bignum V{ } new-sequence length class ] unit-test
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: arrays kernel math sequences sequences.private growable ;
+USING: arrays kernel math sequences sequences.private growable
+accessors ;
IN: vectors
TUPLE: vector
{ underlying array }
{ length array-capacity } ;
-: <vector> ( n -- vector ) f <array> 0 vector boa ; inline
+: <vector> ( n -- vector ) 0 <array> 0 vector boa ; inline
: >vector ( seq -- vector ) V{ } clone-like ;
M: vector equal?
over vector? [ sequence= ] [ 2drop f ] if ;
+M: array like
+ #! If we have an array, we're done.
+ #! If we have a vector, and it's at full capacity, we're done.
+ #! Otherwise, call resize-array, which is a relatively
+ #! fast primitive.
+ drop dup array? [
+ dup vector? [
+ [ length ] [ underlying>> ] bi
+ 2dup length eq?
+ [ nip ] [ resize-array ] if
+ ] [ >array ] if
+ ] unless ;
+
M: sequence new-resizable drop <vector> ;
INSTANCE: vector growable
-USING: vocabs help.markup help.syntax words strings io ;
+USING: vocabs vocabs.loader.private help.markup help.syntax
+words strings io ;
IN: vocabs.loader
+ARTICLE: "add-vocab-roots" "Working with code outside of the Factor source tree"
+"You can work with code outside of the Factor source tree by adding additional directories to the list of vocabulary roots."
+$nl
+"There are three ways of doing this."
+$nl
+"The first way is to use an environment variable. Factor looks at the " { $snippet "FACTOR_ROOTS" } " environment variable for a list of " { $snippet ":" } "-separated paths (on Unix) or a list of " { $snippet ";" } "-separated paths (on Windows)."
+$nl
+"The second way is to create a configuration file. You can list additional vocabulary roots in a file that Factor reads at startup:"
+{ $subsection "factor-roots" }
+"Finally, you can add vocabulary roots dynamically using a word:"
+{ $subsection add-vocab-root } ;
+
ARTICLE: "vocabs.roots" "Vocabulary roots"
"The vocabulary loader searches for it in one of the root directories:"
{ $subsection vocab-roots }
{ { $snippet "extra" } " - additional contributed libraries." }
{ { $snippet "work" } " - a root for vocabularies which are not intended to be contributed back to Factor." }
}
-"Your own vocabularies should go into " { $snippet "extra" } " or " { $snippet "work" } ", depending on whether or not you intend to contribute them back to the Factor project. If you wish to work on vocabularies outside of the Factor source directory, create a " { $link "factor-boot-rc" } " file like the following:"
-{ $code
- "USING: namespaces sequences vocabs.loader ;"
- "\"/home/jane/sources/\" vocab-roots get push"
-}
-"See " { $link "rc-files" } " for details." ;
+"You can store your own vocabularies in the " { $snippet "work" } " directory."
+{ $subsection "add-vocab-roots" } ;
ARTICLE: "vocabs.loader" "Vocabulary loader"
"The vocabulary loader is defined in the " { $vocab-link "vocabs.loader" } " vocabulary."
HELP: vocab-roots
{ $var-description "A sequence of pathname strings to search for vocabularies." } ;
+HELP: add-vocab-root
+{ $values { "root" "a pathname string" } }
+{ $description "Adds a directory pathname to the list of vocabulary roots." }
+{ $see-also "factor-roots" } ;
+
HELP: find-vocab-root
{ $values { "vocab" "a vocabulary specifier" } { "path/f" "a pathname string" } }
{ $description "Searches for a vocabulary in the vocabulary roots." } ;
2 [
[ "vocabs.loader.test.a" require ] must-fail
- [ f ] [ "vocabs.loader.test.a" vocab-source-loaded? ] unit-test
+ [ f ] [ "vocabs.loader.test.a" vocab source-loaded?>> ] unit-test
[ t ] [
"resource:core/vocabs/loader/test/a/a.factor"
] with-compilation-unit
] unit-test
-[ t ] [
+[ +done+ ] [
[ "vocabs.loader.test.d" require ] [ :1 ] recover
- "vocabs.loader.test.d" vocab-source-loaded?
+ "vocabs.loader.test.d" vocab source-loaded?>>
] unit-test
: forget-junk
[ ] [ [ "vocabs.loader.test.e" forget-vocab ] with-compilation-unit ] unit-test
-[ "vocabs.loader.test.e" require ]
-[ relative-overflow? ] must-fail-with
+0 "vocabs.loader.test.g" set-global
+
+[
+ "vocabs.loader.test.f" forget-vocab
+ "vocabs.loader.test.g" forget-vocab
+] with-compilation-unit
+
+[ ] [ "vocabs.loader.test.g" require ] unit-test
+
+[ 1 ] [ "vocabs.loader.test.g" get-global ] unit-test
+
+[
+ "vocabs.loader.test.h" forget-vocab
+ "vocabs.loader.test.i" forget-vocab
+] with-compilation-unit
+
+[ ] [ "vocabs.loader.test.h" require ] unit-test
+
+
+[
+ "vocabs.loader.test.j" forget-vocab
+ "vocabs.loader.test.k" forget-vocab
+] with-compilation-unit
+
+[ ] [ [ "vocabs.loader.test.j" require ] [ drop :1 ] recover ] unit-test
USING: namespaces make sequences io.files kernel assocs words
vocabs definitions parser continuations io hashtables sorting
source-files arrays combinators strings system math.parser
-compiler.errors splitting init accessors ;
+compiler.errors splitting init accessors sets ;
IN: vocabs.loader
SYMBOL: vocab-roots
"resource:work"
} clone vocab-roots set-global
+: add-vocab-root ( root -- )
+ vocab-roots get adjoin ;
+
: vocab-dir ( vocab -- dir )
vocab-name { { CHAR: . CHAR: / } } substitute ;
: vocab-dir+ ( vocab str/f -- path )
- >r vocab-name "." split r>
- [ >r dup peek r> append suffix ] when*
+ [ vocab-name "." split ] dip
+ [ [ dup peek ] dip append suffix ] when*
"/" join ;
: vocab-dir? ( root name -- ? )
- over [
- ".factor" vocab-dir+ append-path exists?
- ] [
- 2drop f
- ] if ;
+ over
+ [ ".factor" vocab-dir+ append-path exists? ]
+ [ 2drop f ]
+ if ;
SYMBOL: root-cache
H{ } clone root-cache set-global
+<PRIVATE
+
: (find-vocab-root) ( name -- path/f )
vocab-roots get swap [ vocab-dir? ] curry find nip ;
+PRIVATE>
+
: find-vocab-root ( vocab -- path/f )
vocab-name dup root-cache get at [ ] [ (find-vocab-root) ] ?if ;
SYMBOL: load-help?
-: load-source ( vocab -- vocab )
- f over set-vocab-source-loaded?
- [ vocab-source-path [ parse-file ] [ [ ] ] if* ] keep
- t swap set-vocab-source-loaded?
- [ % ] [ assert-depth ] if-bootstrapping ;
+ERROR: circular-dependency name ;
-: load-docs ( vocab -- vocab )
- load-help? get [
- f over set-vocab-docs-loaded?
- [ vocab-docs-path [ ?run-file ] when* ] keep
- t swap set-vocab-docs-loaded?
- ] [ drop ] if ;
+<PRIVATE
-: reload ( name -- )
+: load-source ( vocab -- )
[
- dup vocab [ [ load-source ] [ load-docs ] bi ] [ no-vocab ] ?if
- ] with-compiler-errors ;
+ +parsing+ >>source-loaded?
+ dup vocab-source-path [ parse-file ] [ [ ] ] if*
+ [ +parsing+ >>source-loaded? ] dip
+ [ % ] [ assert-depth ] if-bootstrapping
+ +done+ >>source-loaded? drop
+ ] [ ] [ f >>source-loaded? ] cleanup ;
+
+: load-docs ( vocab -- )
+ load-help? get [
+ [
+ +parsing+ >>docs-loaded?
+ [ vocab-docs-path [ ?run-file ] when* ] keep
+ +done+ >>docs-loaded?
+ ] [ ] [ f >>docs-loaded? ] cleanup
+ ] when drop ;
+
+PRIVATE>
: require ( vocab -- )
- load-vocab drop ;
+ [ load-vocab drop ] with-compiler-errors ;
+
+: reload ( name -- )
+ dup vocab
+ [ [ [ load-source ] [ load-docs ] bi ] with-compiler-errors ]
+ [ require ]
+ ?if ;
: run ( vocab -- )
dup load-vocab vocab-main [
SYMBOL: blacklist
+<PRIVATE
+
: add-to-blacklist ( error vocab -- )
vocab-name blacklist get dup [ set-at ] [ 3drop ] if ;
M: vocab (load-vocab)
[
- dup vocab-source-loaded? [ dup load-source ] unless
- dup vocab-docs-loaded? [ dup load-docs ] unless
- drop
+ dup source-loaded?>> +parsing+ eq? [
+ dup source-loaded?>> [ dup load-source ] unless
+ dup docs-loaded?>> [ dup load-docs ] unless
+ ] unless drop
] [ [ swap add-to-blacklist ] keep rethrow ] recover ;
M: vocab-link (load-vocab)
[
[
- dup vocab-name blacklist get at* [
- rethrow
- ] [
- drop
- dup find-vocab-root [
- [ (load-vocab) ] with-compiler-errors
- ] [
- dup vocab [ drop ] [ no-vocab ] if
- ] if
+ dup vocab-name blacklist get at* [ rethrow ] [
+ drop dup find-vocab-root
+ [ [ (load-vocab) ] with-compiler-errors ]
+ [ dup vocab [ drop ] [ no-vocab ] if ]
+ if
] if
] with-compiler-errors
] load-vocab-hook set-global
+PRIVATE>
+
: vocab-where ( vocab -- loc )
vocab-source-path dup [ 1 2array ] when ;
--- /dev/null
+IN: vocabs.laoder.test.f
+USE: vocabs.loader
+
+"vocabs.loader.test.g" require
--- /dev/null
+unportable
--- /dev/null
+IN: vocabs.loader.test.g
+USING: vocabs.loader.test.f namespaces ;
+
+global [ "vocabs.loader.test.g" inc ] bind
--- /dev/null
+unportable
--- /dev/null
+USE: vocabs.loader.test.i
--- /dev/null
+unportable
--- /dev/null
+IN: vocabs.loader.test.i
+USE: vocabs.loader.test.h
--- /dev/null
+unportable
--- /dev/null
+IN: vocabs.loader.test.j
+"vocabs.loader.test.k" require
--- /dev/null
+unportable
--- /dev/null
+IN: vocabs.loader.test.k
+USE: vocabs.loader.test.j
--- /dev/null
+unportable
{ $values { "vocab-spec" "a vocabulary specifier" } { "words" "an assoc mapping strings to words" } }
{ $description "Outputs the words defined in a vocabulary." } ;
-HELP: vocab-source-loaded?
-{ $values { "vocab-spec" "a vocabulary specifier" } { "?" "a boolean" } }
-{ $description "Outputs if the source for this vocubulary has been loaded." } ;
-
-HELP: vocab-docs-loaded?
-{ $values { "vocab-spec" "a vocabulary specifier" } { "?" "a boolean" } }
-{ $description "Outputs if the documentation for this vocubulary has been loaded." } ;
-
HELP: words
{ $values { "vocab" string } { "seq" "a sequence of words" } }
{ $description "Outputs a sequence of words defined in the vocabulary, or " { $link f } " if no vocabulary with this name exists." } ;
main help
source-loaded? docs-loaded? ;
+! sources-loaded? slot is one of these two
+SYMBOL: +parsing+
+SYMBOL: +running+
+SYMBOL: +done+
+
: <vocab> ( name -- vocab )
\ vocab new
swap >>name
M: f vocab-main ;
-GENERIC: vocab-source-loaded? ( vocab-spec -- ? )
-
-M: vocab vocab-source-loaded? source-loaded?>> ;
-
-M: object vocab-source-loaded?
- vocab vocab-source-loaded? ;
-
-M: f vocab-source-loaded? ;
-
-GENERIC: set-vocab-source-loaded? ( ? vocab-spec -- )
-
-M: vocab set-vocab-source-loaded? (>>source-loaded?) ;
-
-M: object set-vocab-source-loaded?
- vocab set-vocab-source-loaded? ;
-
-M: f set-vocab-source-loaded? 2drop ;
-
-GENERIC: vocab-docs-loaded? ( vocab-spec -- ? )
-
-M: vocab vocab-docs-loaded? docs-loaded?>> ;
-
-M: object vocab-docs-loaded?
- vocab vocab-docs-loaded? ;
-
-M: f vocab-docs-loaded? ;
-
-GENERIC: set-vocab-docs-loaded? ( ? vocab-spec -- )
-
-M: vocab set-vocab-docs-loaded? (>>docs-loaded?) ;
-
-M: object set-vocab-docs-loaded?
- vocab set-vocab-docs-loaded? ;
-
-M: f set-vocab-docs-loaded? 2drop ;
-
: create-vocab ( name -- vocab )
dictionary get [ <vocab> ] cache ;
M: array (quot-uses) seq-uses ;
-M: hashtable (quot-uses) >r >alist r> seq-uses ;
+M: hashtable (quot-uses) [ >alist ] dip seq-uses ;
M: callable (quot-uses) seq-uses ;
-M: wrapper (quot-uses) >r wrapped>> r> (quot-uses) ;
+M: wrapper (quot-uses) [ wrapped>> ] dip (quot-uses) ;
: quot-uses ( quot -- assoc )
global [ H{ } clone [ (quot-uses) ] keep ] bind ;
bi* 2bi ;
: compiled-xref ( word dependencies generic-dependencies -- )
- [ [ drop crossref? ] assoc-filter ] bi@
+ [ [ drop crossref? ] { } assoc-filter-as f like ] bi@
[ over ] dip
[ "compiled-uses" compiled-crossref (compiled-xref) ]
[ "compiled-generic-uses" compiled-generic-crossref (compiled-xref) ]
: (compiled-unxref) ( word word-prop variable -- )
[ [ [ dupd word-prop ] dip get remove-vertex* ] 2curry ]
- [ drop [ f swap set-word-prop ] curry ]
+ [ drop [ remove-word-prop ] curry ]
2bi bi ;
: compiled-unxref ( word -- )
"( gensym )" f <word> ;
: define-temp ( quot -- word )
- gensym dup rot define ;
+ [ gensym dup ] dip define ;
: reveal ( word -- )
dup [ name>> ] [ vocabulary>> ] bi dup vocab-words
dup [ 2nip ] [ drop <word> dup reveal ] if ;
: constructor-word ( name vocab -- word )
- >r "<" swap ">" 3append r> create ;
+ [ "<" ">" surround ] dip create ;
PREDICATE: parsing-word < word "parsing" word-prop ;
+: make-parsing ( word -- ) t "parsing" set-word-prop ;
+
: delimiter? ( obj -- ? )
dup word? [ "delimiter" word-prop ] [ drop f ] if ;
>byte-array append ;
: >ber-application-string ( n str -- byte-array )
- >r HEX: 40 + set-tag r> >ber ;
+ [ HEX: 40 + set-tag ] dip >ber ;
GENERIC: >ber-contextspecific ( n obj -- byte-array )
M: string >ber-contextspecific ( n str -- byte-array )
- >r HEX: 80 + set-tag r> >ber ;
+ [ HEX: 80 + set-tag ] dip >ber ;
! =========================================================
! Array
dupd at [ nip ] when* ;
: replace-at ( assoc value key -- assoc )
- >r >r dup r> 1vector r> rot set-at ;
+ [ dupd 1vector ] dip rot set-at ;
: peek-at* ( assoc key -- obj ? )
- swap at* dup [ >r peek r> ] when ;
+ swap at* dup [ [ peek ] dip ] when ;
: peek-at ( assoc key -- obj )
peek-at* drop ;
: insert ( value variable -- ) namespace push-at ;
: generate-key ( assoc -- str )
- >r 32 random-bits >hex r>
+ [ 32 random-bits >hex ] dip
2dup key? [ nip generate-key ] [ drop ] if ;
: set-at-unique ( value assoc -- key )
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: deep-fry ( quot -- quot )
- { _ } last-split1 dup
+ { _ } split1-last dup
[
shallow-fry [ >r ] rot
deep-fry [ [ dip ] curry r> compose ] 4array concat
MACRO: fry ( seq -- quot ) [fry] ;
-: '[ \ ] [ >quotation ] parse-literal \ fry parsed ; parsing
\ No newline at end of file
+: '[ \ ] [ >quotation ] parse-literal \ fry parsed ; parsing
! See http://factorcode.org/license.txt for BSD license.
USING: kernel vocabs vocabs.loader tools.time tools.vocabs
arrays assocs io.styles io help.markup prettyprint sequences
-continuations debugger ;
+continuations debugger math ;
IN: benchmark
: run-benchmark ( vocab -- result )
- [ [ require ] [ [ run ] benchmark ] bi ] curry
- [ error. f ] recover ;
+ [ "=== " write vocab-name print flush ] [
+ [ [ require ] [ [ run ] benchmark ] bi ] curry
+ [ error. f ] recover
+ ] bi ;
: run-benchmarks ( -- assoc )
"benchmark" all-child-vocabs-seq
standard-table-style [
[
[ "Benchmark" write ] with-cell
- [ "Time (ms)" write ] with-cell
+ [ "Time (seconds)" write ] with-cell
] with-row
[
[
[ [ 1array $vocab-link ] with-cell ]
- [ pprint-cell ] bi*
+ [ [ 1000000 /f pprint-cell ] [ "failed" write ] if* ] bi*
] with-row
] assoc-each
] tabular-output ;
-USING: sequences alien.c-types math hints kernel byte-arrays ;
+USING: sequences hints kernel math specialized-arrays.int fry ;
IN: benchmark.dawes
! Phil Dawes's performance problem
-: int-length ( byte-array -- n ) length "int" heap-size /i ; inline
+: count-ones ( int-array -- n ) [ 1 = ] count ; inline
-: count-ones ( byte-array -- n )
- 0 swap [ int-length ] keep [
- int-nth 1 = [ 1 + ] when
- ] curry each-integer ;
+HINTS: count-ones int-array ;
-HINTS: count-ones byte-array ;
-
-: make-byte-array ( -- byte-array )
- 120000 [ 255 bitand ] map >c-int-array ;
+: make-int-array ( -- int-array )
+ 120000 [ 255 bitand ] int-array{ } map-as ;
: dawes-benchmark ( -- )
- make-byte-array 200 swap [ count-ones ] curry replicate drop ;
+ make-int-array 200 swap '[ _ count-ones ] replicate drop ;
MAIN: dawes-benchmark
USING: make math sequences splitting grouping
-kernel columns float-arrays bit-arrays ;
+kernel columns specialized-arrays.double bit-arrays ;
IN: benchmark.dispatch2
: sequences ( -- seq )
"hello world" ,
SBUF" sbuf world" ,
V{ "a" "b" "c" } ,
- F{ 1.0 2.0 3.0 } ,
+ double-array{ 1.0 2.0 3.0 } ,
"hello world" 4 tail-slice ,
10 f <repetition> ,
100 2 <sliced-groups> ,
USING: sequences math mirrors splitting grouping
kernel make assocs alien.syntax columns
-float-arrays bit-arrays ;
+specialized-arrays.double bit-arrays ;
IN: benchmark.dispatch3
GENERIC: g ( obj -- str )
"hello world" ,
SBUF" sbuf world" ,
V{ "a" "b" "c" } ,
- F{ 1.0 2.0 3.0 } ,
+ double-array{ 1.0 2.0 3.0 } ,
"hello world" 4 tail-slice ,
10 f <repetition> ,
100 2 <sliced-groups> ,
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel fry math math.combinatorics math.order sequences
+io prettyprint ;
+IN: benchmark.fannkuch
+
+: count ( quot: ( -- ? ) -- n )
+ #! Call quot until it returns false, return number of times
+ #! it was true
+ [ 0 ] dip '[ _ dip swap [ [ 1+ ] when ] keep ] loop ; inline
+
+: count-flips ( perm -- flip# )
+ '[
+ _ dup first dup 1 =
+ [ 2drop f ] [ head-slice reverse-here t ] if
+ ] count ; inline
+
+: write-permutation ( perm -- )
+ [ CHAR: 0 + write1 ] each nl ; inline
+
+: fannkuch-step ( counter max-flips perm -- counter max-flips )
+ pick 30 < [ [ 1+ ] [ ] [ dup write-permutation ] tri* ] when
+ count-flips max ; inline
+
+: fannkuch ( n -- )
+ [
+ [ 0 0 ] dip [ 1+ ] B{ } map-as
+ [ fannkuch-step ] each-permutation nip
+ ] keep
+ "Pfannkuchen(" write pprint ") = " write . ;
+
+: fannkuch-main ( -- )
+ 9 fannkuch ;
+
+MAIN: fannkuch-main
! Based on http://shootout.alioth.debian.org/gp4/benchmark.php?test=fasta&lang=java&id=2
USING: math kernel io io.files locals multiline assocs sequences
sequences.private benchmark.reverse-complement hints io.encodings.ascii
-byte-arrays float-arrays ;
+byte-arrays specialized-arrays.double ;
IN: benchmark.fasta
: IM 139968 ; inline
: make-cumulative ( freq -- chars floats )
dup keys >byte-array
- swap values >float-array unclip [ + ] accumulate swap suffix ;
+ swap values >double-array unclip [ + ] accumulate swap suffix ;
:: select-random ( seed chars floats -- seed elt )
floats seed random -rot
] alien-callback\r
"int" { "int" } "cdecl" alien-indirect ;\r
\r
-: fib-main ( -- ) 25 fib drop ;\r
+: fib-main ( -- ) 34 fib drop ;\r
\r
MAIN: fib-main\r
"." split1 rot
over length over <
[ CHAR: 0 pad-right ]
- [ head ] if "." swap 3append ;
+ [ head ] if "." glue ;
: discard-lines ( -- )
readln
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors specialized-arrays.double fry kernel locals make math
+math.constants math.functions math.vectors prettyprint
+sequences hints arrays ;
+IN: benchmark.nbody
+
+: solar-mass 4 pi sq * ; inline
+: days-per-year 365.24 ; inline
+
+TUPLE: body
+{ location double-array }
+{ velocity double-array }
+{ mass float read-only } ;
+
+: <body> ( location velocity mass -- body )
+ [ days-per-year v*n ] [ solar-mass * ] bi* body boa ; inline
+
+: <jupiter> ( -- body )
+ double-array{ 4.84143144246472090e+00 -1.16032004402742839e+00 -1.03622044471123109e-01 }
+ double-array{ 1.66007664274403694e-03 7.69901118419740425e-03 -6.90460016972063023e-05 }
+ 9.54791938424326609e-04
+ <body> ;
+
+: <saturn> ( -- body )
+ double-array{ 8.34336671824457987e+00 4.12479856412430479e+00 -4.03523417114321381e-01 }
+ double-array{ -2.76742510726862411e-03 4.99852801234917238e-03 2.30417297573763929e-05 }
+ 2.85885980666130812e-04
+ <body> ;
+
+: <uranus> ( -- body )
+ double-array{ 1.28943695621391310e+01 -1.51111514016986312e+01 -2.23307578892655734e-01 }
+ double-array{ 2.96460137564761618e-03 2.37847173959480950e-03 -2.96589568540237556e-05 }
+ 4.36624404335156298e-05
+ <body> ;
+
+: <neptune> ( -- body )
+ double-array{ 1.53796971148509165e+01 -2.59193146099879641e+01 1.79258772950371181e-01 }
+ double-array{ 2.68067772490389322e-03 1.62824170038242295e-03 -9.51592254519715870e-05 }
+ 5.15138902046611451e-05
+ <body> ;
+
+: <sun> ( -- body )
+ double-array{ 0 0 0 } double-array{ 0 0 0 } 1 <body> ;
+
+: offset-momentum ( body offset -- body )
+ vneg solar-mass v/n >>velocity ; inline
+
+TUPLE: nbody-system { bodies array read-only } ;
+
+: init-bodies ( bodies -- )
+ [ first ] [ double-array{ 0 0 0 } [ [ velocity>> ] [ mass>> ] bi v*n v+ ] reduce ] bi
+ offset-momentum drop ; inline
+
+: <nbody-system> ( -- system )
+ [ <sun> , <jupiter> , <saturn> , <uranus> , <neptune> , ] { } make nbody-system boa
+ dup bodies>> init-bodies ; inline
+
+:: each-pair ( bodies pair-quot: ( other-body body -- ) each-quot: ( body -- ) -- )
+ bodies [| body i |
+ body each-quot call
+ bodies i 1+ tail-slice [
+ body pair-quot call
+ ] each
+ ] each-index ; inline
+
+: update-position ( body dt -- )
+ [ dup velocity>> ] dip '[ _ _ v*n v+ ] change-location drop ;
+
+: mag ( dt body other-body -- mag d )
+ [ location>> ] bi@ v- [ norm-sq dup sqrt * / ] keep ; inline
+
+:: update-velocity ( other-body body dt -- )
+ dt body other-body mag
+ [ [ body ] 2dip '[ other-body mass>> _ * _ n*v v- ] change-velocity drop ]
+ [ [ other-body ] 2dip '[ body mass>> _ * _ n*v v+ ] change-velocity drop ] 2bi ;
+
+: advance ( system dt -- )
+ [ bodies>> ] dip
+ [ '[ _ update-velocity ] [ drop ] each-pair ]
+ [ '[ _ update-position ] each ]
+ 2bi ; inline
+
+: inertia ( body -- e )
+ [ mass>> ] [ velocity>> norm-sq ] bi * 0.5 * ;
+
+: newton's-law ( other-body body -- e )
+ [ [ mass>> ] bi@ * ] [ [ location>> ] bi@ distance ] 2bi / ;
+
+: energy ( system -- x )
+ [ 0.0 ] dip bodies>> [ newton's-law - ] [ inertia + ] each-pair ; inline
+
+: nbody ( n -- )
+ <nbody-system>
+ [ energy . ] [ '[ _ 0.01 advance ] times ] [ energy . ] tri ;
+
+HINTS: update-position body float ;
+HINTS: update-velocity body body float ;
+HINTS: inertia body ;
+HINTS: newton's-law body body ;
+HINTS: nbody fixnum ;
+
+: nbody-main ( -- ) 1000000 nbody ;
+
+MAIN: nbody-main
-USING: math math.functions kernel sequences io io.styles
-prettyprint words hints ;
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: math math.functions kernel io io.styles prettyprint
+combinators hints fry namespaces sequences ;
IN: benchmark.partial-sums
-: summing ( n quot -- y )
- [ >float ] swap [ + ] 3compose
- 0.0 -rot 1 -rot (each-integer) ; inline
-
-: 2/3^k ( n -- y ) [ 2.0 3.0 / swap 1- ^ ] summing ;
-
-HINTS: 2/3^k fixnum ;
-
-: k^-0.5 ( n -- y ) [ -0.5 ^ ] summing ;
-
-HINTS: k^-0.5 fixnum ;
-
-: 1/k(k+1) ( n -- y ) [ dup 1+ * recip ] summing ;
-
-HINTS: 1/k(k+1) fixnum ;
-
+! Helper words
+: summing-integers ( n quot -- y ) [ 0.0 ] 2dip '[ 1+ @ + ] each ; inline
+: summing-floats ( n quot -- y ) '[ >float @ ] summing-integers ; inline
: cube ( x -- y ) dup dup * * ; inline
-
-: flint-hills ( n -- y )
- [ dup cube swap sin sq * recip ] summing ;
-
-HINTS: flint-hills fixnum ;
-
-: cookson-hills ( n -- y )
- [ dup cube swap cos sq * recip ] summing ;
-
-HINTS: cookson-hills fixnum ;
-
-: harmonic ( n -- y ) [ recip ] summing ;
-
-HINTS: harmonic fixnum ;
-
-: riemann-zeta ( n -- y ) [ sq recip ] summing ;
-
-HINTS: riemann-zeta fixnum ;
-
-: -1^ 2 mod zero? 1 -1 ? ; inline
-
-: alternating-harmonic ( n -- y ) [ dup -1^ swap / ] summing ;
-
-HINTS: alternating-harmonic fixnum ;
-
-: gregory ( n -- y ) [ dup -1^ swap 2 * 1- / ] summing ;
-
-HINTS: gregory fixnum ;
-
-: functions
- { 2/3^k k^-0.5 1/k(k+1) flint-hills cookson-hills harmonic riemann-zeta alternating-harmonic gregory } ;
-
-: partial-sums ( n -- )
- standard-table-style [
- functions [
- [ tuck execute pprint-cell pprint-cell ] with-row
- ] with each
- ] tabular-output ;
-
-: partial-sums-main ( -- ) 2500000 partial-sums ;
+: -1^ ( n -- -1/1 ) 2 mod 2 * 1- ; inline
+
+! The functions
+: 2/3^k ( n -- y ) [ 2.0 3.0 / swap 1- ^ ] summing-floats ; inline
+: k^-0.5 ( n -- y ) [ -0.5 ^ ] summing-floats ; inline
+: 1/k(k+1) ( n -- y ) [ dup 1+ * recip ] summing-floats ; inline
+: flint-hills ( n -- y ) [ [ cube ] [ sin sq ] bi * recip ] summing-floats ; inline
+: cookson-hills ( n -- y ) [ [ cube ] [ cos sq ] bi * recip ] summing-floats ; inline
+: harmonic ( n -- y ) [ recip ] summing-floats ; inline
+: riemann-zeta ( n -- y ) [ sq recip ] summing-floats ; inline
+: alternating-harmonic ( n -- y ) [ [ -1^ ] keep /f ] summing-integers ; inline
+: gregory ( n -- y ) [ [ -1^ ] [ 2.0 * 1- ] bi / ] summing-integers ; inline
+
+: partial-sums ( n -- results )
+ [
+ {
+ [ 2/3^k \ 2/3^k set ]
+ [ k^-0.5 \ k^-0.5 set ]
+ [ 1/k(k+1) \ 1/k(k+1) set ]
+ [ flint-hills \ flint-hills set ]
+ [ cookson-hills \ cookson-hills set ]
+ [ harmonic \ harmonic set ]
+ [ riemann-zeta \ riemann-zeta set ]
+ [ alternating-harmonic \ alternating-harmonic set ]
+ [ gregory \ gregory set ]
+ } cleave
+ ] { } make-assoc ;
+
+HINTS: partial-sums fixnum ;
+
+: partial-sums-main ( -- )
+ 2500000 partial-sums simple-table. ;
MAIN: partial-sums-main
! Factor port of the raytracer benchmark from
! http://www.ffconsultancy.com/free/ray_tracer/languages.html
-USING: arrays accessors float-arrays io io.files
+USING: arrays accessors specialized-arrays.double io io.files
io.encodings.binary kernel math math.functions math.vectors
math.parser make sequences sequences.private words hints ;
IN: benchmark.raytracer
! parameters
: light
#! Normalized { -1 -3 2 }.
- F{
+ double-array{
-0.2672612419124244
-0.8017837257372732
0.5345224838248488
: delta 1.4901161193847656E-8 ; inline
-TUPLE: ray { orig float-array read-only } { dir float-array read-only } ;
+TUPLE: ray { orig double-array read-only } { dir double-array read-only } ;
C: <ray> ray
-TUPLE: hit { normal float-array read-only } { lambda float read-only } ;
+TUPLE: hit { normal double-array read-only } { lambda float read-only } ;
C: <hit> hit
GENERIC: intersect-scene ( hit ray scene -- hit )
-TUPLE: sphere { center float-array read-only } { radius float read-only } ;
+TUPLE: sphere { center double-array read-only } { radius float read-only } ;
C: <sphere> sphere
M: group intersect-scene ( hit ray group -- hit )
[ drop objs>> [ intersect-scene ] with each ] if-ray-sphere ;
-: initial-hit T{ hit f F{ 0.0 0.0 0.0 } 1/0. } ; inline
+: initial-hit T{ hit f double-array{ 0.0 0.0 0.0 } 1/0. } ; inline
: initial-intersect ( ray scene -- hit )
[ initial-hit ] 2dip intersect-scene ; inline
: create-offsets ( quot -- )
{
- F{ -1.0 1.0 -1.0 }
- F{ 1.0 1.0 -1.0 }
- F{ -1.0 1.0 1.0 }
- F{ 1.0 1.0 1.0 }
+ double-array{ -1.0 1.0 -1.0 }
+ double-array{ 1.0 1.0 -1.0 }
+ double-array{ -1.0 1.0 1.0 }
+ double-array{ 1.0 1.0 1.0 }
} swap each ; inline
: create-bound ( c r -- sphere ) 3.0 * <sphere> ;
pick 1 = [ <sphere> nip ] [ create-group ] if ;
: ss-point ( dx dy -- point )
- [ oversampling /f ] bi@ 0.0 3float-array ;
+ [ oversampling /f ] bi@ 0.0 double-array{ } 3sequence ;
: ss-grid ( -- ss-grid )
oversampling [ oversampling [ ss-point ] with map ] map ;
: ray-grid ( point ss-grid -- ray-grid )
[
- [ v+ normalize F{ 0.0 0.0 -4.0 } swap <ray> ] with map
+ [ v+ normalize double-array{ 0.0 0.0 -4.0 } swap <ray> ] with map
] with map ;
: ray-pixel ( scene point -- n )
size reverse [
size [
[ size 0.5 * - ] bi@ swap size
- 3float-array
+ double-array{ } 3sequence
] with map
] map ;
pixel-grid [ [ ray-pixel ] with map ] with map ;
: run ( -- string )
- levels F{ 0.0 -1.0 0.0 } 1.0 create ray-trace [
+ levels double-array{ 0.0 -1.0 0.0 } 1.0 create ray-trace [
size size pgm-header
[ [ oversampling sq / pgm-pixel ] each ] each
] B{ } make ;
USING: benchmark.regex-dna io io.files io.encodings.ascii
-io.streams.string kernel tools.test ;
+io.streams.string kernel tools.test splitting ;
IN: benchmark.regex-dna.tests
[ t ] [
: count-patterns ( string -- )
{
- R/ agggtaaa|tttaccct/i,
- R/ [cgt]gggtaaa|tttaccc[acg]/i,
- R/ a[act]ggtaaa|tttacc[agt]t/i,
- R/ ag[act]gtaaa|tttac[agt]ct/i,
- R/ agg[act]taaa|ttta[agt]cct/i,
- R/ aggg[acg]aaa|ttt[cgt]ccct/i,
- R/ agggt[cgt]aa|tt[acg]accct/i,
- R/ agggta[cgt]a|t[acg]taccct/i,
+ R/ agggtaaa|tttaccct/i
+ R/ [cgt]gggtaaa|tttaccc[acg]/i
+ R/ a[act]ggtaaa|tttacc[agt]t/i
+ R/ ag[act]gtaaa|tttac[agt]ct/i
+ R/ agg[act]taaa|ttta[agt]cct/i
+ R/ aggg[acg]aaa|ttt[cgt]ccct/i
+ R/ agggt[cgt]aa|tt[acg]accct/i
+ R/ agggta[cgt]a|t[acg]taccct/i
R/ agggtaa[cgt]|[acg]ttaccct/i
} [
[ raw>> write bl ]
! Factor port of
! http://shootout.alioth.debian.org/gp4/benchmark.php?test=spectralnorm&lang=all
-USING: float-arrays kernel math math.functions math.vectors
-sequences sequences.private prettyprint words
-hints locals ;
+USING: specialized-arrays.double kernel math math.functions
+math.vectors sequences sequences.private prettyprint words hints
+locals ;
IN: benchmark.spectral-norm
:: inner-loop ( u n quot -- seq )
n 0.0 [| j |
u i j quot call +
] reduce
- ] F{ } map-as ; inline
+ ] double-array{ } map-as ; inline
: eval-A ( i j -- n )
[ >float ] bi@
: eval-AtA-times-u ( u n -- seq )
[ eval-A-times-u ] [ eval-At-times-u ] bi ; inline
-: ones ( n -- seq ) [ 1.0 ] F{ } replicate-as ; inline
+: ones ( n -- seq ) [ 1.0 ] double-array{ } replicate-as ; inline
:: u/v ( n -- u v )
n ones dup
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: io.encodings.utf8 io.files kernel sequences xml ;
+IN: benchmark.xml
+
+: xml-benchmark ( -- )
+ "resource:basis/xmode/modes/" [
+ [ utf8 <file-reader> read-xml drop ] each
+ ] with-directory-files ;
+
+MAIN: xml-benchmark
-USING: kernel parser lexer locals.private ;
+USING: kernel parser lexer locals.parser locals.types ;
IN: bind-in
[ ":" split1 string>number [ dup length ] unless* ] { } map>assoc ;
: define-slots ( prefix names quots -- )
- >r [ "-" swap 3append create-in ] with map r>
+ >r [ "-" glue create-in ] with map r>
[ define ] 2each ;
: define-accessors ( classname slots -- )
-USING: combinators.short-circuit kernel namespaces
+USING: kernel
+ namespaces
+ arrays
+ accessors
+ strings
+ sequences
+ locals
+ threads
math
- math.constants
math.functions
+ math.trig
math.order
+ math.ranges
math.vectors
- math.trig
- math.physics.pos
- math.physics.vel
- combinators arrays sequences random vars
- combinators.lib
- accessors ;
+ random
+ calendar
+ opengl.gl
+ opengl
+ ui
+ ui.gadgets
+ ui.gadgets.tracks
+ ui.gadgets.frames
+ ui.gadgets.grids
+ ui.render
+ multi-methods
+ multi-method-syntax
+ combinators.short-circuit
+ processing.shapes
+ flatland ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
IN: boids
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-TUPLE: boid < vel ;
+: constrain ( n a b -- n ) rot min max ;
-C: <boid> boid
+: angle-between ( vec vec -- angle )
+ [ v. ] [ [ norm ] bi@ * ] 2bi / -1 1 constrain acos rad>deg ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-VAR: boids
-VAR: world-size
-VAR: time-slice
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+: relative-position ( self other -- v ) swap [ pos>> ] bi@ v- ;
-VAR: cohesion-weight
-VAR: alignment-weight
-VAR: separation-weight
+: relative-angle ( self other -- angle )
+ over vel>> -rot relative-position angle-between ;
-VAR: cohesion-view-angle
-VAR: alignment-view-angle
-VAR: separation-view-angle
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-VAR: cohesion-radius
-VAR: alignment-radius
-VAR: separation-radius
+: in-radius? ( self other radius -- ? ) [ distance ] dip <= ;
+: in-view? ( self other angle -- ? ) [ relative-angle ] dip 2 / <= ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: init-variables ( -- )
- 1.0 >cohesion-weight
- 1.0 >alignment-weight
- 1.0 >separation-weight
-
- 75 >cohesion-radius
- 50 >alignment-radius
- 25 >separation-radius
+: vsum ( vector-of-vectors -- vec ) { 0 0 } [ v+ ] reduce ;
- 180 >cohesion-view-angle
- 180 >alignment-view-angle
- 180 >separation-view-angle
+: vaverage ( seq-of-vectors -- seq ) [ vsum ] [ length ] bi v/n ;
- 10 >time-slice ;
+: average-position ( boids -- pos ) [ pos>> ] map vaverage ;
+: average-velocity ( boids -- vel ) [ vel>> ] map vaverage ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-! random-boid and random-boids
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: random-range ( a b -- n ) 1+ over - random + ;
+TUPLE: <boid> < <vel> ;
-: random-pos ( -- pos ) world-size> [ random ] map ;
-
-: random-vel ( -- vel ) 2 [ drop -10 10 random-range ] map ;
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: random-boid ( -- boid ) random-pos random-vel <boid> ;
+TUPLE: <behaviour>
+ { weight initial: 1.0 }
+ { view-angle initial: 180 }
+ { radius } ;
-: random-boids ( n -- boids ) [ drop random-boid ] map ;
+TUPLE: <cohesion> < <behaviour> { radius initial: 75 } ;
+TUPLE: <alignment> < <behaviour> { radius initial: 50 } ;
+TUPLE: <separation> < <behaviour> { radius initial: 25 } ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: constrain ( n a b -- n ) rot min max ;
+:: within-neighborhood? ( SELF OTHER BEHAVIOUR -- ? )
-: angle-between ( vec vec -- angle )
- 2dup v. -rot norm swap norm * / -1 1 constrain acos rad>deg ;
+ SELF OTHER
+ {
+ [ BEHAVIOUR radius>> in-radius? ]
+ [ BEHAVIOUR view-angle>> in-view? ]
+ [ eq? not ]
+ }
+ 2&& ;
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+:: neighborhood ( SELF OTHERS BEHAVIOUR -- boids )
+ OTHERS [| OTHER | SELF OTHER BEHAVIOUR within-neighborhood? ] filter ;
-: relative-position ( self other -- v ) swap [ pos>> ] bi@ v- ;
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: relative-angle ( self other -- angle )
-over vel>> -rot relative-position angle-between ;
+: normalize* ( u -- v ) { 0.001 0.001 } v+ normalize ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: vsum ( vector-of-vectors -- vec ) { 0 0 } [ v+ ] reduce ;
+GENERIC: force* ( sequence <boid> <behaviour> -- force )
-: vaverage ( seq-of-vectors -- seq ) [ vsum ] [ length ] bi v/n ;
+:: cohesion-force ( OTHERS SELF BEHAVIOUR -- force )
+ OTHERS average-position SELF pos>> v- normalize* BEHAVIOUR weight>> v*n ;
-: average-position ( boids -- pos ) [ pos>> ] map vaverage ;
+:: alignment-force ( OTHERS SELF BEHAVIOUR -- force )
+ OTHERS average-velocity normalize* BEHAVIOUR weight>> v*n ;
-: average-velocity ( boids -- vel ) [ vel>> ] map vaverage ;
+:: separation-force ( OTHERS SELF BEHAVIOUR -- force )
+ SELF pos>> OTHERS average-position v- normalize* BEHAVIOUR weight>> v*n ;
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+METHOD: force* ( sequence <boid> <cohesion> -- force ) cohesion-force ;
+METHOD: force* ( sequence <boid> <alignment> -- force ) alignment-force ;
+METHOD: force* ( sequence <boid> <separation> -- force ) separation-force ;
-: in-range? ( self other radius -- ? ) >r distance r> <= ;
+:: force ( OTHERS SELF BEHAVIOUR -- force )
+ SELF OTHERS BEHAVIOUR neighborhood
+ [ { 0 0 } ]
+ [ SELF BEHAVIOUR force* ]
+ if-empty ;
-: in-view? ( self other angle -- ? ) >r relative-angle r> 2 / <= ;
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: random-boids ( count -- boids )
+ [
+ drop
+ <boid> new
+ 2 [ drop 1000 random ] map >>pos
+ 2 [ drop -10 10 [a,b] random ] map >>vel
+ ]
+ map ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: normalize* ( u -- v ) { 0.001 0.001 } v+ normalize ;
+: draw-boid ( boid -- )
+ glPushMatrix
+ dup pos>> gl-translate-2d
+ vel>> first2 rect> arg rad>deg 0 0 1 glRotated
+ { { 0 5 } { 0 -5 } { 20 0 } } triangle
+ fill-mode
+ glPopMatrix ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-! average_position(neighbors) - self_position
+: gadget->sky ( gadget -- sky ) { 0 0 } swap dim>> <rectangle> boa ;
-: within-cohesion-neighborhood? ( self other -- ? )
- { [ cohesion-radius> in-range? ]
- [ cohesion-view-angle> in-view? ]
- [ eq? not ] }
- 2&& ;
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: cohesion-neighborhood ( self -- boids )
- boids> [ within-cohesion-neighborhood? ] with filter ;
+USE: syntax ! Switch back to non-multi-method 'TUPLE:' syntax
-: cohesion-force ( self -- force )
- dup cohesion-neighborhood
- dup empty?
- [ 2drop { 0 0 } ]
- [ average-position swap pos>> v- normalize* cohesion-weight> v*n ]
- if ;
+TUPLE: <boids-gadget> < gadget paused boids behaviours time-slice ;
+
+M: <boids-gadget> pref-dim* ( <boids-gadget> -- dim ) drop { 600 400 } ;
+M: <boids-gadget> ungraft* ( <boids-gadget> -- ) t >>paused drop ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-! self_position - average_position(neighbors)
+:: iterate-system ( BOIDS-GADGET -- )
-: within-separation-neighborhood? ( self other -- ? )
- { [ separation-radius> in-range? ]
- [ separation-view-angle> in-view? ]
- [ eq? not ] }
- 2&& ;
+ [let | SKY [ BOIDS-GADGET gadget->sky ]
+ BOIDS [ BOIDS-GADGET boids>> ]
+ TIME-SLICE [ BOIDS-GADGET time-slice>> ]
+ BEHAVIOURS [ BOIDS-GADGET behaviours>> ] |
-: separation-neighborhood ( self -- boids )
- boids> [ within-separation-neighborhood? ] with filter ;
+ BOIDS
-: separation-force ( self -- force )
- dup separation-neighborhood
- dup empty?
- [ 2drop { 0 0 } ]
- [ average-position swap pos>> swap v- normalize* separation-weight> v*n ]
- if ;
+ [| SELF |
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ [wlet | force-due-to [| BEHAVIOUR | BOIDS SELF BEHAVIOUR force ] |
-! average_velocity(neighbors)
+ ! F = m a. M is 1. So F = a.
+
+ [let | ACCEL [ BEHAVIOURS [ force-due-to ] map vsum ] |
-: within-alignment-neighborhood? ( self other -- ? )
- { [ alignment-radius> in-range? ]
- [ alignment-view-angle> in-view? ]
- [ eq? not ] }
- 2&& ;
+ [let | POS [ SELF pos>> SELF vel>> TIME-SLICE v*n v+ ]
+ VEL [ SELF vel>> ACCEL TIME-SLICE v*n v+ ] |
-: alignment-neighborhood ( self -- boids )
-boids> [ within-alignment-neighborhood? ] with filter ;
+ [let | POS [ POS SKY wrap ]
+ VEL [ VEL normalize* ] |
+
+ T{ <boid> f POS VEL } ] ] ] ]
-: alignment-force ( self -- force )
- alignment-neighborhood
- dup empty?
- [ drop { 0 0 } ]
- [ average-velocity normalize* alignment-weight> v*n ]
- if ;
+ ]
+
+ map
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ BOIDS-GADGET (>>boids) ] ;
-! F = m a
-!
-! We let m be equal to 1 so then this is simply: F = a
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: acceleration ( boid -- acceleration )
- { separation-force alignment-force cohesion-force } map-exec-with vsum ;
+M:: <boids-gadget> draw-gadget* ( BOIDS-GADGET -- )
+ origin get
+ [ BOIDS-GADGET boids>> [ draw-boid ] each ]
+ with-translation ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-! iterate-boid
+
+:: start-boids-thread ( GADGET -- )
+ GADGET f >>paused drop
+ [
+ [
+ GADGET paused>>
+ [ f ]
+ [ GADGET iterate-system GADGET relayout-1 1 milliseconds sleep t ]
+ if
+ ]
+ loop
+ ]
+ in-thread ;
+
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: world-width ( -- w ) world-size> first ;
+: default-behaviours ( -- seq )
+ { <cohesion> <alignment> <separation> } [ new ] map ;
+
+: boids-gadget ( -- gadget )
+ <boids-gadget> new-gadget
+ 100 random-boids >>boids
+ default-behaviours >>behaviours
+ 10 >>time-slice
+ t >>clipped? ;
-: world-height ( -- w ) world-size> second ;
+: run-boids ( -- ) boids-gadget dup "Boids" open-window start-boids-thread ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: below? ( n a b -- ? ) drop < ;
+USING: math.parser
+ ui.gadgets.labels
+ ui.gadgets.buttons
+ ui.gadgets.packs ;
+
+: truncate-number ( n -- n ) 10 * round 10 / ;
+
+:: make-behaviour-control ( NAME BEHAVIOUR -- gadget )
+ [let | NAME-LABEL [ NAME <label> reverse-video-theme ]
+ VALUE-LABEL [ 20 32 <string> <label> reverse-video-theme ] |
+
+ [wlet | update-value-label [ ! ( -- )
+ BEHAVIOUR weight>> truncate-number number>string
+ VALUE-LABEL
+ set-label-string ] |
+
+ update-value-label
+
+ <pile> 1 >>fill
+ { 1 0 } <track>
+ NAME-LABEL 0.5 track-add
+ VALUE-LABEL 0.5 track-add
+ add-gadget
+
+ "+0.1"
+ [
+ drop
+ BEHAVIOUR [ 0.1 + ] change-weight drop
+ update-value-label
+ ]
+ <bevel-button> add-gadget
+
+ "-0.1"
+ [
+ drop
+ BEHAVIOUR weight>> 0.1 >
+ [
+ BEHAVIOUR [ 0.1 - ] change-weight drop
+ update-value-label
+ ]
+ when
+ ]
+ <bevel-button> add-gadget ] ] ;
-: above? ( n a b -- ? ) nip > ;
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: wrap ( n a b -- n )
-{ { [ 3dup below? ]
- [ 2nip ] }
- { [ 3dup above? ]
- [ drop nip ] }
- { [ t ]
- [ 2drop ] } }
-cond ;
+:: make-population-control ( BOIDS-GADGET -- gadget )
+ [let | VALUE-LABEL [ 20 32 <string> <label> reverse-video-theme ] |
+
+ [wlet | update-value-label [ ( -- )
+ BOIDS-GADGET boids>> length number>string
+ VALUE-LABEL
+ set-label-string ] |
+
+ update-value-label
+
+ <pile> 1 >>fill
+
+ { 1 0 } <track>
+ "Population: " <label> reverse-video-theme 0.5 track-add
+ VALUE-LABEL 0.5 track-add
+ add-gadget
+
+ "Add 10"
+ [
+ drop
+ BOIDS-GADGET
+ BOIDS-GADGET boids>> 10 random-boids append
+ >>boids
+ drop
+ update-value-label
+ ]
+ <bevel-button>
+ add-gadget
+
+ "Sub 10"
+ [
+ drop
+ BOIDS-GADGET boids>> length 10 >
+ [
+ BOIDS-GADGET
+ BOIDS-GADGET boids>> 10 tail
+ >>boids
+ drop
+ update-value-label
+ ]
+ when
+ ]
+ <bevel-button>
+ add-gadget ] ] ( gadget -- gadget ) ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: wrap-x ( x -- x ) 0 world-width 1- wrap ;
+:: pause-toggle ( BOIDS-GADGET -- )
+ BOIDS-GADGET paused>>
+ [ BOIDS-GADGET start-boids-thread ]
+ [ BOIDS-GADGET t >>paused drop ]
+ if ;
-: wrap-y ( y -- y ) 0 world-height 1- wrap ;
+:: randomize-boids ( BOIDS-GADGET -- )
+ BOIDS-GADGET BOIDS-GADGET boids>> length random-boids >>boids drop ;
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+: boids-app ( -- )
-: new-pos ( boid -- pos ) [ pos>> ] [ vel>> time-slice> v*n ] bi v+ ;
+ [let | BOIDS-GADGET [ boids-gadget ] |
-: new-vel ( boid -- vel )
- [ vel>> ] [ acceleration time-slice> v*n ] bi v+ normalize* ;
+ <frame>
-: wrap-pos ( pos -- pos ) { [ wrap-x ] [ wrap-y ] } parallel-call ;
+ <shelf>
-: iterate-boid ( self -- self ) [ new-pos wrap-pos ] [ new-vel ] bi <boid> ;
+ 1 >>fill
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ "Pause" [ drop BOIDS-GADGET pause-toggle ] <bevel-button> add-gadget
-: iterate-boids ( -- ) boids> [ iterate-boid ] map >boids ;
+ "Randomize"
+ [ drop BOIDS-GADGET randomize-boids ] <bevel-button> add-gadget
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ BOIDS-GADGET make-population-control add-gadget
+
+ "Cohesion: " BOIDS-GADGET behaviours>> first make-behaviour-control
+ "Alignment: " BOIDS-GADGET behaviours>> second make-behaviour-control
+ "Separation: " BOIDS-GADGET behaviours>> third make-behaviour-control
-: init-boids ( -- ) 100 random-boids >boids ;
+ [ add-gadget ] tri@
-: init-world-size ( -- ) { 100 100 } >world-size ;
+ @top grid-add
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ BOIDS-GADGET @center grid-add
+
+ "Boids" open-window
-: randomize ( -- ) boids> length random-boids >boids ;
+ BOIDS-GADGET start-boids-thread ] ;
-: inc* ( variable -- ) dup get 0.1 + 0 1 constrain swap set ;
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: dec* ( variable -- ) dup get 0.1 - 0 1 constrain swap set ;
+: boids-main ( -- ) [ boids-app ] with-ui ;
+MAIN: boids-main
\ No newline at end of file
+++ /dev/null
-Eduardo Cavazos
+++ /dev/null
-USING: tools.deploy.config ;
-H{
- { deploy-math? t }
- { deploy-word-props? f }
- { deploy-c-types? f }
- { deploy-ui? t }
- { deploy-io 2 }
- { deploy-threads? t }
- { deploy-word-defs? f }
- { deploy-compiler? t }
- { deploy-unicode? f }
- { deploy-name "Boids" }
- { "stop-after-last-window?" t }
- { deploy-reflection 1 }
-}
+++ /dev/null
-
-USING: combinators.short-circuit kernel namespaces
- math
- math.trig
- math.functions
- math.vectors
- math.parser
- hashtables sequences threads
- colors
- opengl
- opengl.gl
- ui
- ui.gadgets
- ui.gadgets.handler
- ui.gadgets.slate
- ui.gadgets.theme
- ui.gadgets.frames
- ui.gadgets.labels
- ui.gadgets.buttons
- ui.gadgets.packs
- ui.gadgets.grids
- ui.gestures
- assocs.lib vars rewrite-closures boids accessors
- math.geometry.rect
- newfx
- processing.shapes ;
-
-IN: boids.ui
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-! draw-boid
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: draw-boid ( boid -- )
- glPushMatrix
- dup pos>> gl-translate-2d
- vel>> first2 rect> arg rad>deg 0 0 1 glRotated
- { { 0 5 } { 0 -5 } { 20 0 } } triangle
- fill-mode
- glPopMatrix ;
-
-: draw-boids ( -- ) boids> [ draw-boid ] each ;
-
-: boid-color ( -- color ) T{ rgba f 1.0 0 0 0.3 } ;
-
-: display ( -- )
- boid-color >fill-color
- draw-boids ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-VAR: slate
-
-VAR: loop
-
-: run ( -- )
- slate> rect-dim >world-size
- iterate-boids
- slate> relayout-1
- yield
- loop> [ run ] when ;
-
-: button* ( string quot -- button ) closed-quot <bevel-button> ;
-
-: toggle-loop ( -- ) loop> [ loop off ] [ loop on [ run ] in-thread ] if ;
-
-VARS: population-label cohesion-label alignment-label separation-label ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: update-population-label ( -- )
- "Population: " boids> length number>string append
- 20 32 pad-right population-label> set-label-string ;
-
-: add-10-boids ( -- )
- boids> 10 random-boids append >boids update-population-label ;
-
-: sub-10-boids ( -- )
- boids> 10 tail >boids update-population-label ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: truncate-value ( n -- n ) 10 * round 10 / ;
-
-: update-cohesion-label ( -- )
- "Cohesion: " cohesion-weight> truncate-value number>string append
- 20 32 pad-right cohesion-label> set-label-string ;
-
-: update-alignment-label ( -- )
- "Alignment: " alignment-weight> truncate-value number>string append
- 20 32 pad-right alignment-label> set-label-string ;
-
-: update-separation-label ( -- )
- "Separation: " separation-weight> truncate-value number>string append
- 20 32 pad-right separation-label> set-label-string ;
-
-: inc-cohesion-weight ( -- ) cohesion-weight inc* update-cohesion-label ;
-: dec-cohesion-weight ( -- ) cohesion-weight dec* update-cohesion-label ;
-
-: inc-alignment-weight ( -- ) alignment-weight inc* update-alignment-label ;
-: dec-alignment-weight ( -- ) alignment-weight dec* update-alignment-label ;
-
-: inc-separation-weight ( -- ) separation-weight inc* update-separation-label ;
-: dec-separation-weight ( -- ) separation-weight dec* update-separation-label ;
-
-: boids-window* ( -- )
- init-variables init-world-size init-boids loop on
-
- "" <label> reverse-video-theme >population-label update-population-label
- "" <label> reverse-video-theme >cohesion-label update-cohesion-label
- "" <label> reverse-video-theme >alignment-label update-alignment-label
- "" <label> reverse-video-theme >separation-label update-separation-label
-
- <frame>
-
- <shelf>
-
- 1 >>fill
-
- "ESC - Pause" [ drop toggle-loop ] button* add-gadget
-
- "1 - Randomize" [ drop randomize ] button* add-gadget
-
- <pile> 1 >>fill
- population-label> add-gadget
- "3 - Add 10" [ drop add-10-boids ] button* add-gadget
- "2 - Sub 10" [ drop sub-10-boids ] button* add-gadget
- add-gadget
-
- <pile> 1 >>fill
- cohesion-label> add-gadget
- "q - +0.1" [ drop inc-cohesion-weight ] button* add-gadget
- "a - -0.1" [ drop dec-cohesion-weight ] button* add-gadget
- add-gadget
-
- <pile> 1 >>fill
- alignment-label> add-gadget
- "w - +0.1" [ drop inc-alignment-weight ] button* add-gadget
- "s - -0.1" [ drop dec-alignment-weight ] button* add-gadget
- add-gadget
-
- <pile> 1 >>fill
- separation-label> add-gadget
- "e - +0.1" [ drop inc-separation-weight ] button* add-gadget
- "d - -0.1" [ drop dec-separation-weight ] button* add-gadget
- add-gadget
-
- @top grid-add
-
- C[ display ] <slate>
- dup >slate
- t >>clipped?
- { 600 400 } >>pdim
- C[ [ run ] in-thread ] >>graft
- C[ loop off ] >>ungraft
- @center grid-add
-
- <handler>
- H{ } clone
- T{ key-down f f "1" } C[ drop randomize ] is
- T{ key-down f f "2" } C[ drop sub-10-boids ] is
- T{ key-down f f "3" } C[ drop add-10-boids ] is
- T{ key-down f f "q" } C[ drop inc-cohesion-weight ] is
- T{ key-down f f "a" } C[ drop dec-cohesion-weight ] is
- T{ key-down f f "w" } C[ drop inc-alignment-weight ] is
- T{ key-down f f "s" } C[ drop dec-alignment-weight ] is
- T{ key-down f f "e" } C[ drop inc-separation-weight ] is
- T{ key-down f f "d" } C[ drop dec-separation-weight ] is
- T{ key-down f f "ESC" } C[ drop toggle-loop ] is
- >>table
-
- "Boids" open-window ;
-
-: boids-window ( -- ) [ [ boids-window* ] with-scope ] with-ui ;
-
-MAIN: boids-window
USING: alien.c-types continuations destructors kernel
-opengl opengl.gl bunny.model ;
+opengl opengl.gl bunny.model specialized-arrays.float
+accessors ;
IN: bunny.fixed-pipeline
TUPLE: bunny-fixed-pipeline ;
GL_LIGHTING glEnable
GL_LIGHT0 glEnable
GL_COLOR_MATERIAL glEnable
- GL_LIGHT0 GL_POSITION { 1.0 -1.0 1.0 1.0 } >c-float-array glLightfv
+ GL_LIGHT0 GL_POSITION float-array{ 1.0 -1.0 1.0 1.0 } underlying>> glLightfv
GL_FRONT_AND_BACK GL_SHININESS 100.0 glMaterialf
GL_FRONT_AND_BACK GL_SPECULAR glColorMaterial
GL_FRONT_AND_BACK GL_AMBIENT_AND_DIFFUSE glColorMaterial
http.client io io.encodings.ascii io.files kernel math
math.matrices math.parser math.vectors opengl
opengl.capabilities opengl.gl opengl.demo-support sequences
-sequences.lib splitting vectors words ;
+sequences.lib splitting vectors words
+specialized-arrays.float specialized-arrays.uint ;
IN: bunny.model
: numbers ( str -- seq )
{
[
[ first concat ] [ second concat ] bi
- append >c-float-array
+ append >float-array underlying>>
GL_ARRAY_BUFFER swap GL_STATIC_DRAW <gl-buffer>
]
[
- third concat >c-uint-array
+ third concat >uint-array underlying>>
GL_ELEMENT_ARRAY_BUFFER swap GL_STATIC_DRAW <gl-buffer>
]
[ first length 3 * ]
USING: arrays bunny.model bunny.cel-shaded continuations
destructors kernel math multiline opengl opengl.shaders
-opengl.framebuffers opengl.gl opengl.demo-support
-opengl.capabilities sequences ui.gadgets combinators accessors ;
+opengl.framebuffers opengl.gl opengl.demo-support fry
+opengl.capabilities sequences ui.gadgets combinators accessors
+macros ;
IN: bunny.outlined
STRING: outlined-pass1-fragment-shader-main-source
} cleave
] [ drop ] if ;
+MACRO: (framebuffer-texture>>draw) ( iformat xformat setter -- )
+ '[ _ _ (framebuffer-texture) [ @ drop ] keep ] ;
+
+: (make-framebuffer-textures) ( draw dim -- draw color normal depth )
+ {
+ [ drop ]
+ [ GL_RGBA16F_ARB GL_RGBA [ >>color-texture ] (framebuffer-texture>>draw) ]
+ [ GL_RGBA16F_ARB GL_RGBA [ >>normal-texture ] (framebuffer-texture>>draw) ]
+ [
+ GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT
+ [ >>depth-texture ] (framebuffer-texture>>draw)
+ ]
+ } 2cleave ;
+
+: remake-framebuffer ( draw -- )
+ [ dispose-framebuffer ]
+ [ dup gadget>> dim>>
+ [ (make-framebuffer-textures) (make-framebuffer) >>framebuffer ]
+ [ >>framebuffer-dim drop ] bi
+ ] bi ;
+
: remake-framebuffer-if-needed ( draw -- )
dup [ gadget>> dim>> ] [ framebuffer-dim>> ] bi =
- [ drop ] [
- [ dispose-framebuffer ] [ dup ] [ gadget>> dim>> ] tri {
- [
- GL_RGBA16F_ARB GL_RGBA (framebuffer-texture)
- [ >>color-texture drop ] keep
- ] [
- GL_RGBA16F_ARB GL_RGBA (framebuffer-texture)
- [ >>normal-texture drop ] keep
- ] [
- GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT (framebuffer-texture)
- [ >>depth-texture drop ] keep
- ]
- } 2cleave
- [ (make-framebuffer) >>framebuffer ] [ >>framebuffer-dim ] bi
- drop
- ] if ;
+ [ drop ] [ remake-framebuffer ] if ;
: clear-framebuffer ( -- )
GL_COLOR_ATTACHMENT0_EXT glDrawBuffer
! Copyright (C) 2008 Matthew Willis.
! See http://factorcode.org/license.txt for BSD license.
-USING: sequences math opengl.gadgets kernel
-byte-arrays cairo.ffi cairo io.backend
-ui.gadgets accessors opengl.gl
-arrays fry classes ;
+USING: sequences math kernel byte-arrays cairo.ffi cairo
+io.backend ui.gadgets accessors opengl.gl arrays fry
+classes ui.render namespaces ;
IN: cairo.gadgets
: width>stride ( width -- stride ) 4 * ;
-: copy-cairo ( dim quot -- byte-array )
- >r first2 over width>stride
- [ * nip <byte-array> dup CAIRO_FORMAT_ARGB32 ]
+GENERIC: render-cairo* ( gadget -- )
+
+: render-cairo ( gadget -- byte-array )
+ dup dim>> first2 over width>stride
+ [ * nip <byte-array> dup CAIRO_FORMAT_ARGB32 ]
[ cairo_image_surface_create_for_data ] 3bi
- r> with-cairo-from-surface ; inline
+ rot '[ _ render-cairo* ] with-cairo-from-surface ; inline
-TUPLE: cairo-gadget < texture-gadget ;
+TUPLE: cairo-gadget < gadget ;
: <cairo-gadget> ( dim -- gadget )
cairo-gadget new-gadget
swap >>dim ;
-M: cairo-gadget cache-key* [ dim>> ] [ class ] bi 2array ;
-
-: render-cairo ( dim quot -- bytes format )
- >r 2^-bounds r> copy-cairo GL_BGRA ; inline
-
-GENERIC: render-cairo* ( gadget -- )
-
-M: cairo-gadget render*
- [ dim>> dup ] [ '[ _ render-cairo* ] ] bi
- render-cairo render-bytes* ;
-
-! maybe also texture>png
-! : cairo>png ( gadget path -- )
-! >r [ cairo>bytes CAIRO_FORMAT_ARGB32 ] [ width>> ]
-! [ height>> ] tri over width>stride
-! cairo_image_surface_create_for_data
-! r> [ cairo_surface_write_to_png check-cairo ] curry with-surface ;
+M: cairo-gadget draw-gadget*
+ [ dim>> ] [ render-cairo ] bi
+ origin get first2 glRasterPos2i
+ 1.0 -1.0 glPixelZoom
+ >r first2 GL_BGRA GL_UNSIGNED_BYTE r>
+ glDrawPixels ;
: copy-surface ( surface -- )
cr swap 0 0 cairo_set_source_surface
cr cairo_paint ;
-
-TUPLE: png-gadget < texture-gadget path ;
-: <png> ( path -- gadget )
- png-gadget new-gadget
- swap >>path ;
-
-M: png-gadget render*
- path>> normalize-path cairo_image_surface_create_from_png
- [ cairo_image_surface_get_width ]
- [ cairo_image_surface_get_height 2array dup 2^-bounds ]
- [ [ copy-surface ] curry copy-cairo ] tri
- GL_BGRA render-bytes* ;
-
-M: png-gadget cache-key* path>> ;
! http://cairographics.org/samples/
USING: cairo cairo.ffi locals math.constants math
io.backend kernel alien.c-types libc namespaces
-cairo.gadgets ui.gadgets accessors ;
+cairo.gadgets ui.gadgets accessors specialized-arrays.double ;
IN: cairo.samples
TUPLE: dash-gadget < cairo-gadget ;
M:: dash-gadget render-cairo* ( gadget -- )
- [let | dashes [ { 50 10 10 10 } >c-double-array ]
+ [let | dashes [ double-array{ 50 10 10 10 } underlying>> ]
ndash [ 4 ] |
cr dashes ndash -50 cairo_set_dash
cr 10 cairo_set_line_width
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays byte-arrays kernel math namespaces
opengl.gl sequences math.vectors ui graphics.bitmap graphics.viewer
-models opengl.framebuffers ui.gadgets.worlds ui.gadgets fry alien.syntax ;
+models ui.gadgets.worlds ui.gadgets fry alien.syntax ;
IN: cap
: screenshot-array ( world -- byte-array )
- dim>> product 3 * <byte-array> ;
+ dim>> [ first 3 * 4 align ] [ second ] bi * <byte-array> ;
: gl-screenshot ( gadget -- byte-array )
[
vars colors self self.slots
random-weighted colors.hsv cfdg.gl accessors
ui.gadgets.handler ui.gestures assocs ui.gadgets macros
- qualified ;
+ qualified specialized-arrays.double ;
+
QUALIFIED: syntax
+
IN: cfdg
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: double-nth* ( c-array indices -- seq ) swap [ double-nth ] curry map ;
+! : double-nth* ( c-array indices -- seq ) swap [ double-nth ] curry map ;
+
+: double-nth* ( c-array indices -- seq )
+ swap byte-array>double-array [ nth ] curry map ;
: check-size ( modelview -- num ) { 0 1 4 5 } double-nth* [ abs ] map biggest ;
2 * sin , 2 * cos neg , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 , ]
- { } make >c-double-array glMultMatrixd ;
+ double-array{ } make underlying>> glMultMatrixd ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: delete-dlist ( -- ) dlist get [ dlist get 1 glDeleteLists dlist off ] when ;
-: cfdg-window* ( -- )
+: cfdg-window* ( -- slate )
C[ display ] <slate>
{ 500 500 } >>pdim
C[ delete-dlist ] >>ungraft
dup "CFDG" open-window ;
-: cfdg-window ( -- ) [ cfdg-window* ] with-ui ;
+: cfdg-window ( -- slate ) [ cfdg-window* ] with-ui ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
--- /dev/null
+
+USING: combinators.cleave fry kernel macros parser quotations ;
+
+IN: combinators.cleave.enhanced
+
+: \\
+ scan-word literalize parsed
+ scan-word literalize parsed ; parsing
+
+MACRO: bi ( p q -- quot )
+ [ >quot ] dip
+ >quot
+ '[ _ _ [ keep ] dip call ] ;
+
+MACRO: tri ( p q r -- quot )
+ [ >quot ] 2dip
+ [ >quot ] dip
+ >quot
+ '[ _ _ _ [ [ keep ] dip keep ] dip call ] ;
+
+MACRO: bi* ( p q -- quot )
+ [ >quot ] dip
+ >quot
+ '[ _ _ [ dip ] dip call ] ;
+
+MACRO: tri* ( p q r -- quot )
+ [ >quot ] 2dip
+ [ >quot ] dip
+ >quot
+ '[ _ _ _ [ [ 2dip ] dip dip ] dip call ] ;
+
[ { "foo" "xbarx" } ]
[
- { "oof" "bar" } { [ reverse ] [ "x" swap "x" 3append ] } parallel-call
+ { "oof" "bar" } { [ reverse ] [ "x" dup surround ] } parallel-call
] unit-test
{ 1 1 } [
! Generalized versions of core combinators
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: quad ( x p q r s -- ) >r >r >r keep r> keep r> keep r> call ; inline
+: quad ( x p q r s -- ) [ keep ] 3dip [ keep ] 2dip [ keep ] dip call ; inline
: 4slip ( quot a b c d -- a b c d ) 4 nslip ; inline
[ dip ] curry swap 1quotation [ keep ] curry compose
] { } assoc>map concat compose ;
-: either ( object first second -- ? )
- >r keep swap [ r> drop ] [ r> call ] ?if ; inline
-
: 2quot-with ( obj seq quot1 quot2 -- seq quot1 quot2 )
>r pick >r with r> r> swapd with ;
-: or? ( obj quot1 quot2 -- ? )
- >r keep r> rot [ 2nip ] [ call ] if* ; inline
-
-: and? ( obj quot1 quot2 -- ? )
- >r keep r> rot [ call ] [ 2drop f ] if ; inline
-
MACRO: multikeep ( word out-indexes -- ... )
[
dup >r [ \ npick \ >r 3array % ] each
r> [ drop \ r> , ] each
] [ ] make ;
-: retry ( quot n -- )
- [ drop ] rot compose attempt-all ; inline
-
: do-while ( pred body tail -- )
- >r tuck 2slip r> while ; inline
+ [ tuck 2slip ] dip while ; inline
: generate ( generator predicate -- obj )
- [ dup ] swap [ dup [ nip ] unless not ] 3compose
+ '[ dup @ dup [ nip ] unless not ]
swap [ ] do-while ;
MACRO: predicates ( seq -- quot/f )
dup [ 1quotation [ drop ] prepend ] map
- >r [ [ dup ] prepend ] map r> zip [ drop f ] suffix
+ [ [ [ dup ] prepend ] map ] dip zip [ drop f ] suffix
[ cond ] curry ;
: %chance ( quot n -- ) 100 random > swap when ; inline
-! Copyright (C) 2007 Slava Pestov.
+! Copyright (C) 2007, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: io.files io.launcher io.styles io.encodings.ascii io
-hashtables kernel sequences sequences.lib assocs system sorting
+USING: io.files io.launcher io.styles io.encodings.ascii
+prettyprint io hashtables kernel sequences assocs system sorting
math.parser sets ;
IN: contributors
: changelog ( -- authors )
image parent-directory [
- "git-log --pretty=format:%an" ascii <process-reader> lines
+ "git log --pretty=format:%an" ascii <process-reader> lines
] with-directory ;
: patch-counts ( authors -- assoc )
{ } map>assoc ;
: contributors ( -- )
- changelog patch-counts sort-values <reversed>
- standard-table-style [
- [
- [
- first2 swap
- [ write ] with-cell
- [ number>string write ] with-cell
- ] with-row
- ] each
- ] tabular-output ;
+ changelog patch-counts
+ sort-values <reversed>
+ simple-table. ;
MAIN: contributors
-! Copyright (C) 2008 DoDoug Coleman.
+! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: crypto.barrett kernel math namespaces tools.test ;
IN: crypto.barrett.tests
#! size = word size in bits (8, 16, 32, 64, ...)
[ [ log2 1+ ] [ / 2 * ] bi* ]
[ 2^ rot ^ swap /i ] 2bi ;
-
-
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
USING: arrays combinators checksums checksums.md5
checksums.sha1 checksums.md5.private io io.binary io.files
io.streams.byte-array kernel math math.vectors memoize sequences
-USING: kernel math threads system ;
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel math threads system calendar ;
IN: crypto.timing
: with-timing ( quot n -- )
#! force the quotation to execute in, at minimum, n milliseconds
- millis 2slip millis - + sleep ; inline
+ millis 2slip millis - + milliseconds sleep ; inline
ERROR: empty-xor-key ;
: xor-crypt ( seq key -- seq' )
- dup empty? [ empty-xor-key ] when
+ [ empty-xor-key ] when-empty
[ dup length ] dip '[ _ mod-nth bitxor ] 2map ;
-USING: words kernel sequences locals\r
-locals.private accessors parser namespaces continuations\r
+USING: words kernel sequences locals locals.parser\r
+locals.definitions accessors parser namespaces continuations\r
summary definitions generalizations arrays ;\r
IN: descriptive\r
\r
+++ /dev/null
-
-USING: kernel namespaces sequences math
- listener io prettyprint sequences.lib bake bake.fry ;
-
-IN: display-stack
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-SYMBOL: watched-variables
-
-: watch-var ( sym -- ) watched-variables get push ;
-
-: watch-vars ( seq -- ) watched-variables get [ push ] curry each ;
-
-: unwatch-var ( sym -- ) watched-variables get delete ;
-
-: unwatch-vars ( seq -- ) watched-variables get [ delete ] curry each ;
-
-: print-watched-variables ( -- )
- watched-variables get length 0 >
- [
- "----------" print
- watched-variables get
- watched-variables get [ unparse ] map longest length 2 +
- '[ [ unparse ": " append , 32 pad-right write ] [ get . ] bi ]
- each
-
- ]
- when ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: display-stack ( -- )
- V{ } clone watched-variables set
- [
- print-watched-variables
- "----------" print
- datastack [ . ] each
- "----------" print
- retainstack reverse [ . ] each
- ]
- listener-hook set ;
-
[ get-label ]
[ skip-label get-name ]
2bi
- "." swap 3append
+ "." glue
]
}
}
--- /dev/null
+
+USING: accessors arrays fry kernel math math.vectors sequences
+ math.intervals
+ multi-methods
+ combinators.short-circuit
+ combinators.cleave.enhanced
+ multi-method-syntax ;
+
+IN: flatland
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! Two dimensional world protocol
+
+GENERIC: x ( obj -- x )
+GENERIC: y ( obj -- y )
+
+GENERIC: (x!) ( x obj -- )
+GENERIC: (y!) ( y obj -- )
+
+: x! ( obj x -- obj ) over (x!) ;
+: y! ( obj y -- obj ) over (y!) ;
+
+GENERIC: width ( obj -- width )
+GENERIC: height ( obj -- height )
+
+GENERIC: (width!) ( width obj -- )
+GENERIC: (height!) ( height obj -- )
+
+: width! ( obj width -- obj ) over (width!) ;
+: height! ( obj height -- obj ) over (width!) ;
+
+! Predicates on relative placement
+
+GENERIC: to-the-left-of? ( obj obj -- ? )
+GENERIC: to-the-right-of? ( obj obj -- ? )
+
+GENERIC: below? ( obj obj -- ? )
+GENERIC: above? ( obj obj -- ? )
+
+GENERIC: in-between-horizontally? ( obj obj -- ? )
+
+GENERIC: horizontal-interval ( obj -- interval )
+
+GENERIC: move-to ( obj obj -- )
+
+GENERIC: move-by ( obj delta -- )
+
+GENERIC: move-left-by ( obj obj -- )
+GENERIC: move-right-by ( obj obj -- )
+
+GENERIC: left ( obj -- left )
+GENERIC: right ( obj -- right )
+GENERIC: bottom ( obj -- bottom )
+GENERIC: top ( obj -- top )
+
+GENERIC: distance ( a b -- c )
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! Some of the above methods work on two element sequences.
+! A two element sequence may represent a point in space or describe
+! width and height.
+
+METHOD: x ( sequence -- x ) first ;
+METHOD: y ( sequence -- y ) second ;
+
+METHOD: (x!) ( number sequence -- ) set-first ;
+METHOD: (y!) ( number sequence -- ) set-second ;
+
+METHOD: width ( sequence -- width ) first ;
+METHOD: height ( sequence -- height ) second ;
+
+: changed-x ( seq quot -- ) over [ [ x ] dip call ] dip (x!) ; inline
+: changed-y ( seq quot -- ) over [ [ y ] dip call ] dip (y!) ; inline
+
+METHOD: move-to ( sequence sequence -- ) [ x x! ] [ y y! ] bi drop ;
+METHOD: move-by ( sequence sequence -- ) dupd v+ [ x x! ] [ y y! ] bi drop ;
+
+METHOD: move-left-by ( sequence number -- ) '[ _ - ] changed-x ;
+METHOD: move-right-by ( sequence number -- ) '[ _ + ] changed-x ;
+
+! METHOD: move-left-by ( sequence number -- ) neg 0 2array move-by ;
+! METHOD: move-right-by ( sequence number -- ) 0 2array move-by ;
+
+! METHOD:: move-left-by ( SEQ:sequence X:number -- )
+! SEQ { X 0 } { -1 0 } v* move-by ;
+
+METHOD: distance ( sequence sequence -- dist ) v- norm ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! A class for objects with a position
+
+TUPLE: <pos> pos ;
+
+METHOD: x ( <pos> -- x ) pos>> first ;
+METHOD: y ( <pos> -- y ) pos>> second ;
+
+METHOD: (x!) ( number <pos> -- ) pos>> set-first ;
+METHOD: (y!) ( number <pos> -- ) pos>> set-second ;
+
+METHOD: to-the-left-of? ( <pos> number -- ? ) [ x ] dip < ;
+METHOD: to-the-right-of? ( <pos> number -- ? ) [ x ] dip > ;
+
+METHOD: move-left-by ( <pos> number -- ) [ pos>> ] dip move-left-by ;
+METHOD: move-right-by ( <pos> number -- ) [ pos>> ] dip move-right-by ;
+
+METHOD: above? ( <pos> number -- ? ) [ y ] dip > ;
+METHOD: below? ( <pos> number -- ? ) [ y ] dip < ;
+
+METHOD: move-by ( <pos> sequence -- ) '[ _ v+ ] change-pos drop ;
+
+METHOD: distance ( <pos> <pos> -- dist ) [ pos>> ] bi@ distance ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! A class for objects with velocity. It inherits from <pos>. Hey, if
+! it's moving it has a position right? Unless it's some alternate universe...
+
+TUPLE: <vel> < <pos> vel ;
+
+: moving-up? ( obj -- ? ) vel>> y 0 > ;
+: moving-down? ( obj -- ? ) vel>> y 0 < ;
+
+: step-size ( vel time -- dist ) [ vel>> ] dip v*n ;
+: move-for ( vel time -- ) dupd step-size move-by ;
+
+: reverse-horizontal-velocity ( vel -- ) vel>> [ x neg ] [ ] bi (x!) ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! The 'pos' slot indicates the lower left hand corner of the
+! rectangle. The 'dim' is holds the width and height.
+
+TUPLE: <rectangle> < <pos> dim ;
+
+METHOD: width ( <rectangle> -- width ) dim>> first ;
+METHOD: height ( <rectangle> -- height ) dim>> second ;
+
+METHOD: left ( <rectangle> -- x ) x ;
+METHOD: right ( <rectangle> -- x ) \\ x width bi + ;
+METHOD: bottom ( <rectangle> -- y ) y ;
+METHOD: top ( <rectangle> -- y ) \\ y height bi + ;
+
+: bottom-left ( rectangle -- pos ) pos>> ;
+
+: center-x ( rectangle -- x ) [ left ] [ width 2 / ] bi + ;
+: center-y ( rectangle -- y ) [ bottom ] [ height 2 / ] bi + ;
+
+: center ( rectangle -- seq ) \\ center-x center-y bi 2array ;
+
+METHOD: to-the-left-of? ( <pos> <rectangle> -- ? ) \\ x left bi* < ;
+METHOD: to-the-right-of? ( <pos> <rectangle> -- ? ) \\ x right bi* > ;
+
+METHOD: below? ( <pos> <rectangle> -- ? ) \\ y bottom bi* < ;
+METHOD: above? ( <pos> <rectangle> -- ? ) \\ y top bi* > ;
+
+METHOD: horizontal-interval ( <rectangle> -- interval )
+ \\ left right bi [a,b] ;
+
+METHOD: in-between-horizontally? ( <pos> <rectangle> -- ? )
+ \\ x horizontal-interval bi* interval-contains? ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+TUPLE: <extent> left right bottom top ;
+
+METHOD: left ( <extent> -- left ) left>> ;
+METHOD: right ( <extent> -- right ) right>> ;
+METHOD: bottom ( <extent> -- bottom ) bottom>> ;
+METHOD: top ( <extent> -- top ) top>> ;
+
+METHOD: width ( <extent> -- width ) \\ right>> left>> bi - ;
+METHOD: height ( <extent> -- height ) \\ top>> bottom>> bi - ;
+
+! METHOD: to-extent ( <rectangle> -- <extent> )
+! { [ left>> ] [ right>> ] [ bottom>> ] [ top>> ] } cleave <extent> boa ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+METHOD: to-the-left-of? ( sequence <rectangle> -- ? ) \\ x left bi* < ;
+METHOD: to-the-right-of? ( sequence <rectangle> -- ? ) \\ x right bi* > ;
+
+METHOD: below? ( sequence <rectangle> -- ? ) \\ y bottom bi* < ;
+METHOD: above? ( sequence <rectangle> -- ? ) \\ y top bi* > ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! Some support for the' 'rect' class from math.geometry.rect'
+
+! METHOD: width ( rect -- width ) dim>> first ;
+! METHOD: height ( rect -- height ) dim>> second ;
+
+! METHOD: left ( rect -- left ) loc>> x
+! METHOD: right ( rect -- right ) [ loc>> x ] [ width ] bi + ;
+
+! METHOD: to-the-left-of? ( sequence rect -- ? ) [ x ] [ loc>> x ] bi* < ;
+! METHOD: to-the-right-of? ( sequence rect -- ? ) [ x ] [ loc>> x ] bi* > ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+USING: locals combinators ;
+
+:: wrap ( POINT RECT -- POINT )
+
+ {
+ { [ POINT RECT to-the-left-of? ] [ RECT right ] }
+ { [ POINT RECT to-the-right-of? ] [ RECT left ] }
+ { [ t ] [ POINT x ] }
+ }
+ cond
+
+ {
+ { [ POINT RECT below? ] [ RECT top ] }
+ { [ POINT RECT above? ] [ RECT bottom ] }
+ { [ t ] [ POINT y ] }
+ }
+ cond
+
+ 2array ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+GENERIC: within? ( a b -- ? )
+
+METHOD: within? ( <pos> <rectangle> -- ? )
+ {
+ [ left to-the-right-of? ]
+ [ right to-the-left-of? ]
+ [ bottom above? ]
+ [ top below? ]
+ }
+ 2&& ;
+++ /dev/null
-Doug Coleman
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays classes.singleton combinators
-continuations io io.encodings.binary io.encodings.utf8
-io.files io.sockets kernel io.streams.duplex math
-math.parser sequences splitting namespaces strings fry ftp
-ftp.client.listing-parser urls ;
-IN: ftp.client
-
-: (ftp-response-code) ( str -- n )
- 3 head string>number ;
-
-: ftp-response-code ( string -- n/f )
- dup fourth CHAR: - = [ drop f ] [ (ftp-response-code) ] if ;
-
-: read-response-loop ( ftp-response -- ftp-response )
- readln
- [ add-response-line ] [ ftp-response-code ] bi
- over n>> = [ read-response-loop ] unless ;
-
-: read-response ( -- ftp-response )
- <ftp-response> readln
- [ (ftp-response-code) >>n ]
- [ add-response-line ]
- [ fourth CHAR: - = ] tri
- [ read-response-loop ] when ;
-
-ERROR: ftp-error got expected ;
-
-: ftp-assert ( ftp-response n -- )
- 2dup [ n>> ] dip = [ 2drop ] [ ftp-error ] if ;
-
-: ftp-command ( string -- ftp-response )
- ftp-send read-response ;
-
-: ftp-user ( url -- ftp-response )
- username>> "USER " prepend ftp-command ;
-
-: ftp-password ( url -- ftp-response )
- password>> "PASS " prepend ftp-command ;
-
-: ftp-cwd ( directory -- ftp-response )
- "CWD " prepend ftp-command ;
-
-: ftp-retr ( filename -- ftp-response )
- "RETR " prepend ftp-command ;
-
-: ftp-set-binary ( -- ftp-response ) "TYPE I" ftp-command ;
-
-: ftp-pwd ( -- ftp-response ) "PWD" ftp-command ;
-
-: ftp-list ( -- )
- "LIST" ftp-command 150 ftp-assert ;
-
-: ftp-quit ( -- ftp-response ) "QUIT" ftp-command ;
-
-: ftp-epsv ( -- ftp-response )
- "EPSV" ftp-command dup 229 ftp-assert ;
-
-: parse-epsv ( ftp-response -- port )
- strings>> first "|" split 2 tail* first string>number ;
-
-: open-passive-client ( url protocol -- stream )
- [ host>> ftp-epsv parse-epsv <inet> ] dip <client> drop ;
-
-: list ( url -- ftp-response )
- utf8 open-passive-client
- ftp-list
- lines
- <ftp-response> swap >>strings
- read-response 226 ftp-assert
- parse-list ;
-
-: (ftp-get) ( url path -- )
- [ binary open-passive-client ] dip
- [ ftp-retr 150 ftp-assert drop ]
- [ binary <file-writer> stream-copy ] 2bi
- read-response 226 ftp-assert ;
-
-: ftp-login ( url -- )
- read-response 220 ftp-assert
- [ ftp-user 331 ftp-assert ]
- [ ftp-password 230 ftp-assert ] bi
- ftp-set-binary 200 ftp-assert ;
-
-: ftp-connect ( url -- stream )
- [ host>> ] [ port>> ] bi <inet> utf8 <client> drop ;
-
-: with-ftp-client ( url quot -- )
- [ [ ftp-connect ] keep ] dip
- '[ _ [ ftp-login ] _ bi ftp-quit drop ] with-stream ; inline
-
-: ensure-login ( url -- url )
- dup username>> [
- "anonymous" >>username
- "ftp-client" >>password
- ] unless ;
-
-: >ftp-url ( url -- url' ) >url ensure-port ensure-login ;
-
-: ftp-get ( url -- )
- >ftp-url [
- dup path>>
- [ nip parent-directory ftp-cwd drop ]
- [ file-name (ftp-get) ] 2bi
- ] with-ftp-client ;
-
-
-
-
+++ /dev/null
-Doug Coleman
\ No newline at end of file
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors combinators io.files kernel math.parser
-sequences splitting ;
-IN: ftp.client.listing-parser
-
-: ch>file-type ( ch -- type )
- {
- { CHAR: b [ +block-device+ ] }
- { CHAR: c [ +character-device+ ] }
- { CHAR: d [ +directory+ ] }
- { CHAR: l [ +symbolic-link+ ] }
- { CHAR: s [ +socket+ ] }
- { CHAR: p [ +fifo+ ] }
- { CHAR: - [ +regular-file+ ] }
- [ drop +unknown+ ]
- } case ;
-
-: file-type>ch ( type -- string )
- {
- { +block-device+ [ CHAR: b ] }
- { +character-device+ [ CHAR: c ] }
- { +directory+ [ CHAR: d ] }
- { +symbolic-link+ [ CHAR: l ] }
- { +socket+ [ CHAR: s ] }
- { +fifo+ [ CHAR: p ] }
- { +regular-file+ [ CHAR: - ] }
- [ drop CHAR: - ]
- } case ;
-
-: parse-permissions ( remote-file str -- remote-file )
- [ first ch>file-type >>type ] [ rest >>permissions ] bi ;
-
-TUPLE: remote-file
-type permissions links owner group size month day time year
-name target ;
-
-: <remote-file> ( -- remote-file ) remote-file new ;
-
-: parse-list-11 ( lines -- seq )
- [
- 11 f pad-right
- <remote-file> swap {
- [ 0 swap nth parse-permissions ]
- [ 1 swap nth string>number >>links ]
- [ 2 swap nth >>owner ]
- [ 3 swap nth >>group ]
- [ 4 swap nth string>number >>size ]
- [ 5 swap nth >>month ]
- [ 6 swap nth >>day ]
- [ 7 swap nth >>time ]
- [ 8 swap nth >>name ]
- [ 10 swap nth >>target ]
- } cleave
- ] map ;
-
-: parse-list-8 ( lines -- seq )
- [
- <remote-file> swap {
- [ 0 swap nth parse-permissions ]
- [ 1 swap nth string>number >>links ]
- [ 2 swap nth >>owner ]
- [ 3 swap nth >>size ]
- [ 4 swap nth >>month ]
- [ 5 swap nth >>day ]
- [ 6 swap nth >>time ]
- [ 7 swap nth >>name ]
- } cleave
- ] map ;
-
-: parse-list-3 ( lines -- seq )
- [
- <remote-file> swap {
- [ 0 swap nth parse-permissions ]
- [ 1 swap nth string>number >>links ]
- [ 2 swap nth >>name ]
- } cleave
- ] map ;
-
-: parse-list ( ftp-response -- ftp-response )
- dup strings>>
- [ " " split harvest ] map
- dup length {
- { 11 [ parse-list-11 ] }
- { 9 [ parse-list-11 ] }
- { 8 [ parse-list-8 ] }
- { 3 [ parse-list-3 ] }
- [ drop ]
- } case >>parsed ;
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays assocs combinators io io.files kernel
-math.parser sequences strings ;
-IN: ftp
-
-SINGLETON: active
-SINGLETON: passive
-
-TUPLE: ftp-response n strings parsed ;
-
-: <ftp-response> ( -- ftp-response )
- ftp-response new
- V{ } clone >>strings ;
-
-: add-response-line ( ftp-response string -- ftp-response )
- over strings>> push ;
-
-: ftp-send ( string -- ) write "\r\n" write flush ;
-: ftp-ipv4 1 ; inline
-: ftp-ipv6 2 ; inline
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: combinators.short-circuit accessors combinators io
-io.encodings.8-bit io.encodings io.encodings.binary
-io.encodings.utf8 io.files io.sockets kernel math.parser
-namespaces make sequences ftp io.unix.launcher.parser
-unicode.case splitting assocs classes io.servers.connection
-destructors calendar io.timeouts io.streams.duplex threads
-continuations math concurrency.promises byte-arrays
-io.backend sequences.lib tools.hexdump io.files.listing ;
-IN: ftp.server
-
-TUPLE: ftp-client url mode state command-promise ;
-
-: <ftp-client> ( url -- ftp-client )
- ftp-client new
- swap >>url ;
-
-SYMBOL: client
-
-: ftp-server-directory ( -- str )
- \ ftp-server-directory get-global "resource:temp" or
- normalize-path ;
-
-TUPLE: ftp-command raw tokenized ;
-
-: <ftp-command> ( -- obj )
- ftp-command new ;
-
-TUPLE: ftp-get path ;
-
-: <ftp-get> ( path -- obj )
- ftp-get new
- swap >>path ;
-
-TUPLE: ftp-put path ;
-
-: <ftp-put> ( path -- obj )
- ftp-put new
- swap >>path ;
-
-TUPLE: ftp-list ;
-
-C: <ftp-list> ftp-list
-
-: read-command ( -- ftp-command )
- <ftp-command> readln
- [ >>raw ] [ tokenize-command >>tokenized ] bi ;
-
-: (send-response) ( n string separator -- )
- rot number>string write write ftp-send ;
-
-: send-response ( ftp-response -- )
- [ n>> ] [ strings>> ] bi
- [ but-last-slice [ "-" (send-response) ] with each ]
- [ first " " (send-response) ] 2bi ;
-
-: server-response ( n string -- )
- <ftp-response>
- swap add-response-line
- swap >>n
- send-response ;
-
-: ftp-error ( string -- )
- 500 "Unrecognized command: " rot append server-response ;
-
-: send-banner ( -- )
- 220 "Welcome to " host-name append server-response ;
-
-: anonymous-only ( -- )
- 530 "This FTP server is anonymous only." server-response ;
-
-: handle-QUIT ( obj -- )
- drop 221 "Goodbye." server-response ;
-
-: handle-USER ( ftp-command -- )
- [
- tokenized>> second client get (>>user)
- 331 "Please specify the password." server-response
- ] [
- 2drop "bad USER" ftp-error
- ] recover ;
-
-: handle-PASS ( ftp-command -- )
- [
- tokenized>> second client get (>>password)
- 230 "Login successful" server-response
- ] [
- 2drop "PASS error" ftp-error
- ] recover ;
-
-ERROR: type-error type ;
-
-: parse-type ( string -- string' )
- >upper {
- { "IMAGE" [ "Binary" ] }
- { "I" [ "Binary" ] }
- [ type-error ]
- } case ;
-
-: handle-TYPE ( obj -- )
- [
- tokenized>> second parse-type
- 200 "Switching to " rot " mode" 3append server-response
- ] [
- 2drop "TYPE is binary only" ftp-error
- ] recover ;
-
-: random-local-server ( -- server )
- remote-address get class new 0 >>port binary <server> ;
-
-: port>bytes ( port -- hi lo )
- [ -8 shift ] keep [ HEX: ff bitand ] bi@ ;
-
-: handle-PWD ( obj -- )
- drop
- 257 current-directory get "\"" "\"" surround server-response ;
-
-: handle-SYST ( obj -- )
- drop
- 215 "UNIX Type: L8" server-response ;
-
-: if-command-promise ( quot -- )
- [ client get command-promise>> ] dip
- [ "Establish an active or passive connection first" ftp-error ] if* ;
-
-: handle-STOR ( obj -- )
- [
- tokenized>> second
- [ [ <ftp-put> ] dip fulfill ] if-command-promise
- ] [
- 2drop
- ] recover ;
-
-! EPRT |2|::1|62138|
-! : handle-EPRT ( obj -- )
- ! tokenized>> second "|" split harvest ;
-
-: start-directory ( -- )
- 150 "Here comes the directory listing." server-response ;
-
-: finish-directory ( -- )
- 226 "Opening " server-response ;
-
-GENERIC: service-command ( stream obj -- )
-
-M: ftp-list service-command ( stream obj -- )
- drop
- start-directory
- [
- utf8 encode-output
- directory. [ ftp-send ] each
- ] with-output-stream
- finish-directory ;
-
-: transfer-outgoing-file ( path -- )
- 150 "Opening BINARY mode data connection for "
- rot
- [ file-name ] [
- " " swap file-info size>> number>string
- "(" " bytes)." surround append
- ] bi 3append server-response ;
-
-: transfer-incoming-file ( path -- )
- 150 "Opening BINARY mode data connection for " rot append
- server-response ;
-
-: finish-file-transfer ( -- )
- 226 "File send OK." server-response ;
-
-M: ftp-get service-command ( stream obj -- )
- [
- path>>
- [ transfer-outgoing-file ]
- [ binary <file-reader> swap stream-copy ] bi
- finish-file-transfer
- ] [
- 3drop "File transfer failed" ftp-error
- ] recover ;
-
-M: ftp-put service-command ( stream obj -- )
- [
- path>>
- [ transfer-incoming-file ]
- [ binary <file-writer> stream-copy ] bi
- finish-file-transfer
- ] [
- 3drop "File transfer failed" ftp-error
- ] recover ;
-
-: passive-loop ( server -- )
- [
- [
- |dispose
- 30 seconds over set-timeout
- accept drop &dispose
- client get command-promise>>
- 30 seconds ?promise-timeout
- service-command
- ]
- [ client get f >>command-promise drop ]
- [ drop ] cleanup
- ] with-destructors ;
-
-: handle-LIST ( obj -- )
- drop
- [ [ <ftp-list> ] dip fulfill ] if-command-promise ;
-
-: handle-SIZE ( obj -- )
- [
- tokenized>> second file-info size>>
- 213 swap number>string server-response
- ] [
- 2drop
- 550 "Could not get file size" server-response
- ] recover ;
-
-: handle-RETR ( obj -- )
- [ tokenized>> second <ftp-get> swap fulfill ]
- curry if-command-promise ;
-
-: expect-connection ( -- port )
- random-local-server
- client get <promise> >>command-promise drop
- [ [ passive-loop ] curry in-thread ]
- [ addr>> port>> ] bi ;
-
-: handle-PASV ( obj -- )
- drop client get passive >>mode drop
- expect-connection
- [
- "Entering Passive Mode (127,0,0,1," %
- port>bytes [ number>string ] bi@ "," splice %
- ")" %
- ] "" make 227 swap server-response ;
-
-: handle-EPSV ( obj -- )
- drop
- client get command-promise>> [
- "You already have a passive stream" ftp-error
- ] [
- 229 "Entering Extended Passive Mode (|||"
- expect-connection number>string
- "|)" 3append server-response
- ] if ;
-
-! LPRT 6,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,242,186
-! : handle-LPRT ( obj -- ) tokenized>> "," split ;
-
-ERROR: not-a-directory ;
-ERROR: no-permissions ;
-
-: handle-CWD ( obj -- )
- [
- tokenized>> second dup normalize-path
- dup ftp-server-directory head? [
- no-permissions
- ] unless
-
- file-info directory? [
- set-current-directory
- 250 "Directory successully changed." server-response
- ] [
- not-a-directory
- ] if
- ] [
- 2drop
- 550 "Failed to change directory." server-response
- ] recover ;
-
-: unrecognized-command ( obj -- ) raw>> ftp-error ;
-
-: handle-client-loop ( -- )
- <ftp-command> readln
- USE: prettyprint global [ dup . flush ] bind
- [ >>raw ]
- [ tokenize-command >>tokenized ] bi
- dup tokenized>> first >upper {
- { "USER" [ handle-USER t ] }
- { "PASS" [ handle-PASS t ] }
- { "ACCT" [ drop "ACCT unimplemented" ftp-error t ] }
- { "CWD" [ handle-CWD t ] }
- ! { "XCWD" [ ] }
- ! { "CDUP" [ ] }
- ! { "SMNT" [ ] }
-
- ! { "REIN" [ drop client get reset-ftp-client t ] }
- { "QUIT" [ handle-QUIT f ] }
-
- ! { "PORT" [ ] } ! TODO
- { "PASV" [ handle-PASV t ] }
- ! { "MODE" [ ] }
- { "TYPE" [ handle-TYPE t ] }
- ! { "STRU" [ ] }
-
- ! { "ALLO" [ ] }
- ! { "REST" [ ] }
- { "STOR" [ handle-STOR t ] }
- ! { "STOU" [ ] }
- { "RETR" [ handle-RETR t ] }
- { "LIST" [ handle-LIST t ] }
- { "SIZE" [ handle-SIZE t ] }
- ! { "NLST" [ ] }
- ! { "APPE" [ ] }
- ! { "RNFR" [ ] }
- ! { "RNTO" [ ] }
- ! { "DELE" [ handle-DELE t ] }
- ! { "RMD" [ handle-RMD t ] }
- ! ! { "XRMD" [ handle-XRMD t ] }
- ! { "MKD" [ handle-MKD t ] }
- { "PWD" [ handle-PWD t ] }
- ! { "ABOR" [ ] }
-
- { "SYST" [ handle-SYST t ] }
- ! { "STAT" [ ] }
- ! { "HELP" [ ] }
-
- ! { "SITE" [ ] }
- ! { "NOOP" [ ] }
-
- ! { "EPRT" [ handle-EPRT ] }
- ! { "LPRT" [ handle-LPRT ] }
- { "EPSV" [ handle-EPSV t ] }
- ! { "LPSV" [ drop handle-LPSV t ] }
- [ drop unrecognized-command t ]
- } case [ handle-client-loop ] when ;
-
-TUPLE: ftp-server < threaded-server ;
-
-M: ftp-server handle-client* ( server -- )
- drop
- [
- ftp-server-directory [
- host-name <ftp-client> client set
- send-banner handle-client-loop
- ] with-directory
- ] with-destructors ;
-
-: <ftp-server> ( port -- server )
- ftp-server new-threaded-server
- swap >>insecure
- "ftp.server" >>name
- 5 minutes >>timeout
- latin1 >>encoding ;
-
-: ftpd ( port -- )
- <ftp-server> start-server ;
-
-: ftpd-main ( -- ) 2100 ftpd ;
-
-MAIN: ftpd-main
-
-! sudo tcpdump -i en1 -A -s 10000 tcp port 21
--- /dev/null
+Jose Antonio Ortega Ruiz
+Eduardo Cavazos
--- /dev/null
+! Copyright (C) 2008 Your name.
+! See http://factorcode.org/license.txt for BSD license.
+USING: tools.test fuel ;
+IN: fuel.tests
--- /dev/null
+! Copyright (C) 2008 Jose Antonio Ortega Ruiz.
+! See http://factorcode.org/license.txt for BSD license.
+
+USING: accessors arrays classes classes.tuple compiler.units
+combinators continuations debugger definitions eval help
+io io.files io.streams.string kernel lexer listener listener.private
+make math namespaces parser prettyprint prettyprint.config
+quotations sequences strings source-files vectors vocabs.loader ;
+
+IN: fuel
+
+! Evaluation status:
+
+TUPLE: fuel-status in use ds? restarts ;
+
+SYMBOL: fuel-status-stack
+V{ } clone fuel-status-stack set-global
+
+SYMBOL: fuel-eval-result
+f clone fuel-eval-result set-global
+
+SYMBOL: fuel-eval-output
+f clone fuel-eval-result set-global
+
+SYMBOL: fuel-eval-res-flag
+t clone fuel-eval-res-flag set-global
+
+: fuel-eval-restartable? ( -- ? )
+ fuel-eval-res-flag get-global ; inline
+
+: fuel-eval-restartable ( -- )
+ t fuel-eval-res-flag set-global ; inline
+
+: fuel-eval-non-restartable ( -- )
+ f fuel-eval-res-flag set-global ; inline
+
+: push-fuel-status ( -- )
+ in get use get clone display-stacks? get restarts get-global clone
+ fuel-status boa
+ fuel-status-stack get push ;
+
+: pop-fuel-status ( -- )
+ fuel-status-stack get empty? [
+ fuel-status-stack get pop {
+ [ in>> in set ]
+ [ use>> clone use set ]
+ [ ds?>> display-stacks? swap [ on ] [ off ] if ]
+ [
+ restarts>> fuel-eval-restartable? [ drop ] [
+ clone restarts set-global
+ ] if
+ ]
+ } cleave
+ ] unless ;
+
+
+! Lispy pretty printing
+
+GENERIC: fuel-pprint ( obj -- )
+
+M: object fuel-pprint pprint ; inline
+
+M: f fuel-pprint drop "nil" write ; inline
+
+M: integer fuel-pprint pprint ; inline
+
+M: string fuel-pprint pprint ; inline
+
+M: sequence fuel-pprint
+ dup empty? [ drop f fuel-pprint ] [
+ "(" write
+ [ " " write ] [ fuel-pprint ] interleave
+ ")" write
+ ] if ;
+
+M: tuple fuel-pprint tuple>array fuel-pprint ; inline
+
+M: continuation fuel-pprint drop ":continuation" write ; inline
+
+M: restart fuel-pprint name>> fuel-pprint ; inline
+
+SYMBOL: :restarts
+
+: fuel-restarts ( obj -- seq )
+ compute-restarts :restarts prefix ; inline
+
+M: condition fuel-pprint
+ [ error>> ] [ fuel-restarts ] bi 2array condition prefix fuel-pprint ;
+
+M: source-file-error fuel-pprint
+ [ file>> ] [ error>> ] bi 2array source-file-error prefix
+ fuel-pprint ;
+
+M: source-file fuel-pprint path>> fuel-pprint ;
+
+! Evaluation vocabulary
+
+: fuel-eval-set-result ( obj -- )
+ clone fuel-eval-result set-global ; inline
+
+: fuel-retort ( -- )
+ error get
+ fuel-eval-result get-global
+ fuel-eval-output get-global
+ 3array fuel-pprint ;
+
+: fuel-forget-error ( -- ) f error set-global ; inline
+: fuel-forget-result ( -- ) f fuel-eval-result set-global ; inline
+: fuel-forget-output ( -- ) f fuel-eval-output set-global ; inline
+
+: (fuel-begin-eval) ( -- )
+ push-fuel-status
+ display-stacks? off
+ fuel-forget-error
+ fuel-forget-result
+ fuel-forget-output ;
+
+: (fuel-end-eval) ( quot -- )
+ with-string-writer fuel-eval-output set-global
+ fuel-retort pop-fuel-status ; inline
+
+: (fuel-eval) ( lines -- )
+ [ [ parse-lines ] with-compilation-unit call ] curry
+ [ print-error ] recover ; inline
+
+: (fuel-eval-each) ( lines -- )
+ [ 1vector (fuel-eval) ] each ; inline
+
+: (fuel-eval-usings) ( usings -- )
+ [ "USING: " prepend " ;" append ] map
+ (fuel-eval-each) fuel-forget-error fuel-forget-output ;
+
+: (fuel-eval-in) ( in -- )
+ [ dup "IN: " prepend 1vector (fuel-eval) in set ] when* ; inline
+
+: fuel-eval-in-context ( lines in usings -- )
+ (fuel-begin-eval) [
+ (fuel-eval-usings)
+ (fuel-eval-in)
+ (fuel-eval)
+ ] (fuel-end-eval) ;
+
+: fuel-begin-eval ( in -- )
+ (fuel-begin-eval)
+ (fuel-eval-in)
+ fuel-retort ;
+
+: fuel-eval ( lines -- )
+ (fuel-begin-eval) [ (fuel-eval) ] (fuel-end-eval) ; inline
+
+: fuel-end-eval ( -- ) [ ] (fuel-end-eval) ; inline
+
+: fuel-get-edit-location ( defspec -- )
+ where [ first2 [ (normalize-path) ] dip 2array fuel-eval-set-result ] when* ;
+
+: fuel-run-file ( path -- ) run-file ; inline
+
+: fuel-startup ( -- ) "listener" run ; inline
+
+MAIN: fuel-startup
--- /dev/null
+Slava Pestov
--- /dev/null
+Slides from a talk at Galois by Slava Pestov, October 2008
-USING: windows.dinput windows.dinput.constants parser
-symbols alien.c-types windows.ole32 namespaces assocs kernel
-arrays vectors windows.kernel32 windows.com windows.dinput
-shuffle windows.user32 windows.messages sequences combinators
+USING: windows.dinput windows.dinput.constants parser symbols
+alien.c-types windows.ole32 namespaces assocs kernel arrays
+vectors windows.kernel32 windows.com windows.dinput shuffle
+windows.user32 windows.messages sequences combinators
math.geometry.rect ui.windows accessors math windows alien
-alien.strings io.encodings.utf16 continuations byte-arrays
-locals game-input.backend.dinput.keys-array ;
+alien.strings io.encodings.utf16 io.encodings.utf16n
+continuations byte-arrays locals
+game-input.backend.dinput.keys-array ;
<< "game-input" (use+) >>
IN: game-input.backend.dinput
+++ /dev/null
-Eduardo Cavazos
+++ /dev/null
-USING: tools.deploy.config ;
-V{
- { deploy-ui? t }
- { deploy-io 1 }
- { deploy-reflection 1 }
- { deploy-compiler? t }
- { deploy-math? t }
- { deploy-word-props? f }
- { deploy-c-types? f }
- { "stop-after-last-window?" t }
- { deploy-name "Golden Section" }
-}
+++ /dev/null
-
-USING: kernel namespaces math math.constants math.functions math.order
- arrays sequences
- opengl opengl.gl opengl.glu ui ui.render ui.gadgets ui.gadgets.theme
- ui.gadgets.cartesian colors accessors combinators.cleave
- processing.shapes ;
-
-IN: golden-section
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-! omega(i) = 2*pi*i*(phi-1)
-
-! x(i) = 0.5*i*cos(omega(i))
-! y(i) = 0.5*i*sin(omega(i))
-
-! radius(i) = 10*sin((pi*i)/720)
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: omega ( i -- omega ) phi 1- * 2 * pi * ;
-
-: x ( i -- x ) [ omega cos ] [ 0.5 * ] bi * ;
-: y ( i -- y ) [ omega sin ] [ 0.5 * ] bi * ;
-
-: center ( i -- point ) { x y } 1arr ;
-
-: radius ( i -- radius ) pi * 720 / sin 10 * ;
-
-: color ( i -- i ) dup 360.0 / dup 0.25 1 rgba boa >fill-color ;
-
-: line-width ( i -- i ) dup radius 0.5 * 1 max glLineWidth ;
-
-: draw ( i -- ) [ center ] [ radius 1.5 * 2 * ] bi circle ;
-
-: dot ( i -- ) color line-width draw ;
-
-: golden-section ( -- ) 720 [ dot ] each ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: <golden-section> ( -- gadget )
- <cartesian>
- { 600 600 } >>pdim
- { -400 400 } x-range
- { -400 400 } y-range
- [ golden-section ] >>action ;
-
-: golden-section-window ( -- )
- [ <golden-section> "Golden Section" open-window ] with-ui ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-MAIN: golden-section-window
+++ /dev/null
-Golden section demo
--- /dev/null
+Slava Pestov
--- /dev/null
+Slides from Google Tech Talk by Slava Pestov, October 2008
! Copyright (C) 2007 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: alien arrays byte-arrays combinators summary
-io.backend graphics.viewer io io.binary io.files kernel libc
-math math.functions namespaces opengl opengl.gl prettyprint
-sequences strings ui ui.gadgets.panes io.encodings.binary
-accessors grouping ;
+USING: alien arrays byte-arrays combinators summary io.backend
+graphics.viewer io io.binary io.files kernel libc math
+math.functions math.bitwise namespaces opengl opengl.gl
+prettyprint sequences strings ui ui.gadgets.panes fry
+io.encodings.binary accessors grouping macros alien.c-types ;
IN: graphics.bitmap
-! Currently can only handle 24bit bitmaps.
+! Currently can only handle 24/32bit bitmaps.
! Handles row-reversed bitmaps (their height is negative)
TUPLE: bitmap magic size reserved offset header-length width
height planes bit-count compression size-image
x-pels y-pels color-used color-important rgb-quads color-index array ;
+: (array-copy) ( bitmap array -- bitmap array' )
+ over size-image>> abs memory>byte-array ;
+
+MACRO: (nbits>bitmap) ( bits -- )
+ [ -3 shift ] keep '[
+ bitmap new
+ 2over * _ * >>size-image
+ swap >>height
+ swap >>width
+ swap (array-copy) [ >>array ] [ >>color-index ] bi
+ _ >>bit-count
+ ] ;
+
: bgr>bitmap ( array height width -- bitmap )
- bitmap new
- 2over * 3 * >>size-image
- swap >>height
- swap >>width
- swap [ >>array ] [ >>color-index ] bi
- 24 >>bit-count ;
+ 24 (nbits>bitmap) ;
+
+: bgra>bitmap ( array height width -- bitmap )
+ 32 (nbits>bitmap) ;
: 8bit>array ( bitmap -- array )
[ rgb-quads>> 4 <sliced-groups> [ 3 head-slice ] map ]
: parse-bitmap-header ( bitmap -- )
4 read le> >>header-length
- 4 read le> >>width
- 4 read le> >>height
+ 4 read signed-le> >>width
+ 4 read signed-le> >>height
2 read le> >>planes
2 read le> >>bit-count
4 read le> >>compression
[
[ height>> abs ] keep
bit-count>> {
- ! { 32 [ GL_BGRA GL_UNSIGNED_INT_8_8_8_8 ] } ! broken
+ { 32 [ GL_BGRA GL_UNSIGNED_BYTE ] }
{ 24 [ GL_BGR GL_UNSIGNED_BYTE ] }
{ 8 [ GL_BGR GL_UNSIGNED_BYTE ] }
{ 4 [ GL_BGR GL_UNSIGNED_BYTE ] }
+++ /dev/null
-Doug Coleman
+++ /dev/null
-Doug Coleman
+++ /dev/null
-USING: system ;
-IN: hardware-info.backend
-
-HOOK: cpus os ( -- n )
-HOOK: cpu-mhz os ( -- n )
-HOOK: memory-load os ( -- n )
-HOOK: physical-mem os ( -- n )
-HOOK: available-mem os ( -- n )
-HOOK: total-page-file os ( -- n )
-HOOK: available-page-file os ( -- n )
-HOOK: total-virtual-mem os ( -- n )
-HOOK: available-virtual-mem os ( -- n )
-HOOK: available-virtual-extended-mem os ( -- n )
+++ /dev/null
-USING: alien.syntax kernel math prettyprint io math.parser
-combinators vocabs.loader hardware-info.backend system ;
-IN: hardware-info
-
-: write-unit ( x n str -- )
- [ 2^ /f number>string write bl ] [ write ] bi* ;
-
-: kb ( x -- ) 10 "kB" write-unit ;
-: megs ( x -- ) 20 "MB" write-unit ;
-: gigs ( x -- ) 30 "GB" write-unit ;
-: ghz ( x -- ) 1000000000 /f number>string write bl "GHz" write ;
-
-<< {
- { [ os windows? ] [ "hardware-info.windows" ] }
- { [ os linux? ] [ "hardware-info.linux" ] }
- { [ os macosx? ] [ "hardware-info.macosx" ] }
- [ f ]
-} cond [ require ] when* >>
-
-: hardware-report. ( -- )
- "CPUs: " write cpus number>string write nl
- "CPU Speed: " write cpu-mhz ghz nl
- "Physical RAM: " write physical-mem megs nl ;
+++ /dev/null
-Doug Coleman
+++ /dev/null
-USING: unix alien alien.c-types kernel math sequences strings
-io.unix.backend splitting ;
-IN: hardware-info.linux
-
-: (uname) ( buf -- int )
- "int" f "uname" { "char*" } alien-invoke ;
-
-: uname ( -- seq )
- 65536 "char" <c-array> [ (uname) io-error ] keep
- "\0" split harvest [ >string ] map
- 6 "" pad-right ;
-
-: sysname ( -- string ) uname first ;
-: nodename ( -- string ) uname second ;
-: release ( -- string ) uname third ;
-: version ( -- string ) uname fourth ;
-: machine ( -- string ) uname 4 swap nth ;
-: domainname ( -- string ) uname 5 swap nth ;
-
-: kernel-version ( -- seq )
- release ".-" split harvest 5 "" pad-right ;
+++ /dev/null
-unportable
+++ /dev/null
-Doug Coleman
+++ /dev/null
-USING: alien alien.c-types alien.strings alien.syntax
-byte-arrays kernel namespaces sequences unix
-hardware-info.backend system io.unix.backend io.encodings.ascii
-;
-IN: hardware-info.macosx
-
-! See /usr/include/sys/sysctl.h for constants
-
-LIBRARY: libc
-FUNCTION: int sysctl ( int* name, uint namelen, void* oldp, size_t* oldlenp, void* newp, size_t newlen ) ;
-
-: make-int-array ( seq -- byte-array )
- [ <int> ] map concat ;
-
-: (sysctl-query) ( name namelen oldp oldlenp -- oldp )
- over [ f 0 sysctl io-error ] dip ;
-
-: sysctl-query ( seq n -- byte-array )
- [ [ make-int-array ] [ length ] bi ] dip
- [ <byte-array> ] [ <uint> ] bi (sysctl-query) ;
-
-: sysctl-query-string ( seq -- n )
- 4096 sysctl-query ascii malloc-string ;
-
-: sysctl-query-uint ( seq -- n )
- 4 sysctl-query *uint ;
-
-: sysctl-query-ulonglong ( seq -- n )
- 8 sysctl-query *ulonglong ;
-
-: machine ( -- str ) { 6 1 } sysctl-query-string ;
-: model ( -- str ) { 6 2 } sysctl-query-string ;
-M: macosx cpus ( -- n ) { 6 3 } sysctl-query-uint ;
-: byte-order ( -- n ) { 6 4 } sysctl-query-uint ;
-M: macosx physical-mem ( -- n ) { 6 5 } sysctl-query-uint ;
-: user-mem ( -- n ) { 6 6 } sysctl-query-uint ;
-: page-size ( -- n ) { 6 7 } sysctl-query-uint ;
-: disknames ( -- n ) { 6 8 } 8 sysctl-query ;
-: diskstats ( -- n ) { 6 9 } 8 sysctl-query ;
-: epoch ( -- n ) { 6 10 } sysctl-query-uint ;
-: floating-point ( -- n ) { 6 11 } sysctl-query-uint ;
-: machine-arch ( -- n ) { 6 12 } sysctl-query-string ;
-: vector-unit ( -- n ) { 6 13 } sysctl-query-uint ;
-: bus-frequency ( -- n ) { 6 14 } sysctl-query-uint ;
-M: macosx cpu-mhz ( -- n ) { 6 15 } sysctl-query-uint ;
-: cacheline-size ( -- n ) { 6 16 } sysctl-query-uint ;
-: l1-icache-size ( -- n ) { 6 17 } sysctl-query-uint ;
-: l1-dcache-size ( -- n ) { 6 18 } sysctl-query-uint ;
-: l2-cache-settings ( -- n ) { 6 19 } sysctl-query-uint ;
-: l2-cache-size ( -- n ) { 6 20 } sysctl-query-uint ;
-: l3-cache-settings ( -- n ) { 6 21 } sysctl-query-uint ;
-: l3-cache-size ( -- n ) { 6 22 } sysctl-query-uint ;
-: tb-frequency ( -- n ) { 6 23 } sysctl-query-uint ;
-: mem-size ( -- n ) { 6 24 } sysctl-query-ulonglong ;
-: available-cpus ( -- n ) { 6 25 } sysctl-query-uint ;
-
+++ /dev/null
-unportable
+++ /dev/null
-Query the operating system for hardware information in a platform-independent way
+++ /dev/null
-Doug Coleman
+++ /dev/null
-Doug Coleman
+++ /dev/null
-USING: alien.c-types hardware-info kernel math namespaces
-windows windows.kernel32 hardware-info.backend system ;
-IN: hardware-info.windows.ce
-
-: memory-status ( -- MEMORYSTATUS )
- "MEMORYSTATUS" <c-object>
- "MEMORYSTATUS" heap-size over set-MEMORYSTATUS-dwLength
- [ GlobalMemoryStatus ] keep ;
-
-M: wince cpus ( -- n ) 1 ;
-
-M: wince memory-load ( -- n )
- memory-status MEMORYSTATUS-dwMemoryLoad ;
-
-M: wince physical-mem ( -- n )
- memory-status MEMORYSTATUS-dwTotalPhys ;
-
-M: wince available-mem ( -- n )
- memory-status MEMORYSTATUS-dwAvailPhys ;
-
-M: wince total-page-file ( -- n )
- memory-status MEMORYSTATUS-dwTotalPageFile ;
-
-M: wince available-page-file ( -- n )
- memory-status MEMORYSTATUS-dwAvailPageFile ;
-
-M: wince total-virtual-mem ( -- n )
- memory-status MEMORYSTATUS-dwTotalVirtual ;
-
-M: wince available-virtual-mem ( -- n )
- memory-status MEMORYSTATUS-dwAvailVirtual ;
+++ /dev/null
-unportable
+++ /dev/null
-Doug Coleman
+++ /dev/null
-USING: alien alien.c-types alien.strings
-kernel libc math namespaces hardware-info.backend
-windows windows.advapi32 windows.kernel32 system ;
-IN: hardware-info.windows.nt
-
-: system-info ( -- SYSTEM_INFO )
- "SYSTEM_INFO" <c-object> [ GetSystemInfo ] keep ;
-
-M: winnt cpus ( -- n )
- system-info SYSTEM_INFO-dwNumberOfProcessors ;
-
-: memory-status ( -- MEMORYSTATUSEX )
- "MEMORYSTATUSEX" <c-object>
- "MEMORYSTATUSEX" heap-size over set-MEMORYSTATUSEX-dwLength
- [ GlobalMemoryStatusEx ] keep swap zero? [ win32-error ] when ;
-
-M: winnt memory-load ( -- n )
- memory-status MEMORYSTATUSEX-dwMemoryLoad ;
-
-M: winnt physical-mem ( -- n )
- memory-status MEMORYSTATUSEX-ullTotalPhys ;
-
-M: winnt available-mem ( -- n )
- memory-status MEMORYSTATUSEX-ullAvailPhys ;
-
-M: winnt total-page-file ( -- n )
- memory-status MEMORYSTATUSEX-ullTotalPageFile ;
-
-M: winnt available-page-file ( -- n )
- memory-status MEMORYSTATUSEX-ullAvailPageFile ;
-
-M: winnt total-virtual-mem ( -- n )
- memory-status MEMORYSTATUSEX-ullTotalVirtual ;
-
-M: winnt available-virtual-mem ( -- n )
- memory-status MEMORYSTATUSEX-ullAvailVirtual ;
-
-: pull-win32-string ( alien -- string )
- [ utf16n alien>string ] keep free ;
-
-: computer-name ( -- string )
- MAX_COMPUTERNAME_LENGTH 1+ [ malloc ] keep
- <int> dupd GetComputerName zero? [
- free win32-error f
- ] [
- pull-win32-string
- ] if ;
-
-: username ( -- string )
- UNLEN 1+ [ malloc ] keep
- <int> dupd GetUserName zero? [
- free win32-error f
- ] [
- pull-win32-string
- ] if ;
+++ /dev/null
-unportable
+++ /dev/null
-unportable
+++ /dev/null
-USING: alien alien.c-types kernel libc math namespaces
-windows windows.kernel32 windows.advapi32
-words combinators vocabs.loader hardware-info.backend
-system alien.strings ;
-IN: hardware-info.windows
-
-: system-info ( -- SYSTEM_INFO )
- "SYSTEM_INFO" <c-object> [ GetSystemInfo ] keep ;
-
-: page-size ( -- n )
- system-info SYSTEM_INFO-dwPageSize ;
-
-! 386, 486, 586, 2200 (IA64), 8664 (AMD_X8664)
-: processor-type ( -- n )
- system-info SYSTEM_INFO-dwProcessorType ;
-
-! 0 = x86, 6 = Intel Itanium, 9 = x64 (AMD or Intel), 10 = WOW64, 0xffff = Unk
-: processor-architecture ( -- n )
- system-info SYSTEM_INFO-dwOemId HEX: ffff0000 bitand ;
-
-: os-version
- "OSVERSIONINFO" <c-object>
- "OSVERSIONINFO" heap-size over set-OSVERSIONINFO-dwOSVersionInfoSize
- [ GetVersionEx ] keep swap zero? [ win32-error ] when ;
-
-: windows-major ( -- n )
- os-version OSVERSIONINFO-dwMajorVersion ;
-
-: windows-minor ( -- n )
- os-version OSVERSIONINFO-dwMinorVersion ;
-
-: windows-build# ( -- n )
- os-version OSVERSIONINFO-dwBuildNumber ;
-
-: windows-platform-id ( -- n )
- os-version OSVERSIONINFO-dwPlatformId ;
-
-: windows-service-pack ( -- string )
- os-version OSVERSIONINFO-szCSDVersion utf16n alien>string ;
-
-: feature-present? ( n -- ? )
- IsProcessorFeaturePresent zero? not ;
-
-: sse2? ( -- ? )
- PF_XMMI64_INSTRUCTIONS_AVAILABLE feature-present? ;
-
-: sse3? ( -- ? )
- PF_SSE3_INSTRUCTIONS_AVAILABLE feature-present? ;
-
-: <u16-string-object> ( n -- obj )
- "ushort" <c-array> ;
-
-: get-directory ( word -- str )
- >r MAX_UNICODE_PATH [ <u16-string-object> ] keep dupd r>
- execute win32-error=0/f utf16n alien>string ; inline
-
-: windows-directory ( -- str )
- \ GetWindowsDirectory get-directory ;
-
-: system-directory ( -- str )
- \ GetSystemDirectory get-directory ;
-
-: system-windows-directory ( -- str )
- \ GetSystemWindowsDirectory get-directory ;
-
-<<
-{
- { [ os wince? ] [ "hardware-info.windows.ce" ] }
- { [ os winnt? ] [ "hardware-info.windows.nt" ] }
-} cond [ require ] when* >>
USING: tools.deploy.config ;
H{
- { deploy-c-types? f }
{ deploy-name "Hello world (console)" }
- { deploy-threads? f }
+ { deploy-c-types? f }
{ deploy-word-props? f }
- { deploy-reflection 2 }
- { deploy-io 2 }
- { deploy-math? f }
{ deploy-ui? f }
+ { deploy-reflection 1 }
{ deploy-compiler? f }
- { "stop-after-last-window?" t }
+ { deploy-unicode? f }
+ { deploy-io 2 }
{ deploy-word-defs? f }
+ { deploy-threads? f }
+ { "stop-after-last-window?" t }
+ { deploy-math? f }
}
swap >>name ;
: make-tag ( string attribs -- tag )
- >r [ closing-tag? ] keep "/" trim1 r> rot <tag> ;
+ [ [ closing-tag? ] keep "/" trim1 ] dip rot <tag> ;
: make-text-tag ( string -- tag )
tag new
[ ?head drop ] [ ?tail drop ] bi ;
: single-quote ( str -- newstr )
- "'" swap "'" 3append ;
+ "'" dup surround ;
: double-quote ( str -- newstr )
- "\"" swap "\"" 3append ;
+ "\"" dup surround ;
: quote ( str -- newstr )
CHAR: ' over member?
continuations debugger classes.tuple namespaces make vectors
bit-arrays byte-arrays strings sbufs math.functions macros
sequences.private combinators mirrors
-combinators.short-circuit ;
+combinators.short-circuit fry qualified ;
+RENAME: _ fry => __
IN: inverse
-TUPLE: fail ;
-: fail ( -- * ) \ fail new throw ;
+ERROR: fail ;
M: fail summary drop "Unification failed" ;
: assure ( ? -- ) [ fail ] unless ;
-: =/fail ( obj1 obj2 -- )
- = assure ;
+: =/fail ( obj1 obj2 -- ) = assure ;
! Inverse of a quotation
pick 1quotation 3array "math-inverse" set-word-prop ;
: define-pop-inverse ( word n quot -- )
- >r dupd "pop-length" set-word-prop r>
+ [ dupd "pop-length" set-word-prop ] dip
"pop-inverse" set-word-prop ;
-TUPLE: no-inverse word ;
-: no-inverse ( word -- * ) \ no-inverse new throw ;
+ERROR: no-inverse word ;
M: no-inverse summary
drop "The word cannot be used in pattern matching" ;
+ERROR: bad-math-inverse ;
+
: next ( revquot -- revquot* first )
- [ "Badly formed math inverse" throw ]
+ [ bad-math-inverse ]
[ unclip-slice ] if-empty ;
: constant-word? ( word -- ? )
stack-effect
- [ out>> length 1 = ] keep
- in>> length 0 = and ;
+ [ out>> length 1 = ]
+ [ in>> empty? ] bi and ;
: assure-constant ( constant -- quot )
- dup word? [ "Badly formed math inverse" throw ] when 1quotation ;
+ dup word? [ bad-math-inverse ] when 1quotation ;
: swap-inverse ( math-inverse revquot -- revquot* quot )
- next assure-constant rot second [ swap ] swap 3compose ;
+ next assure-constant rot second '[ @ swap @ ] ;
: pull-inverse ( math-inverse revquot const -- revquot* quot )
assure-constant rot first compose ;
: ?word-prop ( word/object name -- value/f )
over word? [ word-prop ] [ 2drop f ] if ;
-: undo-literal ( object -- quot )
- [ =/fail ] curry ;
+: undo-literal ( object -- quot ) [ =/fail ] curry ;
PREDICATE: normal-inverse < word "inverse" word-prop ;
PREDICATE: math-inverse < word "math-inverse" word-prop ;
: enough? ( stack word -- ? )
dup deferred? [ 2drop f ] [
- [ >r length r> 1quotation infer in>> >= ]
+ [ [ length ] dip 1quotation infer in>> >= ]
[ 3drop f ] recover
] if ;
: fold-word ( stack word -- stack )
2dup enough?
- [ 1quotation with-datastack ] [ >r % r> , { } ] if ;
+ [ 1quotation with-datastack ] [ [ % ] dip , { } ] if ;
: fold ( quot -- folded-quot )
[ { } swap [ fold-word ] each % ] [ ] make ;
throw
] recover ;
+ERROR: undefined-inverse ;
+
GENERIC: inverse ( revquot word -- revquot* quot )
M: object inverse undo-literal ;
M: symbol inverse undo-literal ;
-M: word inverse drop "Inverse is undefined" throw ;
+M: word inverse undefined-inverse ;
M: normal-inverse inverse
"inverse" word-prop ;
[ drop swap-inverse ] [ pull-inverse ] if ;
M: pop-inverse inverse
- [ "pop-length" word-prop cut-slice swap >quotation ] keep
- "pop-inverse" word-prop compose call ;
+ [ "pop-length" word-prop cut-slice swap >quotation ]
+ [ "pop-inverse" word-prop ] bi compose call ;
: (undo) ( revquot -- )
[ unclip-slice inverse % (undo) ] unless-empty ;
\ dup [ [ =/fail ] keep ] define-inverse
\ 2dup [ over =/fail over =/fail ] define-inverse
\ 3dup [ pick =/fail pick =/fail pick =/fail ] define-inverse
-\ pick [ >r pick r> =/fail ] define-inverse
+\ pick [ [ pick ] dip =/fail ] define-inverse
\ tuck [ swapd [ =/fail ] keep ] define-inverse
\ not [ not ] define-inverse
\ sq [ sqrt ] define-inverse
\ sqrt [ sq ] define-inverse
+ERROR: missing-literal ;
+
: assert-literal ( n -- n )
- dup [ word? ] keep symbol? not and
- [ "Literal missing in pattern matching" throw ] when ;
+ dup
+ [ word? ] [ symbol? not ] bi and
+ [ missing-literal ] when ;
\ + [ - ] [ - ] define-math-inverse
\ - [ + ] [ - ] define-math-inverse
\ * [ / ] [ / ] define-math-inverse
\ ? 2 [
[ assert-literal ] bi@
- [ swap >r over = r> swap [ 2drop f ] [ = [ t ] [ fail ] if ] if ]
+ [ swap [ over = ] dip swap [ 2drop f ] [ = [ t ] [ fail ] if ] if ]
2curry
] define-pop-inverse
dup wrapper? [ wrapped>> ] when ;
: boa-inverse ( class -- quot )
- [ deconstruct-pred ] keep slot-readers compose ;
+ [ deconstruct-pred ] [ slot-readers ] bi compose ;
\ boa 1 [ ?wrapped boa-inverse ] define-pop-inverse
: recover-fail ( try fail -- )
[ drop call ] [
- >r nip r> dup fail?
+ [ nip ] dip dup fail?
[ drop call ] [ nip throw ] if
] recover ; inline
: true-out ( quot effect -- quot' )
- out>> [ ndrop ] curry
- [ t ] 3compose ;
+ out>> '[ @ __ ndrop t ] ;
: false-recover ( effect -- quot )
in>> [ ndrop f ] curry [ recover-fail ] curry ;
: [matches?] ( quot -- undoes?-quot )
- [undo] dup infer [ true-out ] keep false-recover curry ;
+ [undo] dup infer [ true-out ] [ false-recover ] bi curry ;
MACRO: matches? ( quot -- ? ) [matches?] ;
-TUPLE: no-match ;
-: no-match ( -- * ) \ no-match new throw ;
+ERROR: no-match ;
M: no-match summary drop "Fall through in switch" ;
: recover-chain ( seq -- quot )
: [switch] ( quot-alist -- quot )
[ dup quotation? [ [ ] swap 2array ] when ] map
- reverse [ >r [undo] r> compose ] { } assoc>map
+ reverse [ [ [undo] ] dip compose ] { } assoc>map
recover-chain ;
MACRO: switch ( quot-alist -- ) [switch] ;
+++ /dev/null
-USING: io.backend ;
-IN: io.files.unique.backend
-
-HOOK: (make-unique-file) io-backend ( path -- )
-HOOK: temporary-path io-backend ( -- path )
+++ /dev/null
-USING: help.markup help.syntax io io.ports kernel math
-io.files.unique.private math.parser io.files ;
-IN: io.files.unique
-
-ARTICLE: "unique" "Making and using unique files"
-"Files:"
-{ $subsection make-unique-file }
-{ $subsection with-unique-file }
-"Directories:"
-{ $subsection make-unique-directory }
-{ $subsection with-unique-directory } ;
-
-ABOUT: "unique"
-
-HELP: make-unique-file ( prefix suffix -- path )
-{ $values { "prefix" "a string" } { "suffix" "a string" }
-{ "path" "a pathname string" } }
-{ $description "Creates a file that is guaranteed not to exist in a platform-specific temporary directory. The file name is composed of a prefix, a number of random digits and letters, and the suffix. Returns the full pathname." }
-{ $errors "Throws an error if a new unique file cannot be created after a number of tries. Since each try generates a new random name, the most likely error is incorrect directory permissions on the temporary directory." }
-{ $see-also with-unique-file } ;
-
-HELP: make-unique-directory ( -- path )
-{ $values { "path" "a pathname string" } }
-{ $description "Creates a directory that is guaranteed not to exist in a platform-specific temporary directory and returns the full pathname." }
-{ $errors "Throws an error if the directory cannot be created after a number of tries. Since each try generates a new random name, the most likely error is incorrect directory permissions on the temporary directory." }
-{ $see-also with-unique-directory } ;
-
-HELP: with-unique-file ( prefix suffix quot -- )
-{ $values { "prefix" "a string" } { "suffix" "a string" }
-{ "quot" "a quotation" } }
-{ $description "Creates a file with " { $link make-unique-file } " and calls the quotation with the path name on the stack." }
-{ $notes "The unique file will be deleted after calling this word." } ;
-
-HELP: with-unique-directory ( quot -- )
-{ $values { "quot" "a quotation" } }
-{ $description "Creates a directory with " { $link make-unique-directory } " and calls the quotation with the pathname on the stack." }
-{ $notes "The directory will be deleted after calling this word." } ;
+++ /dev/null
-USING: io.encodings.ascii sequences strings io io.files accessors
-tools.test kernel io.files.unique ;
-IN: io.files.unique.tests
-
-[ 123 ] [
- "core" ".test" [
- [
- ascii [
- 123 CHAR: a <repetition> >string write
- ] with-file-writer
- ] keep file-info size>>
- ] with-unique-file
-] unit-test
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel math math.bitwise combinators.lib math.parser
-random sequences sequences.lib continuations namespaces
-io.files io arrays io.files.unique.backend system
-combinators vocabs.loader ;
-IN: io.files.unique
-
-<PRIVATE
-: random-letter ( -- ch )
- 26 random { CHAR: a CHAR: A } random + ;
-
-: random-ch ( -- ch )
- { t f } random
- [ 10 random CHAR: 0 + ] [ random-letter ] if ;
-
-: random-name ( n -- string )
- [ random-ch ] "" replicate-as ;
-
-: unique-length ( -- n ) 10 ; inline
-: unique-retries ( -- n ) 10 ; inline
-PRIVATE>
-
-: make-unique-file ( prefix suffix -- path )
- temporary-path -rot
- [
- unique-length random-name swap 3append append-path
- dup (make-unique-file)
- ] 3curry unique-retries retry ;
-
-: with-unique-file ( prefix suffix quot -- )
- >r make-unique-file r> keep delete-file ; inline
-
-: make-unique-directory ( -- path )
- [
- temporary-path unique-length random-name append-path
- dup make-directory
- ] unique-retries retry ;
-
-: with-unique-directory ( quot -- )
- >r make-unique-directory r>
- [ with-directory ] curry keep delete-tree ; inline
-
-{
- { [ os unix? ] [ "io.unix.files.unique" ] }
- { [ os windows? ] [ "io.windows.files.unique" ] }
-} cond require
+++ /dev/null
-Doug Coleman
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: io.files kernel sequences accessors
-dlists deques arrays ;
-IN: io.paths
-
-TUPLE: directory-iterator path bfs queue ;
-
-: qualified-directory ( path -- seq )
- dup directory-files [ append-path ] with map ;
-
-: push-directory ( path iter -- )
- [ qualified-directory ] dip [
- dup queue>> swap bfs>>
- [ push-front ] [ push-back ] if
- ] curry each ;
-
-: <directory-iterator> ( path bfs? -- iterator )
- <dlist> directory-iterator boa
- dup path>> over push-directory ;
-
-: next-file ( iter -- file/f )
- dup queue>> deque-empty? [ drop f ] [
- dup queue>> pop-back dup link-info directory?
- [ over push-directory next-file ] [ nip ] if
- ] if ;
-
-: iterate-directory ( iter quot -- obj )
- over next-file [
- over call
- [ 2drop ] [ iterate-directory ] if
- ] [
- 2drop f
- ] if* ; inline recursive
-
-: find-file ( path bfs? quot -- path/f )
- [ <directory-iterator> ] dip
- [ keep and ] curry iterate-directory ; inline
-
-: each-file ( path bfs? quot -- )
- [ <directory-iterator> ] dip
- [ f ] compose iterate-directory drop ; inline
-
-: find-all-files ( path bfs? quot -- paths )
- [ <directory-iterator> ] dip
- pusher [ [ f ] compose iterate-directory drop ] dip ; inline
-
-: recursive-directory ( path bfs? -- paths )
- [ ] accumulator [ each-file ] dip ;
M: mb-writer stream-nl ( mb-writer -- )
[ [ last-line>> concat ] [ lines>> ] bi push ] keep
V{ } clone >>last-line drop ;
-M: mb-reader dispose drop ;
+M: mb-reader dispose f swap push-line ;
M: mb-writer dispose drop ;
: spawn-client ( -- irc-client )
[ in-messages>> 0.1 seconds ] dip mailbox-get-timeout? ;
: with-irc ( quot: ( -- ) -- )
- [ spawn-client ] dip [ f %push-line ] compose with-irc-client ; inline
+ [ spawn-client ] dip [ irc> terminate-irc ] compose with-irc-client ; inline
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! TESTS
! Test login and nickname set
[ { "factorbot2" } [
- ":some.where 001 factorbot2 :Welcome factorbot2" %push-line
- irc> nick>>
+ ":some.where 001 factorbot2 :Welcome factorbot2" %push-line
+ irc> nick>>
] unit-test
] with-irc
! Test connect
{ V{ "NICK factorbot" "USER factorbot hostname servername :irc.factor" } } [
- "someserver" irc-port "factorbot" f <irc-profile> <irc-client>
+ "someserver" irc-port "factorbot" f <irc-profile> <irc-client>
[ 2drop <test-stream> t ] >>connect
- [ connect-irc ] keep
- stream>> [ in>> [ f ] dip push-line ] [ out>> lines>> ] bi
+ [ connect-irc ] [ stream>> out>> lines>> ] [ terminate-irc ] tri
] unit-test
! Test join
] unit-test
] with-irc
+[ { H{ { "factorbot" +operator+ } { "ircuser" +normal+ } } } [
+ "#factortest" <irc-channel-chat>
+ H{ { "ircuser" +normal+ } } clone >>participants
+ [ %add-named-chat ] keep
+ ":ircserver.net 353 factorbot @ #factortest :@factorbot " %push-line
+ ":ircserver.net 353 factorbot @ #factortest :ircuser2 " %push-line
+ ":ircserver.net 366 factorbot #factortest :End of /NAMES list." %push-line
+ ":ircserver.net 353 factorbot @ #factortest :@factorbot " %push-line
+ ":ircserver.net 353 factorbot @ #factortest :ircuser " %push-line
+ ":ircserver.net 366 factorbot #factortest :End of /NAMES list." %push-line
+ participants>>
+ ] unit-test
+] with-irc
+
! Namelist change notification
[ { T{ participant-changed f f f f } } [
"#factortest" <irc-channel-chat> [ %add-named-chat ] keep
[ participant-changed? ] read-matching-message
] unit-test
] with-irc
+
+! Mode change
+[ { T{ participant-changed f "ircuser" +mode+ "+o" } } [
+ "#factortest" <irc-channel-chat> [ %add-named-chat ] keep
+ ":ircserver.net MODE #factortest +o ircuser" %push-line
+ [ participant-changed? ] read-matching-message
+ ] unit-test
+] with-irc
TUPLE: irc-chat in-messages client ;
TUPLE: irc-server-chat < irc-chat ;
-TUPLE: irc-channel-chat < irc-chat name password timeout participants ;
+TUPLE: irc-channel-chat < irc-chat name password timeout participants clean-participants ;
TUPLE: irc-nick-chat < irc-chat name ;
SYMBOL: +server-chat+
<mailbox> f irc-server-chat boa ;
: <irc-channel-chat> ( name -- irc-channel-chat )
- [ <mailbox> f ] dip f 60 seconds H{ } clone
+ [ <mailbox> f ] dip f 60 seconds H{ } clone t
irc-channel-chat boa ;
: <irc-nick-chat> ( name -- irc-nick-chat )
: change-participant-mode ( channel mode nick -- )
rot chat>
[ participants>> set-at ]
- [ [ [ +mode+ ] dip <participant-changed> ] dip to-chat ] 3bi ; ! FIXME
+ [ [ participant-changed new
+ [ (>>nick) ] [ (>>parameter) ] [ +mode+ >>action ] tri ] dip to-chat ]
+ 3bi ; ! FIXME
DEFER: me?
GENERIC: process-message ( irc-message -- )
M: object process-message drop ;
M: logged-in process-message
- name>> f irc> [ (>>is-ready) ] [ (>>nick) ] [ chats>> ] tri
+ name>> t irc> [ (>>is-ready) ] [ (>>nick) ] [ chats>> ] tri
values [ initialize-chat ] each ;
M: ping process-message trailing>> /PONG ;
M: nick-in-use process-message name>> "_" append /NICK ;
M: nick process-message
[ irc-message-sender ] [ trailing>> ] bi rename-participant-in-all ;
-! M: mode process-message ( mode -- )
-! [ channel-mode? ] keep and [
-! [ name>> ] [ mode>> ] [ parameter>> ] tri
-! [ change-participant-mode ] [ 2drop ] if*
-! ] when* ;
+M: mode process-message ( mode -- )
+ [ channel-mode? ] keep and [
+ [ name>> ] [ mode>> ] [ parameter>> ] tri
+ [ change-participant-mode ] [ 2drop ] if*
+ ] when* ;
: >nick/mode ( string -- nick mode )
dup first "+@" member? [ unclip ] [ 0 ] if participant-mode ;
trailing>> [ blank? ] trim " " split
[ >nick/mode 2array ] map >hashtable ;
+: maybe-clean-participants ( channel-chat -- )
+ dup clean-participants>> [
+ H{ } clone >>participants f >>clean-participants
+ ] when drop ;
+
M: names-reply process-message
[ names-reply>participants ] [ channel>> chat> ] bi [
- [ (>>participants) ]
- [ [ f f f <participant-changed> ] dip name>> to-chat ] bi
+ [ maybe-clean-participants ]
+ [ participants>> 2array assoc-combine ]
+ [ (>>participants) ] tri
] [ drop ] if* ;
+M: end-of-names process-message
+ channel>> chat> [
+ t >>clean-participants
+ [ f f f <participant-changed> ] dip name>> to-chat
+ ] when* ;
+
! ======================================
! Client message handling
! ======================================
|dispose stream-readln [
parse-irc-line handle-reader-message t
] [
- irc> terminate-irc f
+ handle-disconnect
] if*
] with-destructors ;
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: fry irc.client irc.client.private kernel namespaces
+sequences threads io.encodings.8-bit io.launcher io splitting
+make mason.common mason.updates calendar math alarms ;
+IN: irc.gitbot
+
+: bot-profile ( -- obj )
+ "irc.freenode.org" 6667 "jackass" f <irc-profile> ;
+
+: bot-channel ( -- seq ) "#concatenative" ;
+
+GENERIC: handle-message ( msg -- )
+
+M: object handle-message drop ;
+
+: bot-loop ( chat -- )
+ dup hear handle-message bot-loop ;
+
+: start-bot ( -- chat )
+ bot-profile <irc-client>
+ [ connect-irc ]
+ [
+ [ bot-channel <irc-channel-chat> dup ] dip
+ '[ _ [ _ attach-chat ] [ bot-loop ] bi ]
+ "GitBot" spawn drop
+ ] bi ;
+
+: git-log ( from to -- lines )
+ [
+ "git-log" ,
+ "--no-merges" ,
+ "--pretty=format:%h %an: %s" ,
+ ".." glue ,
+ ] { } make
+ latin1 [ input-stream get lines ] with-process-reader ;
+
+: updates ( from to -- lines )
+ git-log reverse
+ dup length 4 > [ 4 head "... and more" suffix ] when ;
+
+: report-updates ( from to chat -- )
+ [ updates ] dip
+ [ 1 seconds sleep ] swap
+ '[ _ speak ] interleave ;
+
+: check-for-updates ( chat -- )
+ [ git-id git-pull-cmd short-running-process git-id ] dip
+ report-updates ;
+
+: bot ( -- )
+ start-bot
+ '[ _ check-for-updates ] 5 minutes every drop ;
+
+MAIN: bot
TUPLE: notice < irc-message type ;
TUPLE: mode < irc-message name mode parameter ;
TUPLE: names-reply < irc-message who channel ;
+TUPLE: end-of-names < irc-message who channel ;
TUPLE: unhandled < irc-message ;
: <irc-client-message> ( command parameters trailing -- irc-message )
M: names-reply >>command-parameters ( names-reply params -- names-reply )
first3 nip [ >>who ] [ >>channel ] bi* ;
+M: end-of-names >>command-parameters ( names-reply params -- names-reply )
+ first2 [ >>who ] [ >>channel ] bi* ;
+
M: mode >>command-parameters ( mode params -- mode )
- dup length 3 = [
- first3 [ >>name ] [ >>mode ] [ >>parameter ] tri*
- ] [
- first2 [ >>name ] [ >>mode ] bi*
- ] if ;
+ dup length {
+ { 3 [ first3 [ >>name ] [ >>mode ] [ >>parameter ] tri* ] }
+ { 2 [ first2 [ >>name ] [ >>mode ] bi* ] }
+ [ drop first >>name dup trailing>> >>mode ]
+ } case ;
PRIVATE>
: copy-message-in ( command irc-message -- command )
{
- [ parameters>> [ >>parameters ] [ >>command-parameters ] bi ]
[ line>> >>line ]
[ prefix>> >>prefix ]
[ command>> >>command ]
[ trailing>> >>trailing ]
[ timestamp>> >>timestamp ]
+ [ parameters>> [ >>parameters ] [ >>command-parameters ] bi ]
} cleave ;
PRIVATE>
{ "001" [ logged-in ] }
{ "433" [ nick-in-use ] }
{ "353" [ names-reply ] }
+ { "366" [ end-of-names ] }
{ "JOIN" [ join ] }
{ "PART" [ part ] }
{ "NICK" [ nick ] }
\r
IN: irc.ui.commandparser\r
\r
-"irc.ui.commands" require\r
-\r
: command ( string string -- string command )\r
[ "say" ] when-empty\r
dup "irc.ui.commands" lookup\r
! Copyright (C) 2008 William Schlieper\r
! See http://factorcode.org/license.txt for BSD license.\r
\r
-USING: accessors kernel arrays irc.client irc.messages irc.ui namespaces ;\r
+USING: accessors kernel sequences arrays irc.client\r
+ irc.messages irc.ui namespaces ;\r
\r
IN: irc.ui.commands\r
\r
[ window>> client>> profile>> nickname>> <own-message> print-irc ]\r
[ chat>> speak ] 2bi ;\r
\r
+: me ( string -- ) ! Placeholder until I make /me look different\r
+ "ACTION " 1 prefix prepend 1 suffix say ;\r
+\r
: join ( string -- )\r
irc-tab get window>> join-channel ;\r
\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\r
- irc.ui.commandparser irc.ui.load ;\r
+ irc.ui.commandparser irc.ui.load vocabs.loader classes prettyprint ;\r
\r
RENAME: join sequences => sjoin\r
\r
foreground associate format ;\r
: dark-red T{ rgba f 0.5 0.0 0.0 1 } ;\r
: dark-green T{ rgba f 0.0 0.5 0.0 1 } ;\r
+: dark-blue T{ rgba f 0.0 0.0 0.5 1 } ;\r
\r
: dot-or-parens ( string -- string )\r
[ "." ]\r
drop "* Ping" blue write-color ;\r
\r
M: privmsg write-irc\r
- "<" blue write-color\r
+ "<" dark-blue write-color\r
[ irc-message-sender write ] keep\r
- "> " blue write-color\r
+ "> " dark-blue write-color\r
trailing>> write ;\r
\r
M: notice write-irc\r
- [ type>> blue write-color ] keep\r
- ": " blue write-color\r
+ [ type>> dark-blue write-color ] keep\r
+ ": " dark-blue write-color\r
trailing>> write ;\r
\r
TUPLE: own-message message nick timestamp ;\r
now own-message boa ;\r
\r
M: own-message write-irc\r
- "<" blue write-color\r
+ "<" dark-blue write-color\r
[ nick>> bold font-style associate format ] keep\r
- "> " blue write-color\r
+ "> " dark-blue write-color\r
message>> write ;\r
\r
M: join write-irc\r
" from the channel" dark-red write-color\r
trailing>> dot-or-parens dark-red write-color ;\r
\r
-: full-mode ( message -- mode )\r
- parameters>> rest " " sjoin ;\r
-\r
M: mode write-irc\r
- "* " blue write-color\r
- [ irc-message-sender write ] keep\r
- " has applied mode " blue write-color\r
- [ full-mode write ] keep\r
- " to " blue write-color\r
- channel>> write ;\r
+ "* " dark-blue write-color\r
+ [ name>> write ] keep\r
+ " has applied mode " dark-blue write-color\r
+ [ mode>> write ] keep\r
+ " to " dark-blue write-color\r
+ parameter>> write ;\r
\r
M: nick write-irc\r
- "* " blue write-color\r
+ "* " dark-blue write-color\r
[ irc-message-sender write ] keep\r
" is now known as " blue write-color\r
trailing>> write ;\r
\r
M: unhandled write-irc\r
"UNHANDLED: " write\r
- line>> blue write-color ;\r
+ line>> dark-blue write-color ;\r
\r
M: irc-end write-irc\r
drop "* You have left IRC" dark-red write-color ;\r
drop ;\r
\r
M: irc-message write-irc\r
- drop ; ! catch all unimplemented writes, THIS WILL CHANGE \r
+ "UNIMPLEMENTED" write\r
+ [ class pprint ] keep\r
+ ": " write\r
+ line>> dark-blue write-color ;\r
\r
GENERIC: time-happened ( message -- timestamp )\r
\r
: main-run ( -- ) run-ircui ;\r
\r
MAIN: main-run\r
+\r
+"irc.ui.commands" require\r
+++ /dev/null
-Alex Chapman
+++ /dev/null
-USING: tools.deploy.config ;
-V{
- { deploy-ui? t }
- { deploy-io 1 }
- { deploy-reflection 1 }
- { deploy-compiler? t }
- { deploy-math? t }
- { deploy-word-props? f }
- { deploy-c-types? f }
- { "stop-after-last-window?" t }
- { deploy-name "Jamshred" }
-}
+++ /dev/null
-Alex Chapman
+++ /dev/null
-! Copyright (C) 2007, 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel opengl arrays sequences jamshred.log jamshred.player jamshred.sound jamshred.tunnel math math.constants math.vectors ;
-IN: jamshred.game
-
-TUPLE: jamshred sounds tunnel players running quit ;
-
-: <jamshred> ( -- jamshred )
- <sounds> <random-tunnel> "Player 1" pick <player>
- 2dup swap play-in-tunnel 1array f f jamshred boa ;
-
-: jamshred-player ( jamshred -- player )
- ! TODO: support more than one player
- players>> first ;
-
-: jamshred-update ( jamshred -- )
- dup running>> [
- jamshred-player update-player
- ] [ drop ] if ;
-
-: toggle-running ( jamshred -- )
- dup running>> [
- f >>running drop
- ] [
- [ jamshred-player moved ]
- [ t >>running drop ] bi
- ] if ;
-
-: mouse-moved ( x-radians y-radians jamshred -- )
- jamshred-player -rot turn-player ;
-
-: units-per-full-roll ( -- n ) 50 ;
-
-: jamshred-roll ( jamshred n -- )
- [ jamshred-player ] dip 2 pi * * units-per-full-roll / roll-player ;
-
-: mouse-scroll-x ( jamshred x -- ) jamshred-roll ;
-
-: mouse-scroll-y ( jamshred y -- )
- neg swap jamshred-player change-player-speed ;
+++ /dev/null
-Alex Chapman
+++ /dev/null
-! Copyright (C) 2007, 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors alien.c-types jamshred.game jamshred.oint
-jamshred.player jamshred.tunnel kernel math math.constants
-math.functions math.vectors opengl opengl.gl opengl.glu
-opengl.demo-support sequences float-arrays ;
-IN: jamshred.gl
-
-: min-vertices 6 ; inline
-: max-vertices 32 ; inline
-
-: n-vertices ( -- n ) 32 ; inline
-
-! render enough of the tunnel that it looks continuous
-: n-segments-ahead ( -- n ) 60 ; inline
-: n-segments-behind ( -- n ) 40 ; inline
-
-: wall-drawing-offset ( -- n )
- #! so that we can't see through the wall, we draw it a bit further away
- 0.15 ;
-
-: wall-drawing-radius ( segment -- r )
- radius>> wall-drawing-offset + ;
-
-: wall-up ( segment -- v )
- [ wall-drawing-radius ] [ up>> ] bi n*v ;
-
-: wall-left ( segment -- v )
- [ wall-drawing-radius ] [ left>> ] bi n*v ;
-
-: segment-vertex ( theta segment -- vertex )
- [
- [ wall-up swap sin v*n ] [ wall-left swap cos v*n ] 2bi v+
- ] [
- location>> v+
- ] bi ;
-
-: segment-vertex-normal ( vertex segment -- normal )
- location>> swap v- normalize ;
-
-: segment-vertex-and-normal ( segment theta -- vertex normal )
- swap [ segment-vertex ] keep dupd segment-vertex-normal ;
-
-: equally-spaced-radians ( n -- seq )
- #! return a sequence of n numbers between 0 and 2pi
- dup [ / pi 2 * * ] curry map ;
-
-: draw-segment-vertex ( segment theta -- )
- over color>> gl-color segment-vertex-and-normal
- gl-normal gl-vertex ;
-
-: draw-vertex-pair ( theta next-segment segment -- )
- rot tuck draw-segment-vertex draw-segment-vertex ;
-
-: draw-segment ( next-segment segment -- )
- GL_QUAD_STRIP [
- [ draw-vertex-pair ] 2curry
- n-vertices equally-spaced-radians F{ 0.0 } append swap each
- ] do-state ;
-
-: draw-segments ( segments -- )
- 1 over length pick subseq swap [ draw-segment ] 2each ;
-
-: segments-to-render ( player -- segments )
- dup nearest-segment>> number>> dup n-segments-behind -
- swap n-segments-ahead + rot tunnel>> sub-tunnel ;
-
-: draw-tunnel ( player -- )
- segments-to-render draw-segments ;
-
-: init-graphics ( width height -- )
- GL_DEPTH_TEST glEnable
- GL_SCISSOR_TEST glDisable
- 1.0 glClearDepth
- 0.0 0.0 0.0 0.0 glClearColor
- GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear
- GL_PROJECTION glMatrixMode glLoadIdentity
- dup 0 = [ 2drop ] [ / >float 45.0 swap 0.1 100.0 gluPerspective ] if
- GL_MODELVIEW glMatrixMode glLoadIdentity
- GL_LEQUAL glDepthFunc
- GL_LIGHTING glEnable
- GL_LIGHT0 glEnable
- GL_FOG glEnable
- GL_FOG_DENSITY 0.09 glFogf
- GL_FRONT GL_AMBIENT_AND_DIFFUSE glColorMaterial
- GL_COLOR_MATERIAL glEnable
- GL_LIGHT0 GL_POSITION F{ 0.0 0.0 0.0 1.0 } >c-float-array glLightfv
- GL_LIGHT0 GL_AMBIENT F{ 0.2 0.2 0.2 1.0 } >c-float-array glLightfv
- GL_LIGHT0 GL_DIFFUSE F{ 1.0 1.0 1.0 1.0 } >c-float-array glLightfv
- GL_LIGHT0 GL_SPECULAR F{ 1.0 1.0 1.0 1.0 } >c-float-array glLightfv ;
-
-: player-view ( player -- )
- [ location>> ]
- [ [ location>> ] [ forward>> ] bi v+ ]
- [ up>> ] tri gl-look-at ;
-
-: draw-jamshred ( jamshred width height -- )
- init-graphics jamshred-player [ player-view ] [ draw-tunnel ] bi ;
-
+++ /dev/null
-! Copyright (C) 2007, 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays calendar jamshred.game jamshred.gl jamshred.player jamshred.log kernel math math.constants math.geometry.rect math.vectors namespaces sequences threads ui ui.backend ui.gadgets ui.gadgets.worlds ui.gestures ui.render ;
-IN: jamshred
-
-TUPLE: jamshred-gadget < gadget { jamshred jamshred } last-hand-loc ;
-
-: <jamshred-gadget> ( jamshred -- gadget )
- jamshred-gadget new-gadget swap >>jamshred ;
-
-: default-width ( -- x ) 800 ;
-: default-height ( -- y ) 600 ;
-
-M: jamshred-gadget pref-dim*
- drop default-width default-height 2array ;
-
-M: jamshred-gadget draw-gadget* ( gadget -- )
- [ jamshred>> ] [ rect-dim first2 draw-jamshred ] bi ;
-
-: jamshred-loop ( gadget -- )
- dup jamshred>> quit>> [
- drop
- ] [
- [ jamshred>> jamshred-update ]
- [ relayout-1 ]
- [ 10 sleep yield jamshred-loop ] tri
- ] if ;
-
-: fullscreen ( gadget -- )
- find-world t swap set-fullscreen* ;
-
-: no-fullscreen ( gadget -- )
- find-world f swap set-fullscreen* ;
-
-: toggle-fullscreen ( world -- )
- [ fullscreen? not ] keep set-fullscreen* ;
-
-M: jamshred-gadget graft* ( gadget -- )
- [ jamshred-loop ] curry in-thread ;
-
-M: jamshred-gadget ungraft* ( gadget -- )
- jamshred>> t swap (>>quit) ;
-
-: jamshred-restart ( jamshred-gadget -- )
- <jamshred> >>jamshred drop ;
-
-: pix>radians ( n m -- theta )
- / pi 4 * * ; ! 2 / / pi 2 * * ;
-
-: x>radians ( x gadget -- theta )
- #! translate motion of x pixels to an angle
- rect-dim first pix>radians neg ;
-
-: y>radians ( y gadget -- theta )
- #! translate motion of y pixels to an angle
- rect-dim second pix>radians ;
-
-: (handle-mouse-motion) ( jamshred-gadget mouse-motion -- )
- over jamshred>> >r
- [ first swap x>radians ] 2keep second swap y>radians
- r> mouse-moved ;
-
-: handle-mouse-motion ( jamshred-gadget -- )
- hand-loc get [
- over last-hand-loc>> [
- v- (handle-mouse-motion)
- ] [ 2drop ] if*
- ] 2keep >>last-hand-loc drop ;
-
-: handle-mouse-scroll ( jamshred-gadget -- )
- jamshred>> scroll-direction get
- [ first mouse-scroll-x ]
- [ second mouse-scroll-y ] 2bi ;
-
-: quit ( gadget -- )
- [ no-fullscreen ] [ close-window ] bi ;
-
-jamshred-gadget H{
- { T{ key-down f f "r" } [ jamshred-restart ] }
- { T{ key-down f f " " } [ jamshred>> toggle-running ] }
- { T{ key-down f f "f" } [ find-world toggle-fullscreen ] }
- { T{ key-down f f "UP" } [ jamshred>> jamshred-player 1 swap change-player-speed ] }
- { T{ key-down f f "DOWN" } [ jamshred>> jamshred-player -1 swap change-player-speed ] }
- { T{ key-down f f "LEFT" } [ jamshred>> 1 jamshred-roll ] }
- { T{ key-down f f "RIGHT" } [ jamshred>> -1 jamshred-roll ] }
- { T{ key-down f f "q" } [ quit ] }
- { T{ motion } [ handle-mouse-motion ] }
- { T{ mouse-scroll } [ handle-mouse-scroll ] }
-} set-gestures
-
-: jamshred-window ( -- gadget )
- [ <jamshred> <jamshred-gadget> dup "Jamshred" open-window ] with-ui ;
-
-MAIN: jamshred-window
+++ /dev/null
-USING: kernel logging ;
-IN: jamshred.log
-
-LOG: (jamshred-log) DEBUG
-
-: with-jamshred-log ( quot -- )
- "jamshred" swap with-logging ;
-
-: jamshred-log ( message -- )
- [ (jamshred-log) ] with-jamshred-log ; ! ugly...
+++ /dev/null
-Alex Chapman
+++ /dev/null
-USING: jamshred.oint tools.test ;
-IN: jamshred.oint-tests
-
-[ { 0 -1 -1 } ] [ { 0 1 -1 } { 0 -1 0 } reflect ] unit-test
-[ { 0 1 0 } ] [ { 1 1 0 } { 1 0 0 } proj-perp ] unit-test
-[ { 1 0 0 } ] [ { 1 1 0 } { 0 1 0 } proj-perp ] unit-test
-[ { 1/2 -1/2 0 } ] [ { 1 0 0 } { 1 1 0 } proj-perp ] unit-test
-[ { -1/2 1/2 0 } ] [ { 0 1 0 } { 1 1 0 } proj-perp ] unit-test
+++ /dev/null
-! Copyright (C) 2007, 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays float-arrays kernel locals math math.constants math.functions math.matrices math.vectors math.quaternions random sequences ;
-IN: jamshred.oint
-
-! An oint is a point with three linearly independent unit vectors
-! given relative to that point. In jamshred a player's location and
-! direction are given by the player's oint. Similarly, a tunnel
-! segment's location and orientation are given by an oint.
-
-TUPLE: oint location forward up left ;
-C: <oint> oint
-
-: rotation-quaternion ( theta axis -- quaternion )
- swap 2 / dup cos swap sin rot n*v first3 rect> >r rect> r> 2array ;
-
-: rotate-vector ( q qrecip v -- v )
- v>q swap q* q* q>v ;
-
-: rotate-oint ( oint theta axis -- )
- rotation-quaternion dup qrecip pick
- [ forward>> rotate-vector >>forward ]
- [ up>> rotate-vector >>up ]
- [ left>> rotate-vector >>left ] 3tri drop ;
-
-: left-pivot ( oint theta -- )
- over left>> rotate-oint ;
-
-: up-pivot ( oint theta -- )
- over up>> rotate-oint ;
-
-: forward-pivot ( oint theta -- )
- over forward>> rotate-oint ;
-
-: random-float+- ( n -- m )
- #! find a random float between -n/2 and n/2
- dup 10000 * >fixnum random 10000 / swap 2 / - ;
-
-: random-turn ( oint theta -- )
- 2 / 2dup random-float+- left-pivot random-float+- up-pivot ;
-
-: location+ ( v oint -- )
- [ location>> v+ ] [ (>>location) ] bi ;
-
-: go-forward ( distance oint -- )
- [ forward>> n*v ] [ location+ ] bi ;
-
-: distance-vector ( oint oint -- vector )
- [ location>> ] bi@ swap v- ;
-
-: distance ( oint oint -- distance )
- distance-vector norm ;
-
-: scalar-projection ( v1 v2 -- n )
- #! the scalar projection of v1 onto v2
- tuck v. swap norm / ;
-
-: proj-perp ( u v -- w )
- dupd proj v- ;
-
-: perpendicular-distance ( oint oint -- distance )
- tuck distance-vector swap 2dup left>> scalar-projection abs
- -rot up>> scalar-projection abs + ;
-
-:: reflect ( v n -- v' )
- #! bounce v on a surface with normal n
- v v n v. n n v. / 2 * n n*v v- ;
-
-: half-way ( p1 p2 -- p3 )
- over v- 2 v/n v+ ;
-
-: half-way-between-oints ( o1 o2 -- p )
- [ location>> ] bi@ half-way ;
+++ /dev/null
-Alex Chapman
+++ /dev/null
-! Copyright (C) 2007, 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors colors combinators float-arrays jamshred.log jamshred.oint jamshred.sound jamshred.tunnel kernel locals math math.constants math.order math.ranges math.vectors math.matrices sequences shuffle strings system ;
-IN: jamshred.player
-
-TUPLE: player < oint
- { name string }
- { sounds sounds }
- tunnel
- nearest-segment
- { last-move integer }
- { speed float } ;
-
-! speeds are in GL units / second
-: default-speed ( -- speed ) 1.0 ;
-: max-speed ( -- speed ) 30.0 ;
-
-: <player> ( name sounds -- player )
- [ F{ 0 0 5 } F{ 0 0 -1 } F{ 0 1 0 } F{ -1 0 0 } ] 2dip
- f f 0 default-speed player boa ;
-
-: turn-player ( player x-radians y-radians -- )
- >r over r> left-pivot up-pivot ;
-
-: roll-player ( player z-radians -- )
- forward-pivot ;
-
-: to-tunnel-start ( player -- )
- [ tunnel>> first dup location>> ]
- [ tuck (>>location) (>>nearest-segment) ] bi ;
-
-: play-in-tunnel ( player segments -- )
- >>tunnel to-tunnel-start ;
-
-: update-nearest-segment ( player -- )
- [ tunnel>> ] [ dup nearest-segment>> nearest-segment ]
- [ (>>nearest-segment) ] tri ;
-
-: update-time ( player -- seconds-passed )
- millis swap [ last-move>> - 1000 / ] [ (>>last-move) ] 2bi ;
-
-: moved ( player -- ) millis swap (>>last-move) ;
-
-: speed-range ( -- range )
- max-speed [0,b] ;
-
-: change-player-speed ( inc player -- )
- [ + speed-range clamp-to-range ] change-speed drop ;
-
-: multiply-player-speed ( n player -- )
- [ * speed-range clamp-to-range ] change-speed drop ;
-
-: distance-to-move ( seconds-passed player -- distance )
- speed>> * ;
-
-: bounce ( d-left player -- d-left' player )
- {
- [ dup nearest-segment>> bounce-off-wall ]
- [ sounds>> bang ]
- [ 3/4 swap multiply-player-speed ]
- [ ]
- } cleave ;
-
-:: (distance) ( heading player -- current next location heading )
- player nearest-segment>>
- player [ tunnel>> ] [ nearest-segment>> ] bi heading heading-segment
- player location>> heading ;
-
-: distance-to-heading-segment ( heading player -- distance )
- (distance) distance-to-next-segment ;
-
-: distance-to-heading-segment-area ( heading player -- distance )
- (distance) distance-to-next-segment-area ;
-
-: distance-to-collision ( player -- distance )
- dup nearest-segment>> (distance-to-collision) ;
-
-: almost-to-collision ( player -- distance )
- distance-to-collision 0.1 - dup 0 < [ drop 0 ] when ;
-
-: from ( player -- radius distance-from-centre )
- [ nearest-segment>> dup radius>> swap ] [ location>> ] bi
- distance-from-centre ;
-
-: distance-from-wall ( player -- distance ) from - ;
-: fraction-from-centre ( player -- fraction ) from swap / ;
-: fraction-from-wall ( player -- fraction )
- fraction-from-centre 1 swap - ;
-
-: update-nearest-segment2 ( heading player -- )
- 2dup distance-to-heading-segment-area 0 <= [
- [ tunnel>> ] [ nearest-segment>> rot heading-segment ]
- [ (>>nearest-segment) ] tri
- ] [
- 2drop
- ] if ;
-
-:: move-player-on-heading ( d-left player distance heading -- d-left' player )
- [let* | d-to-move [ d-left distance min ]
- move-v [ d-to-move heading n*v ] |
- move-v player location+
- heading player update-nearest-segment2
- d-left d-to-move - player ] ;
-
-: distance-to-move-freely ( player -- distance )
- [ almost-to-collision ]
- [ [ forward>> ] keep distance-to-heading-segment-area ] bi min ;
-
-: ?move-player-freely ( d-left player -- d-left' player )
- over 0 > [
- ! must make sure we are moving a significant distance, otherwise
- ! we can recurse endlessly due to floating-point imprecision.
- ! (at least I /think/ that's what causes it...)
- dup distance-to-move-freely dup 0.1 > [
- over forward>> move-player-on-heading ?move-player-freely
- ] [ drop ] if
- ] when ;
-
-: drag-heading ( player -- heading )
- [ forward>> ] [ nearest-segment>> forward>> proj ] bi ;
-
-: drag-player ( d-left player -- d-left' player )
- dup [ [ drag-heading ] keep distance-to-heading-segment-area ]
- [ drag-heading move-player-on-heading ] bi ;
-
-: (move-player) ( d-left player -- d-left' player )
- ?move-player-freely over 0 > [
- ! bounce
- drag-player
- (move-player)
- ] when ;
-
-: move-player ( player -- )
- [ update-time ] [ distance-to-move ] [ (move-player) 2drop ] tri ;
-
-: update-player ( player -- )
- [ move-player ] [ nearest-segment>> white swap (>>color) ] bi ;
+++ /dev/null
-! Copyright (C) 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors io.files kernel openal sequences ;
-IN: jamshred.sound
-
-TUPLE: sounds bang ;
-
-: assign-sound ( source wav-path -- )
- resource-path create-buffer-from-wav AL_BUFFER swap set-source-param ;
-
-: <sounds> ( -- sounds )
- init-openal 1 gen-sources first sounds boa
- dup bang>> "extra/jamshred/sound/bang.wav" assign-sound ;
-
-: bang ( sounds -- ) bang>> source-play check-error ;
+++ /dev/null
-A simple 3d tunnel racing game
+++ /dev/null
-applications
-games
+++ /dev/null
-Alex Chapman
+++ /dev/null
-! Copyright (C) 2007, 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays float-arrays jamshred.oint jamshred.tunnel kernel math.vectors sequences tools.test ;
-IN: jamshred.tunnel.tests
-
-[ 0 ] [ T{ segment f { 0 0 0 } f f f 0 }
- T{ segment f { 1 1 1 } f f f 1 }
- T{ oint f { 0 0 0.25 } }
- nearer-segment number>> ] unit-test
-
-[ 0 ] [ T{ oint f { 0 0 0 } } <straight-tunnel> find-nearest-segment number>> ] unit-test
-[ 1 ] [ T{ oint f { 0 0 -1 } } <straight-tunnel> find-nearest-segment number>> ] unit-test
-[ 2 ] [ T{ oint f { 0 0.1 -2.1 } } <straight-tunnel> find-nearest-segment number>> ] unit-test
-
-[ 3 ] [ <straight-tunnel> T{ oint f { 0 0 -3.25 } } 0 nearest-segment-forward number>> ] unit-test
-
-[ F{ 0 0 0 } ] [ <straight-tunnel> T{ oint f { 0 0 -0.25 } } over first nearest-segment location>> ] unit-test
-
-: test-segment-oint ( -- oint )
- { 0 0 0 } { 0 0 -1 } { 0 1 0 } { -1 0 0 } <oint> ;
-
-[ { -1 0 0 } ] [ test-segment-oint { 1 0 0 } vector-to-centre ] unit-test
-[ { 1 0 0 } ] [ test-segment-oint { -1 0 0 } vector-to-centre ] unit-test
-[ { 0 -1 0 } ] [ test-segment-oint { 0 1 0 } vector-to-centre ] unit-test
-[ { 0 1 0 } ] [ test-segment-oint { 0 -1 0 } vector-to-centre ] unit-test
-[ { -1 0 0 } ] [ test-segment-oint { 1 0 -1 } vector-to-centre ] unit-test
-[ { 1 0 0 } ] [ test-segment-oint { -1 0 -1 } vector-to-centre ] unit-test
-[ { 0 -1 0 } ] [ test-segment-oint { 0 1 -1 } vector-to-centre ] unit-test
-[ { 0 1 0 } ] [ test-segment-oint { 0 -1 -1 } vector-to-centre ] unit-test
-
-: simplest-straight-ahead ( -- oint segment )
- { 0 0 0 } { 0 0 -1 } { 0 1 0 } { -1 0 0 } <oint>
- initial-segment ;
-
-[ { 0.0 0.0 0.0 } ] [ simplest-straight-ahead sideways-heading ] unit-test
-[ { 0.0 0.0 0.0 } ] [ simplest-straight-ahead sideways-relative-location ] unit-test
-
-: simple-collision-up ( -- oint segment )
- { 0 0 0 } { 0 1 0 } { 0 0 1 } { -1 0 0 } <oint>
- initial-segment ;
-
-[ { 0.0 1.0 0.0 } ] [ simple-collision-up sideways-heading ] unit-test
-[ { 0.0 0.0 0.0 } ] [ simple-collision-up sideways-relative-location ] unit-test
-[ { 0.0 1.0 0.0 } ]
-[ simple-collision-up collision-vector 0 0 0 3array v+ ] unit-test
+++ /dev/null
-! Copyright (C) 2007, 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays colors combinators float-arrays kernel jamshred.oint locals math math.constants math.matrices math.order math.ranges math.vectors math.quadratic random sequences vectors ;
-USE: tools.walker
-IN: jamshred.tunnel
-
-: n-segments ( -- n ) 5000 ; inline
-
-TUPLE: segment < oint number color radius ;
-C: <segment> segment
-
-: segment-number++ ( segment -- )
- [ number>> 1+ ] keep (>>number) ;
-
-: random-color ( -- color )
- { 100 100 100 } [ random 100 / >float ] map first3 1.0 <rgba> ;
-
-: tunnel-segment-distance ( -- n ) 0.4 ;
-: random-rotation-angle ( -- theta ) pi 20 / ;
-
-: random-segment ( previous-segment -- segment )
- clone dup random-rotation-angle random-turn
- tunnel-segment-distance over go-forward
- random-color >>color dup segment-number++ ;
-
-: (random-segments) ( segments n -- segments )
- dup 0 > [
- >r dup peek random-segment over push r> 1- (random-segments)
- ] [ drop ] if ;
-
-: default-segment-radius ( -- r ) 1 ;
-
-: initial-segment ( -- segment )
- F{ 0 0 0 } F{ 0 0 -1 } F{ 0 1 0 } F{ -1 0 0 }
- 0 random-color default-segment-radius <segment> ;
-
-: random-segments ( n -- segments )
- initial-segment 1vector swap (random-segments) ;
-
-: simple-segment ( n -- segment )
- [ F{ 0 0 -1 } n*v F{ 0 0 -1 } F{ 0 1 0 } F{ -1 0 0 } ] keep
- random-color default-segment-radius <segment> ;
-
-: simple-segments ( n -- segments )
- [ simple-segment ] map ;
-
-: <random-tunnel> ( -- segments )
- n-segments random-segments ;
-
-: <straight-tunnel> ( -- segments )
- n-segments simple-segments ;
-
-: sub-tunnel ( from to segments -- segments )
- #! return segments between from and to, after clamping from and to to
- #! valid values
- [ sequence-index-range [ clamp-to-range ] curry bi@ ] keep <slice> ;
-
-: nearer-segment ( segment segment oint -- segment )
- #! return whichever of the two segments is nearer to the oint
- >r 2dup r> tuck distance >r distance r> < -rot ? ;
-
-: (find-nearest-segment) ( nearest next oint -- nearest ? )
- #! find the nearest of 'next' and 'nearest' to 'oint', and return
- #! t if the nearest hasn't changed
- pick >r nearer-segment dup r> = ;
-
-: find-nearest-segment ( oint segments -- segment )
- dup first swap rest-slice rot [ (find-nearest-segment) ] curry
- find 2drop ;
-
-: nearest-segment-forward ( segments oint start -- segment )
- rot dup length swap <slice> find-nearest-segment ;
-
-: nearest-segment-backward ( segments oint start -- segment )
- swapd 1+ 0 spin <slice> <reversed> find-nearest-segment ;
-
-: nearest-segment ( segments oint start-segment -- segment )
- #! find the segment nearest to 'oint', and return it.
- #! start looking at segment 'start-segment'
- number>> over >r
- [ nearest-segment-forward ] 3keep
- nearest-segment-backward r> nearer-segment ;
-
-: get-segment ( segments n -- segment )
- over sequence-index-range clamp-to-range swap nth ;
-
-: next-segment ( segments current-segment -- segment )
- number>> 1+ get-segment ;
-
-: previous-segment ( segments current-segment -- segment )
- number>> 1- get-segment ;
-
-: heading-segment ( segments current-segment heading -- segment )
- #! the next segment on the given heading
- over forward>> v. 0 <=> {
- { +gt+ [ next-segment ] }
- { +lt+ [ previous-segment ] }
- { +eq+ [ nip ] } ! current segment
- } case ;
-
-:: distance-to-next-segment ( current next location heading -- distance )
- [let | cf [ current forward>> ] |
- cf next location>> v. cf location v. - cf heading v. / ] ;
-
-:: distance-to-next-segment-area ( current next location heading -- distance )
- [let | cf [ current forward>> ]
- h [ next current half-way-between-oints ] |
- cf h v. cf location v. - cf heading v. / ] ;
-
-: vector-to-centre ( seg loc -- v )
- over location>> swap v- swap forward>> proj-perp ;
-
-: distance-from-centre ( seg loc -- distance )
- vector-to-centre norm ;
-
-: wall-normal ( seg oint -- n )
- location>> vector-to-centre normalize ;
-
-: distant ( -- n ) 1000 ;
-
-: max-real ( a b -- c )
- #! sometimes collision-coefficient yields complex roots, so we ignore these (hack)
- dup real? [
- over real? [ max ] [ nip ] if
- ] [
- drop dup real? [ drop distant ] unless
- ] if ;
-
-:: collision-coefficient ( v w r -- c )
- v norm 0 = [
- distant
- ] [
- [let* | a [ v dup v. ]
- b [ v w v. 2 * ]
- c [ w dup v. r sq - ] |
- c b a quadratic max-real ]
- ] if ;
-
-: sideways-heading ( oint segment -- v )
- [ forward>> ] bi@ proj-perp ;
-
-: sideways-relative-location ( oint segment -- loc )
- [ [ location>> ] bi@ v- ] keep forward>> proj-perp ;
-
-: (distance-to-collision) ( oint segment -- distance )
- [ sideways-heading ] [ sideways-relative-location ]
- [ nip radius>> ] 2tri collision-coefficient ;
-
-: collision-vector ( oint segment -- v )
- dupd (distance-to-collision) swap forward>> n*v ;
-
-: bounce-forward ( segment oint -- )
- [ wall-normal ] [ forward>> swap reflect ] [ (>>forward) ] tri ;
-
-: bounce-left ( segment oint -- )
- #! must be done after forward
- [ forward>> vneg ] dip [ left>> swap reflect ]
- [ forward>> proj-perp normalize ] [ (>>left) ] tri ;
-
-: bounce-up ( segment oint -- )
- #! must be done after forward and left!
- nip [ forward>> ] [ left>> cross ] [ (>>up) ] tri ;
-
-: bounce-off-wall ( oint segment -- )
- swap [ bounce-forward ] [ bounce-left ] [ bounce-up ] 2tri ;
-
: make-key-gadget ( scancode dim array -- )
[
swap [
- " " [ ] <bevel-button>
+ " " [ drop ] <bevel-button>
swap [ first >>loc ] [ second >>dim ] bi
] [ execute ] bi*
] dip set-nth ;
+++ /dev/null
-Joe Groff
\ No newline at end of file
+++ /dev/null
-Stanford Bunny rendered with cartoon-style lines instead of shading
\ No newline at end of file
+++ /dev/null
-demos
-opengl
-glsl
\ No newline at end of file
--- /dev/null
+Doug Coleman
--- /dev/null
+USING: io lint kernel math tools.test ;
+IN: lint.tests
+
+! Don't write code like this
+: lint1 ( -- ) [ "hi" print ] [ ] if ; ! when
+
+[ { { lint1 { [ [ ] if ] } } } ] [ \ lint1 lint-word ] unit-test
+
+: lint2 ( n -- n' ) 1 + ; ! 1+
+[ { [ 1 + ] } ] [ \ lint2 lint ] unit-test
+
+: lint3 dup -rot ; ! tuck
+
+[ { { lint3 { [ dup -rot ] } } } ] [ \ lint3 lint-word ] unit-test
--- /dev/null
+! Copyright (C) 2007, 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien alien.accessors arrays assocs
+combinators.short-circuit fry hashtables html.elements io
+kernel math namespaces prettyprint quotations sequences
+sequences.deep sets slots.private vectors vocabs words
+kernel.private ;
+IN: lint
+
+SYMBOL: def-hash
+SYMBOL: def-hash-keys
+
+: set-hash-vector ( val key hash -- )
+ 2dup at -rot [ ?push ] 2dip set-at ;
+
+: more-defs ( hash -- )
+ {
+ { -rot [ swap >r swap r> ] }
+ { -rot [ swap swapd ] }
+ { rot [ >r swap r> swap ] }
+ { rot [ swapd swap ] }
+ { over [ dup swap ] }
+ { tuck [ dup -rot ] }
+ { swapd [ >r swap r> ] }
+ { 2nip [ nip nip ] }
+ { 2drop [ drop drop ] }
+ { 3drop [ drop drop drop ] }
+ { pop* [ pop drop ] }
+ { when [ [ ] if ] }
+ { >boolean [ f = not ] }
+ } swap '[ first2 _ set-hash-vector ] each ;
+
+: accessor-words ( -- seq )
+{
+ alien-signed-1 alien-signed-2 alien-signed-4 alien-signed-8
+ alien-unsigned-1 alien-unsigned-2 alien-unsigned-4 alien-unsigned-8
+ <displaced-alien> alien-unsigned-cell set-alien-signed-cell
+ set-alien-unsigned-1 set-alien-signed-1 set-alien-unsigned-2
+ set-alien-signed-2 set-alien-unsigned-4 set-alien-signed-4
+ set-alien-unsigned-8 set-alien-signed-8
+ alien-cell alien-signed-cell set-alien-cell set-alien-unsigned-cell
+ set-alien-float alien-float
+} ;
+
+: trivial-defs
+ {
+ [ drop ] [ 2array ]
+ [ bitand ]
+
+ [ . ]
+ [ get ]
+ [ t ] [ f ]
+ [ { } ]
+ [ drop f ]
+ [ "cdecl" ]
+ [ first ] [ second ] [ third ] [ fourth ]
+ [ ">" write-html ] [ "/>" write-html ]
+ } ;
+
+! ! Add definitions
+H{ } clone def-hash set-global
+
+all-words [
+ dup def>> dup callable?
+ [ def-hash get-global set-hash-vector ] [ drop ] if
+] each
+
+! ! Remove definitions
+
+! Remove empty word defs
+def-hash get-global [ drop empty? not ] assoc-filter
+
+! Remove constants [ 1 ]
+[ drop { [ length 1 = ] [ first number? ] } 1&& not ] assoc-filter
+
+! Remove words that are their own definition
+[ [ [ def>> ] [ 1quotation ] bi = not ] filter ] assoc-map
+
+! Remove set-alien-cell, etc.
+[ drop [ accessor-words diff ] keep [ length ] bi@ = ] assoc-filter
+
+! Remove trivial defs
+[ drop trivial-defs member? not ] assoc-filter
+
+! Remove numbers only defs
+[ drop [ number? ] all? not ] assoc-filter
+
+! Remove curry only defs
+[ drop [ \ curry = ] all? not ] assoc-filter
+
+! Remove tag defs
+[
+ drop {
+ [ length 3 = ]
+ [ first \ tag = ] [ second number? ] [ third \ eq? = ]
+ } 1&& not
+] assoc-filter
+
+[
+ drop {
+ [ [ wrapper? ] deep-contains? ]
+ [ [ hashtable? ] deep-contains? ]
+ } 1|| not
+] assoc-filter
+
+! Remove n m shift defs
+[
+ drop dup length 3 = [
+ [ first2 [ number? ] both? ]
+ [ third \ shift = ] bi and not
+ ] [ drop t ] if
+] assoc-filter
+
+! Remove [ n slot ]
+[
+ drop dup length 2 =
+ [ first2 [ number? ] [ \ slot = ] bi* and not ] [ drop t ] if
+] assoc-filter
+
+
+dup more-defs
+
+[ def-hash set-global ] [ keys def-hash-keys set-global ] bi
+
+: find-duplicates ( -- seq )
+ def-hash get-global [ nip length 1 > ] assoc-filter ;
+
+GENERIC: lint ( obj -- seq )
+
+M: object lint ( obj -- seq ) drop f ;
+
+: subseq/member? ( subseq/member seq -- ? )
+ { [ start ] [ member? ] } 2|| ;
+
+M: callable lint ( quot -- seq )
+ [ def-hash-keys get-global ] dip '[ _ subseq/member? ] filter ;
+
+M: word lint ( word -- seq )
+ def>> dup callable? [ lint ] [ drop f ] if ;
+
+: word-path. ( word -- )
+ [ vocabulary>> ] [ unparse ] bi ":" glue print ;
+
+: 4bl ( -- ) bl bl bl bl ;
+
+: (lint.) ( pair -- )
+ first2 [ word-path. ] dip [
+ [ 4bl . "-----------------------------------" print ]
+ [ def-hash get-global at [ 4bl word-path. ] each nl ] bi
+ ] each nl nl ;
+
+: lint. ( alist -- ) [ (lint.) ] each ;
+
+GENERIC: run-lint ( obj -- obj )
+
+: (trim-self) ( val key -- obj ? )
+ def-hash get-global at*
+ [ dupd remove empty? not ] [ drop f ] if ;
+
+: trim-self ( seq -- newseq )
+ [ [ (trim-self) ] filter ] assoc-map ;
+
+: filter-symbols ( alist -- alist )
+ [
+ nip first dup def-hash get-global at
+ [ first ] bi@ literalize = not
+ ] assoc-filter ;
+
+M: sequence run-lint ( seq -- seq )
+ [ dup lint ] { } map>assoc trim-self
+ [ second empty? not ] filter filter-symbols ;
+
+M: word run-lint ( word -- seq ) 1array run-lint ;
+
+: lint-all ( -- seq ) all-words run-lint dup lint. ;
+
+: lint-vocab ( vocab -- seq ) words run-lint dup lint. ;
+
+: lint-word ( word -- seq ) 1array run-lint dup lint. ;
--- /dev/null
+Finds potential mistakes in code
+++ /dev/null
-James Cash
+++ /dev/null
-IN: lisp
-USING: help.markup help.syntax ;
-HELP: <LISP
-{ $description "parsing word which converts the lisp code between <LISP and LISP> into factor quotations and calls it" }
-{ $see-also lisp-string>factor } ;
-
-HELP: lisp-string>factor
-{ $values { "str" "a string of lisp code" } { "quot" "the quotation the lisp compiles into" } }
-{ $description "Turns a string of lisp into a factor quotation" } ;
-
-ARTICLE: "lisp" "Lisp in Factor"
-"This is a simple implementation of a Lisp dialect, which somewhat resembles Scheme." $nl
-"It works in two main stages: "
-{ $list
- { "Parse (via " { $vocab-link "lisp.parser" } " the Lisp code into a "
- { $snippet "s-exp" } " tuple." }
- { "Transform the " { $snippet "s-exp" } " into a Factor quotation, via " { $link convert-form } }
-}
-
-{ $subsection "lisp.parser" } ;
-
-ABOUT: "lisp"
\ No newline at end of file
+++ /dev/null
-! Copyright (C) 2008 James Cash
-! See http://factorcode.org/license.txt for BSD license.
-USING: lisp lisp.parser tools.test sequences math kernel parser arrays lists
-quotations ;
-
-IN: lisp.test
-
-[
- define-lisp-builtins
-
- { 5 } [
- "(+ 2 3)" lisp-eval
- ] unit-test
-
- { 8.3 } [
- "(- 10.4 2.1)" lisp-eval
- ] unit-test
-
- { 3 } [
- "((lambda (x y) (+ x y)) 1 2)" lisp-eval
- ] unit-test
-
- { 42 } [
- "((lambda (x y z) (+ x (- y z))) 40 3 1)" lisp-eval
- ] unit-test
-
- { "b" } [
- "(cond (#f \"a\") (#t \"b\"))" lisp-eval
- ] unit-test
-
- { "b" } [
- "(cond ((< 1 2) \"b\") (#t \"a\"))" lisp-eval
- ] unit-test
-
- { +nil+ } [
- "(list)" lisp-eval
- ] unit-test
-
- { { 1 2 3 4 5 } } [
- "(list 1 2 3 4 5)" lisp-eval list>seq
- ] unit-test
-
- { { 1 2 { 3 { 4 } 5 } } } [
- "(list 1 2 (list 3 (list 4) 5))" lisp-eval cons>seq
- ] unit-test
-
- { 5 } [
- "(begin (+ 1 4))" lisp-eval
- ] unit-test
-
- { 5 } [
- "(begin (+ 5 6) (+ 1 4))" lisp-eval
- ] unit-test
-
- { t } [
- T{ lisp-symbol f "if" } lisp-macro?
- ] unit-test
-
- { 1 } [
- "(if #t 1 2)" lisp-eval
- ] unit-test
-
- { 3 } [
- "((lambda (x) (if x (+ 1 2) (- 3 5))) #t)" lisp-eval
- ] unit-test
-
- { { 5 4 3 } } [
- "((lambda (x &rest xs) (cons x xs)) 5 4 3)" lisp-eval cons>seq
- ] unit-test
-
- { { 5 } } [
- "((lambda (x &rest xs) (cons x xs)) 5)" lisp-eval cons>seq
- ] unit-test
-
- { { 1 2 3 4 } } [
- "((lambda (&rest xs) xs) 1 2 3 4)" lisp-eval cons>seq
- ] unit-test
-
- { 10 } [
- <LISP (begin (+ 1 2) (+ 9 1)) LISP>
- ] unit-test
-
- { 4 } [
- <LISP ((lambda (x y) (if x (+ 1 y) (+ 2 y))) #t 3) LISP>
- ] unit-test
-
- { { 3 3 4 } } [
- <LISP (defun foo (x y &rest z)
- (cons (+ x y) z))
- (foo 1 2 3 4)
- LISP> cons>seq
- ] unit-test
-
-] with-interactive-vocabs
+++ /dev/null
-! Copyright (C) 2008 James Cash
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel peg sequences arrays strings
-namespaces combinators math locals locals.private locals.backend accessors
-vectors syntax lisp.parser assocs parser words
-quotations fry lists summary combinators.short-circuit continuations multiline ;
-IN: lisp
-
-DEFER: convert-form
-DEFER: funcall
-DEFER: lookup-var
-DEFER: lookup-macro
-DEFER: lisp-macro?
-DEFER: lisp-var?
-DEFER: define-lisp-macro
-
-! Functions to convert s-exps to quotations
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: convert-body ( cons -- quot )
- [ ] [ convert-form compose ] foldl ; inline
-
-: convert-cond ( cons -- quot )
- cdr [ 2car [ convert-form ] bi@ 2array ]
- { } lmap-as '[ _ cond ] ;
-
-: convert-general-form ( cons -- quot )
- uncons [ convert-body ] [ convert-form ] bi* '[ _ @ funcall ] ;
-
-! words for convert-lambda
-<PRIVATE
-: localize-body ( assoc body -- newbody )
- {
- { [ dup list? ] [ [ lisp-symbol? ] rot '[ [ name>> _ at ] [ ] bi or ] traverse ] }
- { [ dup lisp-symbol? ] [ name>> swap at ] }
- [ nip ]
- } cond ;
-
-: localize-lambda ( body vars -- newvars newbody )
- swap [ make-locals dup push-locals ] dip
- dupd [ localize-body convert-form ] with lmap>array
- >quotation swap pop-locals ;
-
-: split-lambda ( cons -- body-cons vars-seq )
- cdr uncons [ name>> ] lmap>array ; inline
-
-: rest-lambda ( body vars -- quot )
- "&rest" swap [ remove ] [ index ] 2bi
- [ localize-lambda <lambda> lambda-rewrite call ] dip
- swap '[ _ cut '[ @ _ seq>list ] call _ call call ] 1quotation ;
-
-: normal-lambda ( body vars -- quot )
- localize-lambda <lambda> lambda-rewrite '[ @ compose call call ] 1quotation ;
-PRIVATE>
-
-: convert-lambda ( cons -- quot )
- split-lambda "&rest" over member? [ rest-lambda ] [ normal-lambda ] if ;
-
-: convert-quoted ( cons -- quot )
- cadr 1quotation ;
-
-: convert-defmacro ( cons -- quot )
- cdr [ convert-lambda ] [ car name>> ] bi define-lisp-macro [ ] ;
-
-: macro-expand ( cons -- quot )
- uncons [ list>seq >quotation ] [ lookup-macro ] bi* call call ;
-
-: expand-macros ( cons -- cons )
- dup list? [ [ expand-macros ] lmap dup car lisp-macro? [ macro-expand expand-macros ] when ] when ;
-
-: convert-begin ( cons -- quot )
- cdr [ convert-form ] [ ] lmap-as [ 1 tail* ] [ but-last ] bi
- [ '[ { } _ with-datastack drop ] ] map prepend '[ _ [ call ] each ] ;
-
-: form-dispatch ( cons lisp-symbol -- quot )
- name>>
- { { "lambda" [ convert-lambda ] }
- { "defmacro" [ convert-defmacro ] }
- { "quote" [ convert-quoted ] }
- { "cond" [ convert-cond ] }
- { "begin" [ convert-begin ] }
- [ drop convert-general-form ]
- } case ;
-
-: convert-list-form ( cons -- quot )
- dup car
- {
- { [ dup lisp-symbol? ] [ form-dispatch ] }
- [ drop convert-general-form ]
- } cond ;
-
-: convert-form ( lisp-form -- quot )
- {
- { [ dup cons? ] [ convert-list-form ] }
- { [ dup lisp-var? ] [ lookup-var 1quotation ] }
- { [ dup lisp-symbol? ] [ '[ _ lookup-var ] ] }
- [ 1quotation ]
- } cond ;
-
-: lisp-string>factor ( str -- quot )
- lisp-expr expand-macros convert-form ;
-
-: lisp-eval ( str -- * )
- lisp-string>factor call ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-SYMBOL: lisp-env
-SYMBOL: macro-env
-
-ERROR: no-such-var variable-name ;
-M: no-such-var summary drop "No such variable" ;
-
-: init-env ( -- )
- H{ } clone lisp-env set
- H{ } clone macro-env set ;
-
-: lisp-define ( quot name -- )
- lisp-env get set-at ;
-
-: define-lisp-var ( lisp-symbol body -- )
- swap name>> lisp-define ;
-
-: lisp-get ( name -- word )
- lisp-env get at ;
-
-: lookup-var ( lisp-symbol -- quot )
- [ name>> ] [ lisp-var? ] bi [ lisp-get ] [ no-such-var ] if ;
-
-: lisp-var? ( lisp-symbol -- ? )
- dup lisp-symbol? [ name>> lisp-env get key? ] [ drop f ] if ;
-
-: funcall ( quot sym -- * )
- [ 1array [ call ] with-datastack >quotation ] dip curry call ; inline
-
-: define-primitive ( name vocab word -- )
- swap lookup 1quotation '[ _ compose call ] swap lisp-define ;
-
-: lookup-macro ( lisp-symbol -- lambda )
- name>> macro-env get at ;
-
-: define-lisp-macro ( quot name -- )
- macro-env get set-at ;
-
-: lisp-macro? ( car -- ? )
- dup lisp-symbol? [ name>> macro-env get key? ] [ drop f ] if ;
-
-: define-lisp-builtins ( -- )
- init-env
-
- f "#f" lisp-define
- t "#t" lisp-define
-
- "+" "math" "+" define-primitive
- "-" "math" "-" define-primitive
- "<" "math" "<" define-primitive
- ">" "math" ">" define-primitive
-
- "cons" "lists" "cons" define-primitive
- "car" "lists" "car" define-primitive
- "cdr" "lists" "cdr" define-primitive
- "append" "lists" "lappend" define-primitive
- "nil" "lists" "nil" define-primitive
- "nil?" "lists" "nil?" define-primitive
-
- "set" "lisp" "define-lisp-var" define-primitive
-
- "(set 'list (lambda (&rest xs) xs))" lisp-eval
- "(defmacro setq (var val) (list 'set (list 'quote var) val))" lisp-eval
-
- <" (defmacro defun (name vars &rest body)
- (list 'setq name (cons 'lambda (cons vars body)))) "> lisp-eval
-
- "(defmacro if (pred tr fl) (list 'cond (list pred tr) (list (quote #t) fl)))" lisp-eval
- ;
-
-: <LISP
- "LISP>" parse-multiline-string "(begin " prepend ")" append define-lisp-builtins
- lisp-string>factor parsed \ call parsed ; parsing
\ No newline at end of file
+++ /dev/null
-James Cash
+++ /dev/null
-IN: lisp.parser
-USING: help.markup help.syntax ;
-
-ARTICLE: "lisp.parser" "Parsing strings of Lisp"
-"This vocab uses " { $vocab-link "peg.ebnf" } " to turn strings of Lisp into " { $snippet "s-exp" } "s, which are then used by"
-{ $vocab-link "lisp" } " to produce Factor quotations." ;
\ No newline at end of file
+++ /dev/null
-! Copyright (C) 2008 James Cash
-! See http://factorcode.org/license.txt for BSD license.
-USING: lisp.parser tools.test peg peg.ebnf lists ;
-
-IN: lisp.parser.tests
-
-{ 1234 } [
- "1234" "atom" \ lisp-expr rule parse
-] unit-test
-
-{ -42 } [
- "-42" "atom" \ lisp-expr rule parse
-] unit-test
-
-{ 37/52 } [
- "37/52" "atom" \ lisp-expr rule parse
-] unit-test
-
-{ 123.98 } [
- "123.98" "atom" \ lisp-expr rule parse
-] unit-test
-
-{ "" } [
- "\"\"" "atom" \ lisp-expr rule parse
-] unit-test
-
-{ "aoeu" } [
- "\"aoeu\"" "atom" \ lisp-expr rule parse
-] unit-test
-
-{ "aoeu\"de" } [
- "\"aoeu\\\"de\"" "atom" \ lisp-expr rule parse
-] unit-test
-
-{ T{ lisp-symbol f "foobar" } } [
- "foobar" "atom" \ lisp-expr rule parse
-] unit-test
-
-{ T{ lisp-symbol f "+" } } [
- "+" "atom" \ lisp-expr rule parse
-] unit-test
-
-{ +nil+ } [
- "()" lisp-expr
-] unit-test
-
-{ T{
- cons
- f
- T{ lisp-symbol f "foo" }
- T{
- cons
- f
- 1
- T{ cons f 2 T{ cons f "aoeu" +nil+ } }
- } } } [
- "(foo 1 2 \"aoeu\")" lisp-expr
-] unit-test
-
-{ T{ cons f
- 1
- T{ cons f
- T{ cons f 3 T{ cons f 4 +nil+ } }
- T{ cons f 2 +nil+ } }
- }
-} [
- "(1 (3 4) 2)" lisp-expr
-] unit-test
-
-{ { T{ lisp-symbol { name "quote" } } { 1 2 3 } } } [
- "'(1 2 3)" lisp-expr cons>seq
-] unit-test
-
-{ { T{ lisp-symbol f "quote" } T{ lisp-symbol f "foo" } } } [
- "'foo" lisp-expr cons>seq
-] unit-test
-
-{ { 1 2 { T{ lisp-symbol { name "quote" } } { 3 4 } } 5 } } [
- "(1 2 '(3 4) 5)" lisp-expr cons>seq
-] unit-test
\ No newline at end of file
+++ /dev/null
-! Copyright (C) 2008 James Cash
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel peg peg.ebnf math.parser sequences arrays strings
-math fry accessors lists combinators.short-circuit ;
-
-IN: lisp.parser
-
-TUPLE: lisp-symbol name ;
-C: <lisp-symbol> lisp-symbol
-
-EBNF: lisp-expr
-_ = (" " | "\t" | "\n")*
-LPAREN = "("
-RPAREN = ")"
-dquote = '"'
-squote = "'"
-digit = [0-9]
-integer = ("-")? (digit)+ => [[ first2 append string>number ]]
-float = integer "." (digit)* => [[ first3 >string [ number>string ] 2dip 3append string>number ]]
-rational = integer "/" (digit)+ => [[ first3 nip string>number / ]]
-number = float
- | rational
- | integer
-id-specials = "!" | "$" | "%" | "&" | "*" | "/" | ":"
- | "<" | "#" | " =" | ">" | "?" | "^" | "_"
- | "~" | "+" | "-" | "." | "@"
-letters = [a-zA-Z] => [[ 1array >string ]]
-initials = letters | id-specials
-numbers = [0-9] => [[ 1array >string ]]
-subsequents = initials | numbers
-identifier = initials (subsequents)* => [[ first2 concat append <lisp-symbol> ]]
-escaped = "\" . => [[ second ]]
-string = dquote ( escaped | !(dquote) . )* dquote => [[ second >string ]]
-atom = number
- | identifier
- | string
-s-expression = LPAREN (list-item)* RPAREN => [[ second seq>cons ]]
-list-item = _ ( atom | s-expression | quoted ) _ => [[ second ]]
-quoted = squote list-item => [[ second nil cons "quote" <lisp-symbol> swap cons ]]
-expr = list-item
-;EBNF
\ No newline at end of file
+++ /dev/null
-EBNF grammar for parsing Lisp
+++ /dev/null
-lisp
-parsing
+++ /dev/null
-A Lisp interpreter/compiler in Factor
+++ /dev/null
-lisp
-languages
--- /dev/null
+USING: kernel literals tools.test ;
+IN: literals.tests
+
+<<
+: five 5 ;
+: seven-eleven 7 11 ;
+: six-six-six 6 6 6 ;
+>>
+
+[ { 5 } ] [ { $ five } ] unit-test
+[ { 7 11 } ] [ { $ seven-eleven } ] unit-test
+[ { 6 6 6 } ] [ { $ six-six-six } ] unit-test
--- /dev/null
+USING: continuations kernel parser words ;
+IN: literals
+
+: $ scan-word [ execute ] curry with-datastack ; parsing
IN: mason.child.tests
USING: mason.child mason.config tools.test namespaces ;
-[ { "make" "clean" "winnt-x86-32" } ] [
+[ { "make" "winnt-x86-32" } ] [
[
"winnt" target-os set
"x86.32" target-cpu set
] with-scope
] unit-test
-[ { "make" "clean" "macosx-x86-32" } ] [
+[ { "make" "macosx-x86-32" } ] [
[
"macosx" target-os set
"x86.32" target-cpu set
] with-scope
] unit-test
-[ { "gmake" "clean" "netbsd-ppc" } ] [
+[ { "gmake" "netbsd-ppc" } ] [
[
"netbsd" target-os set
"ppc" target-cpu set
! See http://factorcode.org/license.txt for BSD license.
USING: kernel namespaces make debugger sequences io.files
io.launcher arrays accessors calendar continuations
-combinators.short-circuit mason.common mason.report mason.platform ;
+combinators.short-circuit mason.common mason.report
+mason.platform mason.config http.client ;
IN: mason.child
: make-cmd ( -- args )
- [ gnu-make , "clean" , platform , ] { } make ;
+ gnu-make platform 2array ;
+
+: download-dlls ( -- )
+ target-os get "winnt" = [
+ "http://factorcode.org/dlls/"
+ target-cpu get "x86.64" = [ "64/" append ] when
+ [ "freetype6.dll" append ]
+ [ "zlib1.dll" append ] bi
+ [ download ] bi@
+ ] when ;
: make-vm ( -- )
"factor" [
+ download-dlls
+
<process>
make-cmd >>command
"../compile-log" >>stdout
:: upload-safely ( local username host remote -- )
[let* | temp [ remote ".incomplete" append ]
- scp-remote [ { username "@" host ":" temp } concat ] |
- { "scp" local scp-remote } short-running-process
- { "ssh" host "-l" username "mv" temp remote } short-running-process
+ scp-remote [ { username "@" host ":" temp } concat ]
+ scp [ scp-command get ]
+ ssh [ ssh-command get ] |
+ { scp local scp-remote } short-running-process
+ { ssh host "-l" username "mv" temp remote } short-running-process
] ;
: eval-file ( file -- obj )
! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: system io.files namespaces kernel accessors ;
+USING: system io.files namespaces kernel accessors assocs ;
IN: mason.config
! (Optional) Location for build directories
! Directory with binary packages.
SYMBOL: upload-directory
+
+! Optional: override ssh and scp command names
+SYMBOL: scp-command
+scp-command global [ "scp" or ] change-at
+
+SYMBOL: ssh-command
+ssh-command global [ "ssh" or ] change-at
[ { "scp" "boot.unix-x86.64.image" "joe@blah.com:/stuff/clean/netbsd-x86-64" } ] [
[
+ "scp" scp-command set
"joe" image-username set
"blah.com" image-host set
"/stuff/clean" image-directory set
! Copyright (C) 2008 Eduardo Cavazos, Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel namespaces sequences prettyprint io.files
-io.launcher make
-mason.common mason.platform mason.config ;
+io.launcher make mason.common mason.platform mason.config ;
IN: mason.release.branch
: branch-name ( -- string ) "clean-" platform append ;
: upload-clean-image-cmd ( -- args )
[
- "scp" ,
+ scp-command get ,
boot-image-name ,
[
image-username get % "@" %
USING: kernel namespaces assocs io.files io.encodings.utf8
prettyprint help.lint benchmark tools.time bootstrap.stage2
tools.test tools.vocabs help.html mason.common words generic
-accessors compiler.errors sequences sets sorting ;
+accessors compiler.errors sequences sets sorting math ;
IN: mason.test
: do-load ( -- )
: do-benchmarks ( -- )
run-benchmarks benchmarks-file to-file ;
+: benchmark-ms ( quot -- ms )
+ benchmark 1000 /i ; inline
+
: do-all ( -- )
".." [
bootstrap-time get boot-time-file to-file
- [ do-load do-compile-errors ] benchmark load-time-file to-file
- [ generate-help ] benchmark html-help-time-file to-file
- [ do-tests ] benchmark test-time-file to-file
- [ do-help-lint ] benchmark help-lint-time-file to-file
- [ do-benchmarks ] benchmark benchmark-time-file to-file
+ [ do-load do-compile-errors ] benchmark-ms load-time-file to-file
+ [ generate-help ] benchmark-ms html-help-time-file to-file
+ [ do-tests ] benchmark-ms test-time-file to-file
+ [ do-help-lint ] benchmark-ms help-lint-time-file to-file
+ [ do-benchmarks ] benchmark-ms benchmark-time-file to-file
] with-directory ;
MAIN: do-all
\ No newline at end of file
--- /dev/null
+John Benediktsson
--- /dev/null
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: help.syntax help.markup kernel assocs sequences quotations ;
+
+IN: math.binpack
+
+HELP: binpack
+{ $values { "assoc" assoc } { "n" "number of bins" } { "bins" "packed bins" } }
+{ $description "Packs the (key, value) pairs into the specified number of bins, using the value as a weight." } ;
+
+HELP: binpack*
+{ $values { "items" sequence } { "n" "number of bins" } { "bins" "packed bins" } }
+{ $description "Packs a sequence of numbers into the specified number of bins." } ;
+
+HELP: binpack!
+{ $values { "items" sequence } { "quot" quotation } { "n" "number of bins" } { "bins" "packed bins" } }
+{ $description "Packs a sequence of items into the specified number of bins, using the quotatino to determine the weight." } ;
+
--- /dev/null
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: kernel tools.test math.binpack ;
+
+[ t ] [ { V{ } } { } 1 binpack = ] unit-test
+
+[ t ] [ { { 3 } { 2 1 } } { 1 2 3 } 2 binpack* = ] unit-test
+
+[ t ] [ { { 1000 } { 100 60 30 7 } { 70 60 40 23 3 } }
+ { 100 23 40 60 1000 30 60 07 70 03 } 3 binpack* = ] unit-test
+
+
--- /dev/null
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: sequences kernel arrays vectors accessors assocs sorting math math.functions ;
+
+IN: math.binpack
+
+: (binpack) ( bins item -- )
+ [ [ values sum ] map ] keep
+ zip sort-keys values first push ;
+
+: binpack ( assoc n -- bins )
+ [ sort-values <reversed> dup length ] dip
+ tuck / ceiling <array> [ <vector> ] map
+ tuck [ (binpack) ] curry each ;
+
+: binpack* ( items n -- bins )
+ [ dup zip ] dip binpack [ keys ] map ;
+
+: binpack! ( items quot n -- bins )
+ [ dupd map zip ] dip binpack [ keys ] map ;
+
--- /dev/null
+Bin-packing algorithms.
{ [ os macosx? ] [ "libblas.dylib" "cdecl" add-library ] }
{ [ os windows? ] [ "blas.dll" "cdecl" add-library ] }
{ [ os openbsd? ] [ "libcblas.so" "cdecl" add-library ] }
+ { [ os freebsd? ] [ "libcblas.so" "cdecl" add-library ] }
[ "libblas.so" "cdecl" add-library ]
} cond >>
TYPEDEF: int CBLAS_INDEX
-C-STRUCT: CBLAS_C
+C-STRUCT: float-complex
{ "float" "real" }
{ "float" "imag" } ;
-C-STRUCT: CBLAS_Z
+C-STRUCT: double-complex
{ "double" "real" }
{ "double" "imag" } ;
( int N, double* X, int incX, double* Y, int incY ) ;
FUNCTION: void cblas_cdotu_sub
- ( int N, CBLAS_C* X, int incX, CBLAS_C* Y, int incY, CBLAS_C* dotu ) ;
+ ( int N, void* X, int incX, void* Y, int incY, void* dotu ) ;
FUNCTION: void cblas_cdotc_sub
- ( int N, CBLAS_C* X, int incX, CBLAS_C* Y, int incY, CBLAS_C* dotc ) ;
+ ( int N, void* X, int incX, void* Y, int incY, void* dotc ) ;
FUNCTION: void cblas_zdotu_sub
- ( int N, CBLAS_Z* X, int incX, CBLAS_Z* Y, int incY, CBLAS_Z* dotu ) ;
+ ( int N, void* X, int incX, void* Y, int incY, void* dotu ) ;
FUNCTION: void cblas_zdotc_sub
- ( int N, CBLAS_Z* X, int incX, CBLAS_Z* Y, int incY, CBLAS_Z* dotc ) ;
+ ( int N, void* X, int incX, void* Y, int incY, void* dotc ) ;
FUNCTION: float cblas_snrm2
( int N, float* X, int incX ) ;
( int N, double* X, int incX ) ;
FUNCTION: float cblas_scnrm2
- ( int N, CBLAS_C* X, int incX ) ;
+ ( int N, void* X, int incX ) ;
FUNCTION: float cblas_scasum
- ( int N, CBLAS_C* X, int incX ) ;
+ ( int N, void* X, int incX ) ;
FUNCTION: double cblas_dznrm2
- ( int N, CBLAS_Z* X, int incX ) ;
+ ( int N, void* X, int incX ) ;
FUNCTION: double cblas_dzasum
- ( int N, CBLAS_Z* X, int incX ) ;
+ ( int N, void* X, int incX ) ;
FUNCTION: CBLAS_INDEX cblas_isamax
( int N, float* X, int incX ) ;
FUNCTION: CBLAS_INDEX cblas_idamax
( int N, double* X, int incX ) ;
FUNCTION: CBLAS_INDEX cblas_icamax
- ( int N, CBLAS_C* X, int incX ) ;
+ ( int N, void* X, int incX ) ;
FUNCTION: CBLAS_INDEX cblas_izamax
- ( int N, CBLAS_Z* X, int incX ) ;
+ ( int N, void* X, int incX ) ;
FUNCTION: void cblas_sswap
( int N, float* X, int incX, float* Y, int incY ) ;
( int N, double alpha, double* X, int incX, double* Y, int incY ) ;
FUNCTION: void cblas_cswap
- ( int N, CBLAS_C* X, int incX, CBLAS_C* Y, int incY ) ;
+ ( int N, void* X, int incX, void* Y, int incY ) ;
FUNCTION: void cblas_ccopy
- ( int N, CBLAS_C* X, int incX, CBLAS_C* Y, int incY ) ;
+ ( int N, void* X, int incX, void* Y, int incY ) ;
FUNCTION: void cblas_caxpy
- ( int N, CBLAS_C* alpha, CBLAS_C* X, int incX, CBLAS_C* Y, int incY ) ;
+ ( int N, void* alpha, void* X, int incX, void* Y, int incY ) ;
FUNCTION: void cblas_zswap
- ( int N, CBLAS_Z* X, int incX, CBLAS_Z* Y, int incY ) ;
+ ( int N, void* X, int incX, void* Y, int incY ) ;
FUNCTION: void cblas_zcopy
- ( int N, CBLAS_Z* X, int incX, CBLAS_Z* Y, int incY ) ;
+ ( int N, void* X, int incX, void* Y, int incY ) ;
FUNCTION: void cblas_zaxpy
- ( int N, CBLAS_Z* alpha, CBLAS_Z* X, int incX, CBLAS_Z* Y, int incY ) ;
+ ( int N, void* alpha, void* X, int incX, void* Y, int incY ) ;
FUNCTION: void cblas_sscal
( int N, float alpha, float* X, int incX ) ;
FUNCTION: void cblas_dscal
( int N, double alpha, double* X, int incX ) ;
FUNCTION: void cblas_cscal
- ( int N, CBLAS_C* alpha, CBLAS_C* X, int incX ) ;
+ ( int N, void* alpha, void* X, int incX ) ;
FUNCTION: void cblas_zscal
- ( int N, CBLAS_Z* alpha, CBLAS_Z* X, int incX ) ;
+ ( int N, void* alpha, void* X, int incX ) ;
FUNCTION: void cblas_csscal
- ( int N, float alpha, CBLAS_C* X, int incX ) ;
+ ( int N, float alpha, void* X, int incX ) ;
FUNCTION: void cblas_zdscal
- ( int N, double alpha, CBLAS_Z* X, int incX ) ;
+ ( int N, double alpha, void* X, int incX ) ;
FUNCTION: void cblas_srotg
( float* a, float* b, float* c, float* s ) ;
}
"All of these subclasses share the same tuple layout:"
{ $list
- { { $snippet "data" } " contains an alien pointer referencing or byte-array containing a packed, column-major array of float, double, float complex, or double complex values;" }
+ { { $snippet "underlying" } " contains an alien pointer referencing or byte-array containing a packed, column-major array of float, double, float complex, or double complex values;" }
{ { $snippet "ld" } " indicates the distance, in elements, between matrix columns;" }
{ { $snippet "rows" } " and " { $snippet "cols" } " indicate the number of significant rows and columns in the matrix;" }
{ "and " { $snippet "transpose" } ", if set to a true value, indicates that the matrix should be treated as transposed relative to its in-memory representation." }
USING: accessors alien alien.c-types arrays byte-arrays combinators
-combinators.lib combinators.short-circuit fry kernel locals macros
+combinators.short-circuit fry kernel locals macros
math math.blas.cblas math.blas.vectors math.blas.vectors.private
-math.complex math.functions math.order multi-methods qualified
-sequences sequences.merged sequences.private generalizations
-shuffle symbols ;
-QUALIFIED: syntax
+math.complex math.functions math.order functors words
+sequences sequences.merged sequences.private shuffle symbols
+specialized-arrays.direct.float specialized-arrays.direct.double
+specialized-arrays.float specialized-arrays.double ;
IN: math.blas.matrices
-TUPLE: blas-matrix-base data ld rows cols transpose ;
-TUPLE: float-blas-matrix < blas-matrix-base ;
-TUPLE: double-blas-matrix < blas-matrix-base ;
-TUPLE: float-complex-blas-matrix < blas-matrix-base ;
-TUPLE: double-complex-blas-matrix < blas-matrix-base ;
-
-C: <float-blas-matrix> float-blas-matrix
-C: <double-blas-matrix> double-blas-matrix
-C: <float-complex-blas-matrix> float-complex-blas-matrix
-C: <double-complex-blas-matrix> double-complex-blas-matrix
-
-METHOD: element-type { float-blas-matrix }
- drop "float" ;
-METHOD: element-type { double-blas-matrix }
- drop "double" ;
-METHOD: element-type { float-complex-blas-matrix }
- drop "CBLAS_C" ;
-METHOD: element-type { double-complex-blas-matrix }
- drop "CBLAS_Z" ;
+TUPLE: blas-matrix-base underlying ld rows cols transpose ;
: Mtransposed? ( matrix -- ? )
transpose>> ; inline
: Mheight ( matrix -- height )
dup Mtransposed? [ cols>> ] [ rows>> ] if ; inline
+GENERIC: n*M.V+n*V! ( alpha A x beta y -- y=alpha*A.x+b*y )
+GENERIC: n*V(*)V+M! ( alpha x y A -- A=alpha*x(*)y+A )
+GENERIC: n*V(*)Vconj+M! ( alpha x y A -- A=alpha*x(*)yconj+A )
+GENERIC: n*M.M+n*M! ( alpha A B beta C -- C=alpha*A.B+beta*C )
+
<PRIVATE
: (blas-transpose) ( matrix -- integer )
GENERIC: (blas-matrix-like) ( data ld rows cols transpose exemplar -- matrix )
-METHOD: (blas-matrix-like) { object object object object object float-blas-matrix }
- drop <float-blas-matrix> ;
-METHOD: (blas-matrix-like) { object object object object object double-blas-matrix }
- drop <double-blas-matrix> ;
-METHOD: (blas-matrix-like) { object object object object object float-complex-blas-matrix }
- drop <float-complex-blas-matrix> ;
-METHOD: (blas-matrix-like) { object object object object object double-complex-blas-matrix }
- drop <double-complex-blas-matrix> ;
-
-METHOD: (blas-matrix-like) { object object object object object float-blas-vector }
- drop <float-blas-matrix> ;
-METHOD: (blas-matrix-like) { object object object object object double-blas-vector }
- drop <double-blas-matrix> ;
-METHOD: (blas-matrix-like) { object object object object object float-complex-blas-vector }
- drop <float-complex-blas-matrix> ;
-METHOD: (blas-matrix-like) { object object object object object double-complex-blas-vector }
- drop <double-complex-blas-matrix> ;
-
-METHOD: (blas-vector-like) { object object object float-blas-matrix }
- drop <float-blas-vector> ;
-METHOD: (blas-vector-like) { object object object double-blas-matrix }
- drop <double-blas-vector> ;
-METHOD: (blas-vector-like) { object object object float-complex-blas-matrix }
- drop <float-complex-blas-vector> ;
-METHOD: (blas-vector-like) { object object object double-complex-blas-matrix }
- drop <double-complex-blas-vector> ;
-
: (validate-gemv) ( A x y -- )
{
[ drop [ Mwidth ] [ length>> ] bi* = ]
[ nip [ Mheight ] [ length>> ] bi* = ]
} 3&&
- [ "Mismatched matrix and vectors in matrix-vector multiplication" throw ] unless ;
+ [ "Mismatched matrix and vectors in matrix-vector multiplication" throw ]
+ unless ;
-:: (prepare-gemv) ( alpha A x beta y >c-arg -- order A-trans m n alpha A-data A-ld x-data x-inc beta y-data y-inc y )
+:: (prepare-gemv)
+ ( alpha A x beta y >c-arg -- order A-trans m n alpha A-data A-ld x-data x-inc beta y-data y-inc
+ y )
A x y (validate-gemv)
CblasColMajor
A (blas-transpose)
A rows>>
A cols>>
alpha >c-arg call
- A data>>
+ A underlying>>
A ld>>
- x data>>
+ x underlying>>
x inc>>
beta >c-arg call
- y data>>
+ y underlying>>
y inc>>
y ; inline
[ nip [ length>> ] [ Mheight ] bi* = ]
[ nipd [ length>> ] [ Mwidth ] bi* = ]
} 3&&
- [ "Mismatched vertices and matrix in vector outer product" throw ] unless ;
+ [ "Mismatched vertices and matrix in vector outer product" throw ]
+ unless ;
-:: (prepare-ger) ( alpha x y A >c-arg -- order m n alpha x-data x-inc y-data y-inc A-data A-ld A )
+:: (prepare-ger)
+ ( alpha x y A >c-arg -- order m n alpha x-data x-inc y-data y-inc A-data A-ld
+ A )
x y A (validate-ger)
CblasColMajor
A rows>>
A cols>>
alpha >c-arg call
- x data>>
+ x underlying>>
x inc>>
- y data>>
+ y underlying>>
y inc>>
- A data>>
+ A underlying>>
A ld>>
A f >>transpose ; inline
[ drop [ Mwidth ] [ Mheight ] bi* = ]
[ nip [ Mheight ] bi@ = ]
[ nipd [ Mwidth ] bi@ = ]
- } 3&& [ "Mismatched matrices in matrix multiplication" throw ] unless ;
+ } 3&&
+ [ "Mismatched matrices in matrix multiplication" throw ]
+ unless ;
-:: (prepare-gemm) ( alpha A B beta C >c-arg -- order A-trans B-trans m n k alpha A-data A-ld B-data B-ld beta C-data C-ld C )
+:: (prepare-gemm)
+ ( alpha A B beta C >c-arg -- order A-trans B-trans m n k alpha A-data A-ld B-data B-ld beta C-data C-ld
+ C )
A B C (validate-gemm)
CblasColMajor
A (blas-transpose)
C cols>>
A Mwidth
alpha >c-arg call
- A data>>
+ A underlying>>
A ld>>
- B data>>
+ B underlying>>
B ld>>
beta >c-arg call
- C data>>
+ C underlying>>
C ld>>
C f >>transpose ; inline
PRIVATE>
-: >float-blas-matrix ( arrays -- matrix )
- [ >c-float-array ] (>matrix) <float-blas-matrix> ;
-: >double-blas-matrix ( arrays -- matrix )
- [ >c-double-array ] (>matrix) <double-blas-matrix> ;
-: >float-complex-blas-matrix ( arrays -- matrix )
- [ (flatten-complex-sequence) >c-float-array ] (>matrix)
- <float-complex-blas-matrix> ;
-: >double-complex-blas-matrix ( arrays -- matrix )
- [ (flatten-complex-sequence) >c-double-array ] (>matrix)
- <double-complex-blas-matrix> ;
-
-GENERIC: n*M.V+n*V! ( alpha A x beta y -- y=alpha*A.x+b*y )
-GENERIC: n*V(*)V+M! ( alpha x y A -- A=alpha*x(*)y+A )
-GENERIC: n*V(*)Vconj+M! ( alpha x y A -- A=alpha*x(*)yconj+A )
-GENERIC: n*M.M+n*M! ( alpha A B beta C -- C=alpha*A.B+beta*C )
-
-METHOD: n*M.V+n*V! { real float-blas-matrix float-blas-vector real float-blas-vector }
- [ ] (prepare-gemv) [ cblas_sgemv ] dip ;
-METHOD: n*M.V+n*V! { real double-blas-matrix double-blas-vector real double-blas-vector }
- [ ] (prepare-gemv) [ cblas_dgemv ] dip ;
-METHOD: n*M.V+n*V! { number float-complex-blas-matrix float-complex-blas-vector number float-complex-blas-vector }
- [ (>c-complex) ] (prepare-gemv) [ cblas_cgemv ] dip ;
-METHOD: n*M.V+n*V! { number double-complex-blas-matrix double-complex-blas-vector number double-complex-blas-vector }
- [ (>z-complex) ] (prepare-gemv) [ cblas_zgemv ] dip ;
-
-METHOD: n*V(*)V+M! { real float-blas-vector float-blas-vector float-blas-matrix }
- [ ] (prepare-ger) [ cblas_sger ] dip ;
-METHOD: n*V(*)V+M! { real double-blas-vector double-blas-vector double-blas-matrix }
- [ ] (prepare-ger) [ cblas_dger ] dip ;
-METHOD: n*V(*)V+M! { number float-complex-blas-vector float-complex-blas-vector float-complex-blas-matrix }
- [ (>c-complex) ] (prepare-ger) [ cblas_cgeru ] dip ;
-METHOD: n*V(*)V+M! { number double-complex-blas-vector double-complex-blas-vector double-complex-blas-matrix }
- [ (>z-complex) ] (prepare-ger) [ cblas_zgeru ] dip ;
-
-METHOD: n*V(*)Vconj+M! { real float-blas-vector float-blas-vector float-blas-matrix }
- [ ] (prepare-ger) [ cblas_sger ] dip ;
-METHOD: n*V(*)Vconj+M! { real double-blas-vector double-blas-vector double-blas-matrix }
- [ ] (prepare-ger) [ cblas_dger ] dip ;
-METHOD: n*V(*)Vconj+M! { number float-complex-blas-vector float-complex-blas-vector float-complex-blas-matrix }
- [ (>c-complex) ] (prepare-ger) [ cblas_cgerc ] dip ;
-METHOD: n*V(*)Vconj+M! { number double-complex-blas-vector double-complex-blas-vector double-complex-blas-matrix }
- [ (>z-complex) ] (prepare-ger) [ cblas_zgerc ] dip ;
-
-METHOD: n*M.M+n*M! { real float-blas-matrix float-blas-matrix real float-blas-matrix }
- [ ] (prepare-gemm) [ cblas_sgemm ] dip ;
-METHOD: n*M.M+n*M! { real double-blas-matrix double-blas-matrix real double-blas-matrix }
- [ ] (prepare-gemm) [ cblas_dgemm ] dip ;
-METHOD: n*M.M+n*M! { number float-complex-blas-matrix float-complex-blas-matrix number float-complex-blas-matrix }
- [ (>c-complex) ] (prepare-gemm) [ cblas_cgemm ] dip ;
-METHOD: n*M.M+n*M! { number double-complex-blas-matrix double-complex-blas-matrix number double-complex-blas-matrix }
- [ (>z-complex) ] (prepare-gemm) [ cblas_zgemm ] dip ;
-
! XXX should do a dense clone
-syntax:M: blas-matrix-base clone
+M: blas-matrix-base clone
[
- [
- { [ data>> ] [ ld>> ] [ cols>> ] [ element-type heap-size ] } cleave
- * * memory>byte-array
- ] [ { [ ld>> ] [ rows>> ] [ cols>> ] [ transpose>> ] } cleave ] bi
+ [ {
+ [ underlying>> ]
+ [ ld>> ]
+ [ cols>> ]
+ [ element-type heap-size ]
+ } cleave * * memory>byte-array ]
+ [ {
+ [ ld>> ]
+ [ rows>> ]
+ [ cols>> ]
+ [ transpose>> ]
+ } cleave ]
+ bi
] keep (blas-matrix-like) ;
! XXX try rounding stride to next 128 bit bound for better vectorizin'
:: (Msub) ( matrix row col height width -- data ld rows cols )
matrix ld>> col * row + matrix element-type heap-size *
- matrix data>> <displaced-alien>
+ matrix underlying>> <displaced-alien>
matrix ld>>
height
width ;
-: Msub ( matrix row col height width -- sub )
- 5 npick dup transpose>>
- [ nip [ [ swap ] 2dip swap ] when (Msub) ] 2keep
- swap (blas-matrix-like) ;
+:: Msub ( matrix row col height width -- sub )
+ matrix dup transpose>>
+ [ col row width height ]
+ [ row col height width ] if (Msub)
+ matrix transpose>> matrix (blas-matrix-like) ;
-TUPLE: blas-matrix-rowcol-sequence parent inc rowcol-length rowcol-jump length ;
+TUPLE: blas-matrix-rowcol-sequence
+ parent inc rowcol-length rowcol-jump length ;
C: <blas-matrix-rowcol-sequence> blas-matrix-rowcol-sequence
INSTANCE: blas-matrix-rowcol-sequence sequence
-syntax:M: blas-matrix-rowcol-sequence length
+M: blas-matrix-rowcol-sequence length
length>> ;
-syntax:M: blas-matrix-rowcol-sequence nth-unsafe
+M: blas-matrix-rowcol-sequence nth-unsafe
{
[
[ rowcol-jump>> ]
[ parent>> element-type heap-size ]
- [ parent>> data>> ] tri
+ [ parent>> underlying>> ] tri
[ * * ] dip <displaced-alien>
]
[ rowcol-length>> ]
} cleave (blas-vector-like) ;
: (Mcols) ( A -- columns )
- { [ ] [ drop 1 ] [ rows>> ] [ ld>> ] [ cols>> ] } cleave
- <blas-matrix-rowcol-sequence> ;
+ { [ ] [ drop 1 ] [ rows>> ] [ ld>> ] [ cols>> ] }
+ cleave <blas-matrix-rowcol-sequence> ;
: (Mrows) ( A -- rows )
- { [ ] [ ld>> ] [ cols>> ] [ drop 1 ] [ rows>> ] } cleave
- <blas-matrix-rowcol-sequence> ;
+ { [ ] [ ld>> ] [ cols>> ] [ drop 1 ] [ rows>> ] }
+ cleave <blas-matrix-rowcol-sequence> ;
: Mrows ( A -- rows )
dup transpose>> [ (Mcols) ] [ (Mrows) ] if ;
recip swap n*M ; inline
: Mtranspose ( matrix -- matrix^T )
- [ { [ data>> ] [ ld>> ] [ rows>> ] [ cols>> ] [ transpose>> not ] } cleave ] keep (blas-matrix-like) ;
-
-syntax:M: blas-matrix-base equal?
+ [ {
+ [ underlying>> ]
+ [ ld>> ] [ rows>> ]
+ [ cols>> ]
+ [ transpose>> not ]
+ } cleave ] keep (blas-matrix-like) ;
+
+M: blas-matrix-base equal?
{
[ [ Mwidth ] bi@ = ]
[ [ Mcols ] bi@ [ = ] 2all? ]
} 2&& ;
+<<
+
+FUNCTOR: (define-blas-matrix) ( TYPE T U C -- )
+
+VECTOR IS ${TYPE}-blas-vector
+<VECTOR> IS <${TYPE}-blas-vector>
+>ARRAY IS >${TYPE}-array
+TYPE>ARG IS ${TYPE}>arg
+XGEMV IS cblas_${T}gemv
+XGEMM IS cblas_${T}gemm
+XGERU IS cblas_${T}ger${U}
+XGERC IS cblas_${T}ger${C}
+
+MATRIX DEFINES ${TYPE}-blas-matrix
+<MATRIX> DEFINES <${TYPE}-blas-matrix>
+>MATRIX DEFINES >${TYPE}-blas-matrix
+
+WHERE
+
+TUPLE: MATRIX < blas-matrix-base ;
+: <MATRIX> ( underlying ld rows cols transpose -- matrix )
+ MATRIX boa ; inline
+
+M: MATRIX element-type
+ drop TYPE ;
+M: MATRIX (blas-matrix-like)
+ drop <MATRIX> execute ;
+M: VECTOR (blas-matrix-like)
+ drop <MATRIX> execute ;
+M: MATRIX (blas-vector-like)
+ drop <VECTOR> execute ;
+
+: >MATRIX ( arrays -- matrix )
+ [ >ARRAY execute underlying>> ] (>matrix)
+ <MATRIX> execute ;
+
+M: VECTOR n*M.V+n*V!
+ [ TYPE>ARG execute ] (prepare-gemv)
+ [ XGEMV execute ] dip ;
+M: MATRIX n*M.M+n*M!
+ [ TYPE>ARG execute ] (prepare-gemm)
+ [ XGEMM execute ] dip ;
+M: MATRIX n*V(*)V+M!
+ [ TYPE>ARG execute ] (prepare-ger)
+ [ XGERU execute ] dip ;
+M: MATRIX n*V(*)Vconj+M!
+ [ TYPE>ARG execute ] (prepare-ger)
+ [ XGERC execute ] dip ;
+
+;FUNCTOR
+
+
+: define-real-blas-matrix ( TYPE T -- )
+ "" "" (define-blas-matrix) ;
+: define-complex-blas-matrix ( TYPE T -- )
+ "u" "c" (define-blas-matrix) ;
+
+"float" "s" define-real-blas-matrix
+"double" "d" define-real-blas-matrix
+"float-complex" "c" define-complex-blas-matrix
+"double-complex" "z" define-complex-blas-matrix
+
+>>
-USING: kernel math.blas.matrices math.blas.vectors parser
+USING: kernel math.blas.vectors math.blas.matrices parser
arrays prettyprint.backend sequences ;
IN: math.blas.syntax
: zmatrix{
\ } [ >double-complex-blas-matrix ] parse-literal ; parsing
-M: float-blas-vector pprint-delims drop \ svector{ \ } ;
-M: double-blas-vector pprint-delims drop \ dvector{ \ } ;
-M: float-complex-blas-vector pprint-delims drop \ cvector{ \ } ;
-M: double-complex-blas-vector pprint-delims drop \ zvector{ \ } ;
+M: float-blas-vector pprint-delims
+ drop \ svector{ \ } ;
+M: double-blas-vector pprint-delims
+ drop \ dvector{ \ } ;
+M: float-complex-blas-vector pprint-delims
+ drop \ cvector{ \ } ;
+M: double-complex-blas-vector pprint-delims
+ drop \ zvector{ \ } ;
-M: float-blas-matrix pprint-delims drop \ smatrix{ \ } ;
-M: double-blas-matrix pprint-delims drop \ dmatrix{ \ } ;
-M: float-complex-blas-matrix pprint-delims drop \ cmatrix{ \ } ;
-M: double-complex-blas-matrix pprint-delims drop \ zmatrix{ \ } ;
+M: float-blas-matrix pprint-delims
+ drop \ smatrix{ \ } ;
+M: double-blas-matrix pprint-delims
+ drop \ dmatrix{ \ } ;
+M: float-complex-blas-matrix pprint-delims
+ drop \ cmatrix{ \ } ;
+M: double-complex-blas-matrix pprint-delims
+ drop \ zmatrix{ \ } ;
M: blas-vector-base >pprint-sequence ;
M: blas-vector-base pprint* pprint-object ;
}
"All of these subclasses share the same tuple layout:"
{ $list
- { { $snippet "data" } " contains an alien pointer referencing or byte-array containing a packed array of float, double, float complex, or double complex values;" }
+ { { $snippet "underlying" } " contains an alien pointer referencing or byte-array containing a packed array of float, double, float complex, or double complex values;" }
{ { $snippet "length" } " indicates the length of the vector;" }
{ "and " { $snippet "inc" } " indicates the distance, in elements, between elements." }
} } ;
USING: accessors alien alien.c-types arrays byte-arrays combinators
-combinators.short-circuit fry kernel macros math math.blas.cblas
-math.complex math.functions math.order multi-methods qualified
-sequences sequences.private generalizations ;
-QUALIFIED: syntax
+combinators.short-circuit fry kernel math math.blas.cblas
+math.complex math.functions math.order sequences.complex
+sequences.complex-components sequences sequences.private
+functors words locals
+specialized-arrays.float specialized-arrays.double
+specialized-arrays.direct.float specialized-arrays.direct.double ;
IN: math.blas.vectors
-TUPLE: blas-vector-base data length inc ;
-TUPLE: float-blas-vector < blas-vector-base ;
-TUPLE: double-blas-vector < blas-vector-base ;
-TUPLE: float-complex-blas-vector < blas-vector-base ;
-TUPLE: double-complex-blas-vector < blas-vector-base ;
+TUPLE: blas-vector-base underlying length inc ;
-INSTANCE: float-blas-vector sequence
-INSTANCE: double-blas-vector sequence
-INSTANCE: float-complex-blas-vector sequence
-INSTANCE: double-complex-blas-vector sequence
+INSTANCE: blas-vector-base virtual-sequence
-C: <float-blas-vector> float-blas-vector
-C: <double-blas-vector> double-blas-vector
-C: <float-complex-blas-vector> float-complex-blas-vector
-C: <double-complex-blas-vector> double-complex-blas-vector
+GENERIC: element-type ( v -- type )
GENERIC: n*V+V! ( alpha x y -- y=alpha*x+y )
GENERIC: n*V! ( alpha x -- x=alpha*x )
-
GENERIC: V. ( x y -- x.y )
GENERIC: V.conj ( x y -- xconj.y )
GENERIC: Vnorm ( x -- norm )
GENERIC: Vasum ( x -- sum )
GENERIC: Vswap ( x y -- x=y y=x )
-
GENERIC: Viamax ( x -- max-i )
-GENERIC: element-type ( v -- type )
-
-METHOD: element-type { float-blas-vector }
- drop "float" ;
-METHOD: element-type { double-blas-vector }
- drop "double" ;
-METHOD: element-type { float-complex-blas-vector }
- drop "CBLAS_C" ;
-METHOD: element-type { double-complex-blas-vector }
- drop "CBLAS_Z" ;
-
<PRIVATE
GENERIC: (blas-vector-like) ( data length inc exemplar -- vector )
-METHOD: (blas-vector-like) { object object object float-blas-vector }
- drop <float-blas-vector> ;
-METHOD: (blas-vector-like) { object object object double-blas-vector }
- drop <double-blas-vector> ;
-METHOD: (blas-vector-like) { object object object float-complex-blas-vector }
- drop <float-complex-blas-vector> ;
-METHOD: (blas-vector-like) { object object object double-complex-blas-vector }
- drop <double-complex-blas-vector> ;
-
-: (prepare-copy) ( v element-size -- length v-data v-inc v-dest-data v-dest-inc )
- [ [ length>> ] [ data>> ] [ inc>> ] tri ] dip
- 4 npick * <byte-array>
- 1 ;
-
-MACRO: (do-copy) ( copy make-vector -- )
- '[ over 6 npick _ 2dip 1 @ ] ;
-
-: (prepare-swap) ( v1 v2 -- length v1-data v1-inc v2-data v2-inc v1 v2 )
- [
- [ [ length>> ] bi@ min ]
- [ [ [ data>> ] [ inc>> ] bi ] bi@ ] 2bi
- ] 2keep ;
-
-: (prepare-axpy) ( n v1 v2 -- length n v1-data v1-inc v2-data v2-inc v2 )
- [
- [ [ length>> ] bi@ min swap ]
- [ [ [ data>> ] [ inc>> ] bi ] bi@ ] 2bi
- ] keep ;
-
-: (prepare-scal) ( n v -- length n v-data v-inc v )
- [ [ length>> swap ] [ data>> ] [ inc>> ] tri ] keep ;
+GENERIC: (blas-direct-array) ( blas-vector -- direct-array )
+
+: shorter-length ( v1 v2 -- length )
+ [ length>> ] bi@ min ; inline
+: data-and-inc ( v -- data inc )
+ [ underlying>> ] [ inc>> ] bi ; inline
+: datas-and-incs ( v1 v2 -- v1-data v1-inc v2-data v2-inc )
+ [ data-and-inc ] bi@ ; inline
+
+:: (prepare-copy)
+ ( v element-size -- length v-data v-inc v-dest-data v-dest-inc
+ copy-data copy-length copy-inc )
+ v [ length>> ] [ data-and-inc ] bi
+ v length>> element-size * <byte-array>
+ 1
+ over v length>> 1 ;
+
+: (prepare-swap)
+ ( v1 v2 -- length v1-data v1-inc v2-data v2-inc
+ v1 v2 )
+ [ shorter-length ] [ datas-and-incs ] [ ] 2tri ;
+
+:: (prepare-axpy)
+ ( n v1 v2 -- length n v1-data v1-inc v2-data v2-inc
+ v2 )
+ v1 v2 shorter-length
+ n
+ v1 v2 datas-and-incs
+ v2 ;
+
+:: (prepare-scal)
+ ( n v -- length n v-data v-inc
+ v )
+ v length>>
+ n
+ v data-and-inc
+ v ;
: (prepare-dot) ( v1 v2 -- length v1-data v1-inc v2-data v2-inc )
- [ [ length>> ] bi@ min ]
- [ [ [ data>> ] [ inc>> ] bi ] bi@ ] 2bi ;
-
-: (prepare-nrm2) ( v -- length v1-data v1-inc )
- [ length>> ] [ data>> ] [ inc>> ] tri ;
-
-: (flatten-complex-sequence) ( seq -- seq' )
- [ [ real-part ] [ imaginary-part ] bi 2array ] map concat ;
-
-: (>c-complex) ( complex -- alien )
- [ real-part ] [ imaginary-part ] bi 2array >c-float-array ;
-: (>z-complex) ( complex -- alien )
- [ real-part ] [ imaginary-part ] bi 2array >c-double-array ;
-
-: (c-complex>) ( alien -- complex )
- 2 c-float-array> first2 rect> ;
-: (z-complex>) ( alien -- complex )
- 2 c-double-array> first2 rect> ;
-
-: (prepare-nth) ( n v -- n*inc v-data )
- [ inc>> ] [ data>> ] bi [ * ] dip ;
-
-MACRO: (complex-nth) ( nth-quot -- )
- '[
- [ 2 * dup 1+ ] dip
- _ curry bi@ rect>
- ] ;
-
-: (c-complex-nth) ( n alien -- complex )
- [ float-nth ] (complex-nth) ;
-: (z-complex-nth) ( n alien -- complex )
- [ double-nth ] (complex-nth) ;
-
-MACRO: (set-complex-nth) ( set-nth-quot -- )
- '[
- [
- [ [ real-part ] [ imaginary-part ] bi ]
- [ 2 * dup 1+ ] bi*
- swapd
- ] dip
- _ curry 2bi@
- ] ;
-
-: (set-c-complex-nth) ( complex n alien -- )
- [ set-float-nth ] (set-complex-nth) ;
-: (set-z-complex-nth) ( complex n alien -- )
- [ set-double-nth ] (set-complex-nth) ;
+ [ shorter-length ] [ datas-and-incs ] 2bi ;
+
+: (prepare-nrm2) ( v -- length data inc )
+ [ length>> ] [ data-and-inc ] bi ;
PRIVATE>
+: n*V+V ( alpha x y -- alpha*x+y ) clone n*V+V! ; inline
+: n*V ( alpha x -- alpha*x ) clone n*V! ; inline
+
+: V+ ( x y -- x+y )
+ 1.0 -rot n*V+V ; inline
+: V- ( x y -- x-y )
+ -1.0 spin n*V+V ; inline
+
+: Vneg ( x -- -x )
+ -1.0 swap n*V ; inline
+
+: V*n ( x alpha -- x*alpha )
+ swap n*V ; inline
+: V/n ( x alpha -- x/alpha )
+ recip swap n*V ; inline
+
+: Vamax ( x -- max )
+ [ Viamax ] keep nth ; inline
+
+:: Vsub ( v start length -- sub )
+ v inc>> start * v element-type heap-size *
+ v underlying>> <displaced-alien>
+ length v inc>> v (blas-vector-like) ;
+
: <zero-vector> ( exemplar -- zero )
[ element-type <c-object> ]
[ length>> 0 ]
[ 1 swap ] 2bi
(blas-vector-like) ;
-syntax:M: blas-vector-base length
- length>> ;
-
-syntax:M: float-blas-vector nth-unsafe
- (prepare-nth) float-nth ;
-syntax:M: float-blas-vector set-nth-unsafe
- (prepare-nth) set-float-nth ;
-
-syntax:M: double-blas-vector nth-unsafe
- (prepare-nth) double-nth ;
-syntax:M: double-blas-vector set-nth-unsafe
- (prepare-nth) set-double-nth ;
-
-syntax:M: float-complex-blas-vector nth-unsafe
- (prepare-nth) (c-complex-nth) ;
-syntax:M: float-complex-blas-vector set-nth-unsafe
- (prepare-nth) (set-c-complex-nth) ;
-
-syntax:M: double-complex-blas-vector nth-unsafe
- (prepare-nth) (z-complex-nth) ;
-syntax:M: double-complex-blas-vector set-nth-unsafe
- (prepare-nth) (set-z-complex-nth) ;
-
-syntax:M: blas-vector-base equal?
+M: blas-vector-base equal?
{
[ [ length ] bi@ = ]
[ [ = ] 2all? ]
} 2&& ;
-: >float-blas-vector ( seq -- v )
- [ >c-float-array ] [ length ] bi 1 <float-blas-vector> ;
-: >double-blas-vector ( seq -- v )
- [ >c-double-array ] [ length ] bi 1 <double-blas-vector> ;
-: >float-complex-blas-vector ( seq -- v )
- [ (flatten-complex-sequence) >c-float-array ] [ length ] bi
- 1 <float-complex-blas-vector> ;
-: >double-complex-blas-vector ( seq -- v )
- [ (flatten-complex-sequence) >c-double-array ] [ length ] bi
- 1 <double-complex-blas-vector> ;
-
-syntax:M: float-blas-vector clone
- "float" heap-size (prepare-copy)
- [ cblas_scopy ] [ <float-blas-vector> ] (do-copy) ;
-syntax:M: double-blas-vector clone
- "double" heap-size (prepare-copy)
- [ cblas_dcopy ] [ <double-blas-vector> ] (do-copy) ;
-syntax:M: float-complex-blas-vector clone
- "CBLAS_C" heap-size (prepare-copy)
- [ cblas_ccopy ] [ <float-complex-blas-vector> ] (do-copy) ;
-syntax:M: double-complex-blas-vector clone
- "CBLAS_Z" heap-size (prepare-copy)
- [ cblas_zcopy ] [ <double-complex-blas-vector> ] (do-copy) ;
-
-METHOD: Vswap { float-blas-vector float-blas-vector }
- (prepare-swap) [ cblas_sswap ] 2dip ;
-METHOD: Vswap { double-blas-vector double-blas-vector }
- (prepare-swap) [ cblas_dswap ] 2dip ;
-METHOD: Vswap { float-complex-blas-vector float-complex-blas-vector }
- (prepare-swap) [ cblas_cswap ] 2dip ;
-METHOD: Vswap { double-complex-blas-vector double-complex-blas-vector }
- (prepare-swap) [ cblas_zswap ] 2dip ;
-
-METHOD: n*V+V! { real float-blas-vector float-blas-vector }
- (prepare-axpy) [ cblas_saxpy ] dip ;
-METHOD: n*V+V! { real double-blas-vector double-blas-vector }
- (prepare-axpy) [ cblas_daxpy ] dip ;
-METHOD: n*V+V! { number float-complex-blas-vector float-complex-blas-vector }
- [ (>c-complex) ] 2dip
- (prepare-axpy) [ cblas_caxpy ] dip ;
-METHOD: n*V+V! { number double-complex-blas-vector double-complex-blas-vector }
- [ (>z-complex) ] 2dip
- (prepare-axpy) [ cblas_zaxpy ] dip ;
-
-METHOD: n*V! { real float-blas-vector }
- (prepare-scal) [ cblas_sscal ] dip ;
-METHOD: n*V! { real double-blas-vector }
- (prepare-scal) [ cblas_dscal ] dip ;
-METHOD: n*V! { number float-complex-blas-vector }
- [ (>c-complex) ] dip
- (prepare-scal) [ cblas_cscal ] dip ;
-METHOD: n*V! { number double-complex-blas-vector }
- [ (>z-complex) ] dip
- (prepare-scal) [ cblas_zscal ] dip ;
-
-: n*V+V ( alpha x y -- alpha*x+y ) clone n*V+V! ; inline
-: n*V ( alpha x -- alpha*x ) clone n*V! ; inline
+M: blas-vector-base length
+ length>> ;
+M: blas-vector-base virtual-seq
+ (blas-direct-array) ;
+M: blas-vector-base virtual@
+ [ inc>> * ] [ nip (blas-direct-array) ] 2bi ;
-: V+ ( x y -- x+y )
- 1.0 -rot n*V+V ; inline
-: V- ( x y -- x-y )
- -1.0 spin n*V+V ; inline
+: float>arg ( f -- f ) ; inline
+: double>arg ( f -- f ) ; inline
+: arg>float ( f -- f ) ; inline
+: arg>double ( f -- f ) ; inline
-: Vneg ( x -- -x )
- -1.0 swap n*V ; inline
+<<
-: V*n ( x alpha -- x*alpha )
- swap n*V ; inline
-: V/n ( x alpha -- x/alpha )
- recip swap n*V ; inline
+FUNCTOR: (define-blas-vector) ( TYPE T -- )
-METHOD: V. { float-blas-vector float-blas-vector }
- (prepare-dot) cblas_sdot ;
-METHOD: V. { double-blas-vector double-blas-vector }
- (prepare-dot) cblas_ddot ;
-METHOD: V. { float-complex-blas-vector float-complex-blas-vector }
- (prepare-dot)
- "CBLAS_C" <c-object> [ cblas_cdotu_sub ] keep (c-complex>) ;
-METHOD: V. { double-complex-blas-vector double-complex-blas-vector }
- (prepare-dot)
- "CBLAS_Z" <c-object> [ cblas_zdotu_sub ] keep (z-complex>) ;
-
-METHOD: V.conj { float-blas-vector float-blas-vector }
- (prepare-dot) cblas_sdot ;
-METHOD: V.conj { double-blas-vector double-blas-vector }
- (prepare-dot) cblas_ddot ;
-METHOD: V.conj { float-complex-blas-vector float-complex-blas-vector }
- (prepare-dot)
- "CBLAS_C" <c-object> [ cblas_cdotc_sub ] keep (c-complex>) ;
-METHOD: V.conj { double-complex-blas-vector double-complex-blas-vector }
- (prepare-dot)
- "CBLAS_Z" <c-object> [ cblas_zdotc_sub ] keep (z-complex>) ;
-
-METHOD: Vnorm { float-blas-vector }
- (prepare-nrm2) cblas_snrm2 ;
-METHOD: Vnorm { double-blas-vector }
- (prepare-nrm2) cblas_dnrm2 ;
-METHOD: Vnorm { float-complex-blas-vector }
- (prepare-nrm2) cblas_scnrm2 ;
-METHOD: Vnorm { double-complex-blas-vector }
- (prepare-nrm2) cblas_dznrm2 ;
-
-METHOD: Vasum { float-blas-vector }
- (prepare-nrm2) cblas_sasum ;
-METHOD: Vasum { double-blas-vector }
- (prepare-nrm2) cblas_dasum ;
-METHOD: Vasum { float-complex-blas-vector }
- (prepare-nrm2) cblas_scasum ;
-METHOD: Vasum { double-complex-blas-vector }
- (prepare-nrm2) cblas_dzasum ;
-
-METHOD: Viamax { float-blas-vector }
- (prepare-nrm2) cblas_isamax ;
-METHOD: Viamax { double-blas-vector }
- (prepare-nrm2) cblas_idamax ;
-METHOD: Viamax { float-complex-blas-vector }
- (prepare-nrm2) cblas_icamax ;
-METHOD: Viamax { double-complex-blas-vector }
- (prepare-nrm2) cblas_izamax ;
+<DIRECT-ARRAY> IS <direct-${TYPE}-array>
+>ARRAY IS >${TYPE}-array
+XCOPY IS cblas_${T}copy
+XSWAP IS cblas_${T}swap
+IXAMAX IS cblas_i${T}amax
-: Vamax ( x -- max )
- [ Viamax ] keep nth ; inline
+VECTOR DEFINES ${TYPE}-blas-vector
+<VECTOR> DEFINES <${TYPE}-blas-vector>
+>VECTOR DEFINES >${TYPE}-blas-vector
+
+WHERE
+
+TUPLE: VECTOR < blas-vector-base ;
+: <VECTOR> ( underlying length inc -- vector ) VECTOR boa ; inline
+
+: >VECTOR ( seq -- v )
+ [ >ARRAY execute underlying>> ] [ length ] bi 1 <VECTOR> execute ;
+
+M: VECTOR clone
+ TYPE heap-size (prepare-copy)
+ [ XCOPY execute ] 3dip <VECTOR> execute ;
+
+M: VECTOR element-type
+ drop TYPE ;
+M: VECTOR Vswap
+ (prepare-swap) [ XSWAP execute ] 2dip ;
+M: VECTOR Viamax
+ (prepare-nrm2) IXAMAX execute ;
+
+M: VECTOR (blas-vector-like)
+ drop <VECTOR> execute ;
+
+M: VECTOR (blas-direct-array)
+ [ underlying>> ]
+ [ [ length>> ] [ inc>> ] bi * ] bi
+ <DIRECT-ARRAY> execute ;
+
+;FUNCTOR
+
+
+FUNCTOR: (define-real-blas-vector) ( TYPE T -- )
+
+VECTOR IS ${TYPE}-blas-vector
+XDOT IS cblas_${T}dot
+XNRM2 IS cblas_${T}nrm2
+XASUM IS cblas_${T}asum
+XAXPY IS cblas_${T}axpy
+XSCAL IS cblas_${T}scal
+
+WHERE
+
+M: VECTOR V.
+ (prepare-dot) XDOT execute ;
+M: VECTOR V.conj
+ (prepare-dot) XDOT execute ;
+M: VECTOR Vnorm
+ (prepare-nrm2) XNRM2 execute ;
+M: VECTOR Vasum
+ (prepare-nrm2) XASUM execute ;
+M: VECTOR n*V+V!
+ (prepare-axpy) [ XAXPY execute ] dip ;
+M: VECTOR n*V!
+ (prepare-scal) [ XSCAL execute ] dip ;
+
+;FUNCTOR
+
+
+FUNCTOR: (define-complex-helpers) ( TYPE -- )
+
+<DIRECT-COMPLEX-ARRAY> DEFINES <direct-${TYPE}-complex-array>
+>COMPLEX-ARRAY DEFINES >${TYPE}-complex-array
+ARG>COMPLEX DEFINES arg>${TYPE}-complex
+COMPLEX>ARG DEFINES ${TYPE}-complex>arg
+<DIRECT-ARRAY> IS <direct-${TYPE}-array>
+>ARRAY IS >${TYPE}-array
+
+WHERE
+
+: <DIRECT-COMPLEX-ARRAY> ( alien len -- sequence )
+ 1 shift <DIRECT-ARRAY> execute <complex-sequence> ;
+: >COMPLEX-ARRAY ( sequence -- sequence )
+ <complex-components> >ARRAY execute ;
+: COMPLEX>ARG ( complex -- alien )
+ >rect 2array >ARRAY execute underlying>> ;
+: ARG>COMPLEX ( alien -- complex )
+ 2 <DIRECT-ARRAY> execute first2 rect> ;
+
+;FUNCTOR
+
+
+FUNCTOR: (define-complex-blas-vector) ( TYPE C S -- )
+
+VECTOR IS ${TYPE}-blas-vector
+XDOTU_SUB IS cblas_${C}dotu_sub
+XDOTC_SUB IS cblas_${C}dotc_sub
+XXNRM2 IS cblas_${S}${C}nrm2
+XXASUM IS cblas_${S}${C}asum
+XAXPY IS cblas_${C}axpy
+XSCAL IS cblas_${C}scal
+TYPE>ARG IS ${TYPE}>arg
+ARG>TYPE IS arg>${TYPE}
+
+WHERE
+
+M: VECTOR V.
+ (prepare-dot) TYPE <c-object>
+ [ XDOTU_SUB execute ] keep
+ ARG>TYPE execute ;
+M: VECTOR V.conj
+ (prepare-dot) TYPE <c-object>
+ [ XDOTC_SUB execute ] keep
+ ARG>TYPE execute ;
+M: VECTOR Vnorm
+ (prepare-nrm2) XXNRM2 execute ;
+M: VECTOR Vasum
+ (prepare-nrm2) XXASUM execute ;
+M: VECTOR n*V+V!
+ [ TYPE>ARG execute ] 2dip
+ (prepare-axpy) [ XAXPY execute ] dip ;
+M: VECTOR n*V!
+ [ TYPE>ARG execute ] dip
+ (prepare-scal) [ XSCAL execute ] dip ;
+
+;FUNCTOR
+
+
+: define-real-blas-vector ( TYPE T -- )
+ [ (define-blas-vector) ]
+ [ (define-real-blas-vector) ] 2bi ;
+:: define-complex-blas-vector ( TYPE C S -- )
+ TYPE (define-complex-helpers)
+ TYPE "-complex" append
+ [ C (define-blas-vector) ]
+ [ C S (define-complex-blas-vector) ] bi ;
+
+"float" "s" define-real-blas-vector
+"double" "d" define-real-blas-vector
+"float" "c" "s" define-complex-blas-vector
+"double" "z" "d" define-complex-blas-vector
+
+>>
-: Vsub ( v start length -- sub )
- rot [
- [
- nip [ inc>> ] [ element-type heap-size ] [ data>> ] tri
- [ * * ] dip <displaced-alien>
- ] [ swap 2nip ] [ 2nip inc>> ] 3tri
- ] keep (blas-vector-like) ;
+++ /dev/null
-Slava Pestov
-Doug Coleman
-Aaron Schaefer
+++ /dev/null
-USING: help.markup help.syntax kernel math math.order sequences ;
-IN: math.combinatorics
-
-HELP: factorial
-{ $values { "n" "a non-negative integer" } { "n!" integer } }
-{ $description "Outputs the product of all positive integers less than or equal to " { $snippet "n" } "." }
-{ $examples { $example "USING: math.combinatorics prettyprint ;" "4 factorial ." "24" } } ;
-
-HELP: nPk
-{ $values { "n" "a non-negative integer" } { "k" "a non-negative integer" } { "nPk" integer } }
-{ $description "Outputs the total number of unique permutations of size " { $snippet "k" } " (order does matter) that can be taken from a set of size " { $snippet "n" } "." }
-{ $examples { $example "USING: math.combinatorics prettyprint ;" "10 4 nPk ." "5040" } } ;
-
-HELP: nCk
-{ $values { "n" "a non-negative integer" } { "k" "a non-negative integer" } { "nCk" integer } }
-{ $description "Outputs the total number of unique combinations of size " { $snippet "k" } " (order does not matter) that can be taken from a set of size " { $snippet "n" } ". Commonly written as \"n choose k\"." }
-{ $examples { $example "USING: math.combinatorics prettyprint ;" "10 4 nCk ." "210" } } ;
-
-HELP: permutation
-{ $values { "n" "a non-negative integer" } { "seq" sequence } { "seq" sequence } }
-{ $description "Outputs the " { $snippet "nth" } " lexicographical permutation of " { $snippet "seq" } "." }
-{ $notes "Permutations are 0-based and a bounds error will be thrown if " { $snippet "n" } " is larger than " { $snippet "seq length factorial 1-" } "." }
-{ $examples { $example "USING: math.combinatorics prettyprint ;" "1 3 permutation ." "{ 0 2 1 }" } { $example "USING: math.combinatorics prettyprint ;" "5 { \"apple\" \"banana\" \"orange\" } permutation ." "{ \"orange\" \"banana\" \"apple\" }" } } ;
-
-HELP: all-permutations
-{ $values { "seq" sequence } { "seq" sequence } }
-{ $description "Outputs a sequence containing all permutations of " { $snippet "seq" } " in lexicographical order." }
-{ $examples { $example "USING: math.combinatorics prettyprint ;" "3 all-permutations ." "{ { 0 1 2 } { 0 2 1 } { 1 0 2 } { 1 2 0 } { 2 0 1 } { 2 1 0 } }" } } ;
-
-HELP: inverse-permutation
-{ $values { "seq" sequence } { "permutation" sequence } }
-{ $description "Outputs a sequence of indices representing the lexicographical permutation of " { $snippet "seq" } "." }
-{ $notes "All items in " { $snippet "seq" } " must be comparable by " { $link <=> } "." }
-{ $examples { $example "USING: math.combinatorics prettyprint ;" "\"dcba\" inverse-permutation ." "{ 3 2 1 0 }" } { $example "USING: math.combinatorics prettyprint ;" "{ 12 56 34 78 } inverse-permutation ." "{ 0 2 1 3 }" } } ;
-
-
-IN: math.combinatorics.private
-
-HELP: factoradic
-{ $values { "n" integer } { "factoradic" sequence } }
-{ $description "Converts a positive integer " { $snippet "n" } " to factoradic form. The factoradic of an integer is its representation based on a mixed radix numerical system that corresponds to the values of " { $snippet "n" } " factorial." }
-{ $examples { $example "USING: math.combinatorics.private prettyprint ;" "859 factoradic ." "{ 1 1 0 3 0 1 0 }" } } ;
-
-HELP: >permutation
-{ $values { "factoradic" sequence } { "permutation" sequence } }
-{ $description "Converts an integer represented in factoradic form into its corresponding unique permutation (0-based)." }
-{ $notes "For clarification, the following two statements are equivalent:" { $code "10 factoradic >permutation" "{ 1 2 0 0 } >permutation" } }
-{ $examples { $example "USING: math.combinatorics.private prettyprint ;" "{ 0 0 0 0 } >permutation ." "{ 0 1 2 3 }" } } ;
-
+++ /dev/null
-USING: math.combinatorics math.combinatorics.private tools.test ;
-IN: math.combinatorics.tests
-
-[ { } ] [ 0 factoradic ] unit-test
-[ { 1 0 } ] [ 1 factoradic ] unit-test
-[ { 1 1 0 3 0 1 0 } ] [ 859 factoradic ] unit-test
-
-[ { 0 1 2 3 } ] [ { 0 0 0 0 } >permutation ] unit-test
-[ { 0 1 3 2 } ] [ { 0 0 1 0 } >permutation ] unit-test
-[ { 1 2 0 6 3 5 4 } ] [ { 1 1 0 3 0 1 0 } >permutation ] unit-test
-
-[ { 0 1 2 3 } ] [ 0 4 permutation-indices ] unit-test
-[ { 0 1 3 2 } ] [ 1 4 permutation-indices ] unit-test
-[ { 1 2 0 6 3 5 4 } ] [ 859 7 permutation-indices ] unit-test
-
-[ 1 ] [ 0 factorial ] unit-test
-[ 1 ] [ 1 factorial ] unit-test
-[ 3628800 ] [ 10 factorial ] unit-test
-
-[ 1 ] [ 3 0 nPk ] unit-test
-[ 6 ] [ 3 2 nPk ] unit-test
-[ 6 ] [ 3 3 nPk ] unit-test
-[ 0 ] [ 3 4 nPk ] unit-test
-[ 311875200 ] [ 52 5 nPk ] unit-test
-[ 672151459757865654763838640470031391460745878674027315200000000000 ] [ 52 47 nPk ] unit-test
-
-[ 1 ] [ 3 0 nCk ] unit-test
-[ 3 ] [ 3 2 nCk ] unit-test
-[ 1 ] [ 3 3 nCk ] unit-test
-[ 0 ] [ 3 4 nCk ] unit-test
-[ 2598960 ] [ 52 5 nCk ] unit-test
-[ 2598960 ] [ 52 47 nCk ] unit-test
-
-[ { "a" "b" "c" "d" } ] [ 0 { "a" "b" "c" "d" } permutation ] unit-test
-[ { "d" "c" "b" "a" } ] [ 23 { "a" "b" "c" "d" } permutation ] unit-test
-[ { "d" "a" "b" "c" } ] [ 18 { "a" "b" "c" "d" } permutation ] unit-test
-
-[ { { "a" "b" "c" } { "a" "c" "b" }
- { "b" "a" "c" } { "b" "c" "a" }
- { "c" "a" "b" } { "c" "b" "a" } } ] [ { "a" "b" "c" } all-permutations ] unit-test
-
-[ { 0 1 2 } ] [ { "a" "b" "c" } inverse-permutation ] unit-test
-[ { 2 1 0 } ] [ { "c" "b" "a" } inverse-permutation ] unit-test
-[ { 3 0 2 1 } ] [ { 12 45 34 2 } inverse-permutation ] unit-test
-
+++ /dev/null
-! 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 fry ;
-IN: math.combinatorics
-
-<PRIVATE
-
-: possible? ( n m -- ? )
- 0 rot between? ; inline
-
-: twiddle ( n k -- n k )
- 2dup - dupd > [ dupd - ] when ; inline
-
-! See this article for explanation of the factoradic-based permutation methodology:
-! http://msdn2.microsoft.com/en-us/library/aa302371.aspx
-
-: factoradic ( n -- factoradic )
- 0 [ over 0 > ] [ 1+ [ /mod ] keep swap ] [ ] produce reverse 2nip ;
-
-: (>permutation) ( seq n -- seq )
- [ '[ _ dupd >= [ 1+ ] when ] map ] keep prefix ;
-
-: >permutation ( factoradic -- permutation )
- reverse 1 cut [ (>permutation) ] each ;
-
-: permutation-indices ( n seq -- permutation )
- length [ factoradic ] dip 0 pad-left >permutation ;
-
-PRIVATE>
-
-: factorial ( n -- n! )
- 1 [ 1+ * ] reduce ;
-
-: nPk ( n k -- nPk )
- 2dup possible? [ dupd - [a,b) product ] [ 2drop 0 ] if ;
-
-: nCk ( n k -- nCk )
- twiddle [ nPk ] keep factorial / ;
-
-: permutation ( n seq -- seq )
- [ permutation-indices ] keep nths ;
-
-: all-permutations ( seq -- seq )
- [ length factorial ] keep '[ _ permutation ] map ;
-
-: each-permutation ( seq quot -- )
- [ [ length factorial ] keep ] dip
- '[ _ permutation @ ] each ; inline
-
-: reduce-permutations ( seq initial quot -- result )
- swapd each-permutation ; inline
-
-: inverse-permutation ( seq -- permutation )
- <enum> >alist sort-values keys ;
+++ /dev/null
-Permutations and combinations
+++ /dev/null
-Reginald Ford
-Eduardo Cavazos
\ No newline at end of file
+++ /dev/null
-USING: help.markup help.syntax math math.functions ;
-IN: math.derivatives
-
-HELP: derivative ( x function -- m )
-{ $values { "x" "a position on the function" } { "function" "a differentiable function" } { "m" number } }
-{ $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 math.derivatives prettyprint ;"
- "4 [ sq ] derivative >integer ."
- "8"
- }
- { $notes
- "For applied scientists, you may play with the settings "
- "in the source file to achieve arbitrary accuracy. "
- }
-} ;
-
-HELP: (derivative)
-{ $values
- { "x" "a position on the function" }
- { "func" "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."
- }
- { "ans" number }
- { "error" number }
-}
-{ $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 math.derivatives prettyprint ;"
- "4 [ sq ] derivative >integer ."
- "8"
- }
- { $notes
- "For applied scientists, you may play with the settings "
- "in the source file to achieve arbitrary accuracy. "
- }
-} ;
-
-HELP: derivative-func
-{ $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: kernel math.derivatives math.functions math.trig prettyprint ;"
- "60 deg>rad [ sin ] derivative-func call 0.5 .001 ~ ."
- "t"
- }
- { $notes
- "Without a heavy algebraic system, derivatives must be "
- "approximated. With the current settings, there is a fair trade of "
- "speed and accuracy; the first 12 digits "
- "will always be correct with " { $link sin } " and " { $link cos }
- ". The following code performs a minumum and maximum error test."
- { $code
- "USING: kernel math math.functions math.trig sequences sequences.lib ;"
- "360"
- "["
- " deg>rad"
- " [ [ sin ] derivative-func call ]"
- " ! Note: the derivative of sin is cos"
- " [ cos ]"
- " bi - abs"
- "] map minmax"
-
- }
- }
-} ;
-
-ARTICLE: "derivatives" "The Derivative Toolkit"
-"A toolkit for computing the derivative of functions."
-{ $subsection derivative }
-{ $subsection derivative-func }
-{ $subsection (derivative) } ;
-ABOUT: "derivatives"
+++ /dev/null
-USING: math math.derivatives tools.test ;
-IN: math.derivatives.test
-
-[ 8 ] [ 4 [ sq ] derivative >integer ] unit-test
-
+++ /dev/null
-! Copyright (c) 2008 Reginald Keith Ford II, Eduardo Cavazos.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel continuations combinators sequences math math.order math.ranges
- accessors float-arrays ;
-IN: math.derivatives
-
-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 ; inline
-: con ( -- val ) 1.6 ; inline
-: con2 ( -- val ) con con * ; inline
-: big ( -- val ) largest-float ; inline
-: safe ( -- val ) 2.0 ; inline
-
-! 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 ;
-! Copyright (C) 2008 John Benediktsson
+! Copyright (C) 2008 John Benediktsson, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license
-
-USING: help.markup help.syntax ;
-
+USING: help.markup help.syntax math ;
IN: math.finance
HELP: sma
{ $list "MOM[t] = SEQ[t] - SEQ[t-n]" }
} ;
+HELP: biweekly
+{ $values
+ { "x" number }
+ { "y" number }
+}
+{ $description "Divides a number by the number of two week periods in a year." } ;
+
+HELP: daily-360
+{ $values
+ { "x" number }
+ { "y" number }
+}
+{ $description "Divides a number by the number of days in a 360-day year." } ;
+
+HELP: daily-365
+{ $values
+ { "x" number }
+ { "y" number }
+}
+{ $description "Divides a number by the number of days in a 365-day year." } ;
+
+HELP: monthly
+{ $values
+ { "x" number }
+ { "y" number }
+}
+{ $description "Divides a number by the number of months in a year." } ;
+
+HELP: semimonthly
+{ $values
+ { "x" number }
+ { "y" number }
+}
+{ $description "Divides a number by the number of half-months in a year. Note that biweekly has two more periods than semimonthly." } ;
+
+HELP: weekly
+{ $values
+ { "x" number }
+ { "y" number }
+}
+{ $description "Divides a number by the number of weeks in a year." } ;
+
+ARTICLE: "time-period-calculations" "Calculations over periods of time"
+{ $subsection monthly }
+{ $subsection semimonthly }
+{ $subsection biweekly }
+{ $subsection weekly }
+{ $subsection daily-360 }
+{ $subsection daily-365 } ;
+
+ARTICLE: "math.finance" "Financial math"
+"The " { $vocab-link "math.finance" } " vocabulary contains financial calculation words." $nl
+"Calculating payroll over periods of time:"
+{ $subsection "time-period-calculations" } ;
+
+ABOUT: "math.finance"
[ { 1 3 1 } ] [ { 1 3 2 6 3 } 2 momentum ] unit-test
+[ 4+1/6 ] [ 100 semimonthly ] unit-test
-! Copyright (C) 2008 John Benediktsson.
+! Copyright (C) 2008 John Benediktsson, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays assocs kernel grouping sequences shuffle
math math.functions math.statistics math.vectors ;
: momentum ( seq n -- newseq )
[ tail-slice ] 2keep [ dup length ] dip - head-slice v- ;
+: monthly ( x -- y ) 12 / ; inline
+
+: semimonthly ( x -- y ) 24 / ; inline
+
+: biweekly ( x -- y ) 26 / ; inline
+
+: weekly ( x -- y ) 52 / ; inline
+
+: daily-360 ( x -- y ) 360 / ; inline
+
+: daily-365 ( x -- y ) 365 / ; inline
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
-USING: tools.test math.floating-point ;
+USING: tools.test math.floating-point math.constants kernel
+math.constants fry sequences kernel math ;
IN: math.floating-point.tests
+
+[ t ] [ pi >double< >double pi = ] unit-test
+[ t ] [ -1.0 >double< >double -1.0 = ] unit-test
+
+[ t ] [ 1/0. infinity? ] unit-test
+[ t ] [ -1/0. infinity? ] unit-test
+[ f ] [ 0/0. infinity? ] unit-test
+[ f ] [ 10. infinity? ] unit-test
+[ f ] [ -10. infinity? ] unit-test
+[ f ] [ 0. infinity? ] unit-test
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math sequences prettyprint math.parser io
-math.functions ;
+math.functions math.bitwise combinators.short-circuit ;
IN: math.floating-point
: (double-sign) ( bits -- n ) -63 shift ; inline
: double-sign ( double -- n ) double>bits (double-sign) ;
: (double-exponent-bits) ( bits -- n )
- -52 shift 11 2^ 1- bitand ; inline
+ -52 shift 11 on-bits mask ; inline
: double-exponent-bits ( double -- n )
double>bits (double-exponent-bits) ;
: (double-mantissa-bits) ( double -- n )
- 52 2^ 1- bitand ;
+ 52 on-bits mask ;
: double-mantissa-bits ( double -- n )
double>bits (double-mantissa-bits) ;
11 [ bl ] times print
] tri ;
+: infinity? ( double -- ? )
+ double>bits
+ {
+ [ (double-exponent-bits) 11 on-bits = ]
+ [ (double-mantissa-bits) 0 = ]
+ } 1&& ;
[ { 0 0 -1 } ] [ { 1 0 0 } { 0 1 0 } cross ] unit-test
[ { 1 0 0 } ] [ { 0 1 0 } { 0 0 1 } cross ] unit-test
[ { 0 1 0 } ] [ { 0 0 1 } { 1 0 0 } cross ] unit-test
+
+[ { 1 0 0 } ] [ { 1 1 0 } { 1 0 0 } proj ] unit-test
+++ /dev/null
-Reginald Ford
\ No newline at end of file
+++ /dev/null
-! Copyright (c) 2008 Reginald Keith Ford II.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel math math.derivatives ;
-IN: math.newtons-method
-
-! Newton's method of approximating roots
-
-<PRIVATE
-
-: newton-step ( x function -- x2 )
- dupd [ call ] [ derivative ] 2bi / - ; inline
-
-: newton-precision ( -- n ) 13 ; inline
-
-PRIVATE>
-
-: newtons-method ( guess function -- x )
- newton-precision [ [ newton-step ] keep ] times drop ;
math.vectors vectors ;
IN: math.numerical-integration
-SYMBOL: num-steps 180 num-steps set-global
+SYMBOL: num-steps
+
+180 num-steps set-global
: setup-simpson-range ( from to -- frange )
2dup swap - num-steps get / <range> ;
: generate-simpson-weights ( seq -- seq )
- { 1 4 }
- swap length 2 / 2 - { 2 4 } <repetition> concat
- { 1 } 3append ;
+ length 2 / 2 - { 2 4 } <repetition> concat
+ { 1 4 } { 1 } surround ;
: integrate-simpson ( from to f -- x )
[ setup-simpson-range dup ] dip
+++ /dev/null
-Doug Coleman
+++ /dev/null
-IN: math.polynomials.tests
-USING: kernel math math.polynomials tools.test ;
-
-! Tests
-[ { 0 1 } ] [ { 0 1 0 0 } ptrim ] unit-test
-[ { 1 } ] [ { 1 0 0 } ptrim ] unit-test
-[ { 0 } ] [ { 0 } ptrim ] unit-test
-[ { 3 10 8 } ] [ { 1 2 } { 3 4 } p* ] unit-test
-[ { 3 10 8 } ] [ { 3 4 } { 1 2 } p* ] unit-test
-[ { 0 0 0 0 0 0 0 0 0 0 } ] [ { 0 0 0 } { 0 0 0 0 0 0 0 0 } p* ] unit-test
-[ { 0 1 } ] [ { 0 1 } { 1 } p* ] unit-test
-[ { 0 } ] [ { } { } p* ] unit-test
-[ { 0 } ] [ { 0 } { } p* ] unit-test
-[ { 0 } ] [ { } { 0 } p* ] unit-test
-[ { 0 0 0 } ] [ { 0 0 0 } { 0 0 0 } p+ ] unit-test
-[ { 0 0 0 } ] [ { 0 0 0 } { 0 0 0 } p- ] unit-test
-[ { 0 0 0 } ] [ 4 { 0 0 0 } n*p ] unit-test
-[ { 4 8 0 12 } ] [ 4 { 1 2 0 3 } n*p ] unit-test
-[ { 1 4 7 6 0 0 0 0 0 } ] [ { 1 2 3 0 0 0 } { 1 2 0 0 } p* ] unit-test
-[ V{ 7 -2 1 } V{ -20 0 0 } ] [ { 1 1 1 1 } { 3 1 } p/mod ] unit-test
-[ V{ 0 0 } V{ 1 1 } ] [ { 1 1 } { 1 1 1 1 } p/mod ] unit-test
-[ V{ 1 0 1 } V{ 0 0 0 } ] [ { 1 1 1 1 } { 1 1 } p/mod ] unit-test
-[ V{ 1 0 1 } V{ 0 0 0 } ] [ { 1 1 1 1 } { 1 1 0 0 0 0 0 0 } p/mod ] unit-test
-[ V{ 1 0 1 } V{ 0 0 0 } ] [ { 1 1 1 1 0 0 0 0 } { 1 1 0 0 } p/mod ] unit-test
-[ V{ 5.0 } V{ 0 } ] [ { 10.0 } { 2.0 } p/mod ] unit-test
-[ V{ 15/16 } V{ 0 } ] [ { 3/4 } { 4/5 } p/mod ] unit-test
-[ t ] [ { 0 1 } { 0 1 0 } p= ] unit-test
-[ f ] [ { 0 0 1 } { 0 1 0 } p= ] unit-test
-[ t ] [ { 1 1 1 } { 1 1 1 } p= ] unit-test
-[ { 0 0 } { 1 1 } ] [ { 1 1 1 1 } { 1 1 } pgcd ] unit-test
-
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: arrays kernel make math math.order math.vectors sequences shuffle
- splitting vectors ;
-IN: math.polynomials
-
-! Polynomials are vectors with the highest powers on the right:
-! { 1 1 0 1 } -> 1 + x + x^3
-! { } -> 0
-
-: powers ( n x -- seq )
- #! Output sequence has n elements, { 1 x x^2 x^3 ... }
- <array> 1 [ * ] accumulate nip ;
-
-<PRIVATE
-
-: 2pad-left ( p p n -- p p ) [ 0 pad-left ] curry bi@ ;
-: 2pad-right ( p p n -- p p ) [ 0 pad-right ] curry bi@ ;
-: pextend ( p p -- p p ) 2dup [ length ] bi@ max 2pad-right ;
-: pextend-left ( p p -- p p ) 2dup [ length ] bi@ max 2pad-left ;
-: unempty ( seq -- seq ) [ { 0 } ] when-empty ;
-: 2unempty ( seq seq -- seq seq ) [ unempty ] bi@ ;
-
-PRIVATE>
-
-: p= ( p p -- ? ) pextend = ;
-
-: ptrim ( p -- p )
- dup length 1 = [ [ zero? ] trim-right ] unless ;
-
-: 2ptrim ( p p -- p p ) [ ptrim ] bi@ ;
-: p+ ( p p -- p ) pextend v+ ;
-: p- ( p p -- p ) pextend v- ;
-: n*p ( n p -- n*p ) n*v ;
-
-! convolution
-: pextend-conv ( p p -- p p )
- #! extend to: p_m + p_n - 1
- 2dup [ length ] bi@ + 1- 2pad-right [ >vector ] bi@ ;
-
-: p* ( p p -- p )
- #! Multiply two polynomials.
- 2unempty pextend-conv <reversed> dup length
- [ over length pick <slice> pick [ * ] 2map sum ] map 2nip reverse ;
-
-: p-sq ( p -- p-sq )
- dup p* ;
-
-<PRIVATE
-
-: p/mod-setup ( p p -- p p n )
- 2ptrim
- 2dup [ length ] bi@ -
- dup 1 < [ drop 1 ] when
- [ over length + 0 pad-left pextend ] keep 1+ ;
-
-: /-last ( seq seq -- a )
- #! divide the last two numbers in the sequences
- [ peek ] bi@ / ;
-
-: (p/mod) ( p p -- p p )
- 2dup /-last
- 2dup , n*p swapd
- p- >vector
- dup pop* swap rest-slice ;
-
-PRIVATE>
-
-: p/mod ( a b -- / mod )
- p/mod-setup [ [ (p/mod) ] times ] V{ } make
- reverse nip swap 2ptrim pextend ;
-
-: (pgcd) ( b a y x -- a d )
- dup V{ 0 } clone p= [
- drop nip
- ] [
- tuck p/mod [ pick p* swap [ swapd p- ] dip ] dip (pgcd)
- ] if ;
-
-: pgcd ( p p -- p q )
- swap V{ 0 } clone V{ 1 } clone 2swap (pgcd) [ >array ] bi@ ;
-
-: pdiff ( p -- p' )
- #! Polynomial derivative.
- dup length v* { 0 } ?head drop ;
-
-: polyval ( p x -- p[x] )
- #! Evaluate a polynomial.
- [ dup length ] dip powers v. ;
-
+++ /dev/null
-Polynomial arithmetic
+++ /dev/null
-Slava Pestov
+++ /dev/null
-IN: math.quaternions.tests
-USING: tools.test math.quaternions kernel math.vectors
-math.constants ;
-
-[ 1.0 ] [ qi norm ] unit-test
-[ 1.0 ] [ qj norm ] unit-test
-[ 1.0 ] [ qk norm ] unit-test
-[ 1.0 ] [ q1 norm ] unit-test
-[ 0.0 ] [ q0 norm ] unit-test
-[ t ] [ qi qj q* qk = ] unit-test
-[ t ] [ qj qk q* qi = ] unit-test
-[ t ] [ qk qi q* qj = ] unit-test
-[ t ] [ qi qi q* q1 v+ q0 = ] unit-test
-[ t ] [ qj qj q* q1 v+ q0 = ] unit-test
-[ t ] [ qk qk q* q1 v+ q0 = ] unit-test
-[ t ] [ qi qj qk q* q* q1 v+ q0 = ] unit-test
-[ t ] [ C{ 0 1 } qj n*v qk = ] unit-test
-[ t ] [ qj C{ 0 1 } q*n qk v+ q0 = ] unit-test
-[ t ] [ qk qj q/ qi = ] unit-test
-[ t ] [ qi qk q/ qj = ] unit-test
-[ t ] [ qj qi q/ qk = ] unit-test
-[ t ] [ qi q>v v>q qi = ] unit-test
-[ t ] [ qj q>v v>q qj = ] unit-test
-[ t ] [ qk q>v v>q qk = ] unit-test
-[ t ] [ 1 c>q q1 = ] unit-test
-[ t ] [ C{ 0 1 } c>q qi = ] unit-test
+++ /dev/null
-! Copyright (C) 2005, 2007 Slava Pestov.
-! See http://factorcode.org/license.txt for BSD license.
-
-! Everybody's favorite non-commutative skew field, the
-! quaternions!
-
-! Quaternions are represented as pairs of complex numbers,
-! using the identity: (a+bi)+(c+di)j = a+bi+cj+dk.
-USING: arrays kernel math math.vectors math.functions
-arrays sequences ;
-IN: math.quaternions
-
-<PRIVATE
-
-: ** conjugate * ; inline
-
-: 2q ( u v -- u' u'' v' v'' ) [ first2 ] bi@ ; inline
-
-: q*a ( u v -- a ) 2q swapd ** [ * ] dip - ; inline
-
-: q*b ( u v -- b ) 2q [ ** swap ] dip * + ; inline
-
-PRIVATE>
-
-: q* ( u v -- u*v )
- #! Multiply quaternions.
- [ q*a ] [ q*b ] 2bi 2array ;
-
-: qconjugate ( u -- u' )
- #! Quaternion conjugate.
- first2 [ conjugate ] [ neg ] bi* 2array ;
-
-: qrecip ( u -- 1/u )
- #! Quaternion inverse.
- qconjugate dup norm-sq v/n ;
-
-: q/ ( u v -- u/v )
- #! Divide quaternions.
- qrecip q* ;
-
-: q*n ( q n -- q )
- #! Note: you will get the wrong result if you try to
- #! multiply a quaternion by a complex number on the right
- #! using v*n. Use this word instead. Note that v*n with a
- #! quaternion and a real is okay.
- conjugate v*n ;
-
-: c>q ( c -- q )
- #! Turn a complex number into a quaternion.
- 0 2array ;
-
-: v>q ( v -- q )
- #! Turn a 3-vector into a quaternion with real part 0.
- first3 rect> [ 0 swap rect> ] dip 2array ;
-
-: q>v ( q -- v )
- #! Get the vector part of a quaternion, discarding the real
- #! part.
- first2 [ imaginary-part ] dip >rect 3array ;
-
-! Zero
-: q0 { 0 0 } ;
-
-! Units
-: q1 { 1 0 } ;
-: qi { C{ 0 1 } 0 } ;
-: qj { 0 1 } ;
-: qk { 0 C{ 0 1 } } ;
-
-! Euler angles -- see
-! http://www.mathworks.com/access/helpdesk/help/toolbox/aeroblks/euleranglestoquaternions.html
-
-: (euler) ( theta unit -- q )
- [ -0.5 * dup cos c>q swap sin ] dip n*v v- ;
-
-: euler ( phi theta psi -- q )
- [ qi (euler) ] [ qj (euler) ] [ qk (euler) ] tri* q* q* ;
+++ /dev/null
-Quaternion arithmetic and Euler angles
+++ /dev/null
-Doug Coleman
-Michael Judge
+++ /dev/null
-USING: help.markup help.syntax debugger ;
-IN: math.statistics
-
-HELP: geometric-mean
-{ $values { "seq" "a sequence of numbers" } { "n" "a non-negative real number"} }
-{ $description "Computes the geometric mean of all elements in " { $snippet "seq" } ". The geometric mean measures the central tendency of a data set that minimizes the effects of extreme values." }
-{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } geometric-mean ." "1.81712059283214" } }
-{ $errors "Throws a " { $link signal-error. } " (square-root of 0) if the sequence is empty." } ;
-
-HELP: harmonic-mean
-{ $values { "seq" "a sequence of numbers" } { "n" "a non-negative real number"} }
-{ $description "Computes the harmonic mean of the elements in " { $snippet "seq" } ". The harmonic mean is appropriate when the average of rates is desired." }
-{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } harmonic-mean ." "6/11" } }
-{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
-
-HELP: mean
-{ $values { "seq" "a sequence of numbers" } { "n" "a non-negative real number"} }
-{ $description "Computes the arithmetic mean of all elements in " { $snippet "seq" } "." }
-{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } mean ." "2" } }
-{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
-
-HELP: median
-{ $values { "seq" "a sequence of numbers" } { "n" "a non-negative real number"} }
-{ $description "Computes the median of " { $snippet "seq" } " by sorting the sequence from lowest value to highest and outputting the middle one. If there is an even number of elements in the sequence, the median is not unique, so the mean of the two middle values is outputted." }
-{ $examples
- { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } median ." "2" }
- { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } median ." "2+1/2" } }
-{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
-
-HELP: range
-{ $values { "seq" "a sequence of numbers" } { "n" "a non-negative real number"} }
-{ $description "Computes the distance of the maximum and minimum values in " { $snippet "seq" } "." }
-{ $examples
- { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } range ." "2" }
- { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } range ." "3" } } ;
-
-HELP: std
-{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
-{ $description "Computes the standard deviation of " { $snippet "seq" } " by squaring the variance of the sequence. It measures how widely spread the values in a sequence are about the mean." }
-{ $examples
- { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } std ." "1.0" }
- { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } std ." "1.290994448735806" } } ;
-
-HELP: ste
- { $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
- { $description "Computes the standard error of the mean for " { $snippet "seq" } ". It's defined as the standard deviation divided by the square root of the length of the sequence, and measures uncertainty associated with the estimate of the mean." }
- { $examples
- { $example "USING: math.statistics prettyprint ;" "{ -2 2 } ste ." "2.0" }
- { $example "USING: math.statistics prettyprint ;" "{ -2 2 2 } ste ." "1.333333333333333" } } ;
-
-HELP: var
-{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
-{ $description "Computes the variance of " { $snippet "seq" } ". It's a measurement of the spread of values in a sequence. The larger the variance, the larger the distance of values from the mean." }
-{ $notes "If the number of elements in " { $snippet "seq" } " is 1 or less, it outputs 0." }
-{ $examples
- { $example "USING: math.statistics prettyprint ;" "{ 1 } var ." "0" }
- { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } var ." "1" }
- { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } var ." "1+2/3" } } ;
-
+++ /dev/null
-USING: kernel math math.functions math.statistics tools.test ;
-IN: math.statistics.tests
-
-[ 1 ] [ { 1 } mean ] unit-test
-[ 3/2 ] [ { 1 2 } mean ] unit-test
-[ 0 ] [ { 0 0 0 } geometric-mean ] unit-test
-[ t ] [ { 2 2 2 2 } geometric-mean 2.0 .0001 ~ ] unit-test
-[ 1.0 ] [ { 1 1 1 } geometric-mean ] unit-test
-[ 1/3 ] [ { 1 1 1 } harmonic-mean ] unit-test
-
-[ 0 ] [ { 1 } range ] unit-test
-[ 89 ] [ { 1 2 30 90 } range ] unit-test
-[ 2 ] [ { 1 2 3 } median ] unit-test
-[ 5/2 ] [ { 1 2 3 4 } median ] unit-test
-
-[ 1 ] [ { 1 2 3 } var ] unit-test
-[ 1.0 ] [ { 1 2 3 } std ] unit-test
-[ t ] [ { 1 2 3 4 } ste 0.6454972243679028 - .0001 < ] unit-test
-
-[ t ] [ { 23.2 33.4 22.5 66.3 44.5 } std 18.1906 - .0001 < ] unit-test
-
-[ 0 ] [ { 1 } var ] unit-test
-[ 0.0 ] [ { 1 } std ] unit-test
-[ 0.0 ] [ { 1 } ste ] unit-test
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman, Michael Judge.
-! See http://factorcode.org/license.txt for BSD license.
-USING: arrays kernel math math.analysis math.functions sequences sequences.lib
- sorting ;
-IN: math.statistics
-
-: mean ( seq -- n )
- #! arithmetic mean, sum divided by length
- [ sum ] [ length ] bi / ;
-
-: geometric-mean ( seq -- n )
- #! geometric mean, nth root of product
- [ length ] [ product ] bi nth-root ;
-
-: harmonic-mean ( seq -- n )
- #! harmonic mean, reciprocal of sum of reciprocals.
- #! positive reals only
- [ recip ] sigma recip ;
-
-: median ( seq -- n )
- #! middle number if odd, avg of two middle numbers if even
- natural-sort dup length even? [
- [ midpoint@ dup 1- 2array ] keep nths mean
- ] [
- [ midpoint@ ] keep nth
- ] if ;
-
-: range ( seq -- n )
- #! max - min
- minmax swap - ;
-
-: var ( seq -- x )
- #! variance, normalize by N-1
- dup length 1 <= [
- drop 0
- ] [
- [ [ mean ] keep [ - sq ] with sigma ] keep
- length 1- /
- ] if ;
-
-: std ( seq -- x )
- #! standard deviation, sqrt of variance
- var sqrt ;
-
-: ste ( seq -- x )
- #! standard error, standard deviation / sqrt ( length of sequence )
- [ std ] [ length ] bi sqrt / ;
-
-: ((r)) ( mean(x) mean(y) {x} {y} -- (r) )
- ! finds sigma((xi-mean(x))(yi-mean(y))
- 0 [ [ [ pick ] dip swap - ] bi@ * + ] 2reduce 2nip ;
-
-: (r) ( mean(x) mean(y) {x} {y} sx sy -- r )
- * recip [ [ ((r)) ] keep length 1- / ] dip * ;
-
-: [r] ( {{x,y}...} -- mean(x) mean(y) {x} {y} sx sy )
- first2 [ [ [ mean ] bi@ ] 2keep ] 2keep [ std ] bi@ ;
-
-: r ( {{x,y}...} -- r )
- [r] (r) ;
-
-: r^2 ( {{x,y}...} -- r )
- r sq ;
-
-: least-squares ( {{x,y}...} -- alpha beta )
- [r] >r >r >r >r 2dup r> r> r> r>
- ! stack is mean(x) mean(y) mean(x) mean(y) {x} {y} sx sy
- [ (r) ] 2keep ! stack is mean(x) mean(y) r sx sy
- swap / * ! stack is mean(x) mean(y) beta
- [ swapd * - ] keep ;
-
+++ /dev/null
-Mean, median, standard deviation, and other statistical routines
: text-with-scale ( index seq -- str )
[ nth 3digits>text ] [ drop scale-numbers ] 2bi
- [ " " swap 3append ] unless-empty ;
+ [ " " glue ] unless-empty ;
: append-with-conjunction ( str1 str2 -- newstr )
over length zero? [
! From http://www.ffconsultancy.com/ocaml/maze/index.html
USING: sequences namespaces math math.vectors opengl opengl.gl
-opengl.demo-support arrays kernel random ui ui.gadgets
-ui.gadgets.canvas ui.render math.order math.geometry.rect ;
+arrays kernel random ui ui.gadgets ui.gadgets.canvas ui.render
+math.order math.geometry.rect ;
IN: maze
: line-width 8 ;
: (draw-maze) ( cell -- )
dup vertex
glEnd
- GL_POINTS [ dup vertex ] do-state
+ GL_POINTS glBegin dup vertex glEnd
GL_LINE_STRIP glBegin
dup vertex
dup visit
] if ;
: draw-maze ( n -- )
- -0.5 0.5 0 glTranslated
line-width 2 - glLineWidth
line-width 2 - glPointSize
1.0 1.0 1.0 1.0 glColor4d
+++ /dev/null
-Phil Dawes
+++ /dev/null
-IN: micros.backend
-USING: io.backend ;
-
-HOOK: (micros) io-backend ( -- n )
+++ /dev/null
-IN: micros
-USING: help.syntax help.markup kernel prettyprint sequences ;
-
-HELP: micros
-{ $values { "n" "an integer" } }
-{ $description "Outputs the number of microseconds ellapsed since midnight January 1, 1970"
-} ;
-
-
-HELP: micro-time
-{ $values { "quot" "a quot" }
- { "n" "an integer" } }
-{ $description "executes the quotation and pushes the number of microseconds taken onto the stack"
-} ;
+++ /dev/null
-IN: micros.tests
-USING: micros tools.test math math.functions system kernel ;
-
-! a bit racy but I can't think of a better way to check this right now
-[ t ]
-[ millis 1000 / micros 1000000 / [ truncate ] bi@ = ] unit-test
-
+++ /dev/null
-IN: micros
-USING: micros.backend system kernel combinators vocabs.loader math ;
-
-: micros ( -- n ) (micros) ; inline
-
-: micro-time ( quot -- n )
- micros slip micros swap - ; inline
-
-{
- { [ os unix? ] [ "micros.unix" ] }
- { [ os windows? ] [ "micros.windows" ] }
-} cond require
-
+++ /dev/null
-Microsecond precision clock
+++ /dev/null
-unportable
+++ /dev/null
-IN: micros.unix
-USING: micros.backend io.backend system alien.c-types kernel unix.time math ;
-
-M: unix (micros)
- "timespec" <c-object> dup f gettimeofday drop
- [ timespec-sec 1000000 * ] [ timespec-nsec ] bi + ;
+++ /dev/null
-unportable
+++ /dev/null
-IN: micros.windows
-USING: system kernel windows.time math math.functions micros.backend ;
-
-! 116444736000000000 is the windowstime epoch offset
-! since windowstime starts at 1600 and unix epoch is 1970
-M: windows (micros)
- windows-time 116444736000000000 - 10 / truncate ;
\ No newline at end of file
-USING: tools.test monads math kernel sequences lists promises ;
+USING: tools.test math kernel sequences lists promises monads ;
IN: monads.tests
[ 5 ] [ 1 identity-monad return [ 4 + ] fmap run-identity ] unit-test
[ 1/10 ] [ DECIMAL: .1 ] unit-test
[ 1/10 ] [ DECIMAL: 0.1 ] unit-test
[ 1/10 ] [ DECIMAL: 00.10 ] unit-test
-
-
+[ 23 ] [ DECIMAL: 23 ] unit-test
+[ -23 ] [ DECIMAL: -23 ] unit-test
+[ -23-1/100 ] [ DECIMAL: -23.01 ] unit-test
[ "DECIMAL: ." eval ] must-fail
[ "DECIMAL: f" eval ] must-fail
[ "DECIMAL: 0.f" eval ] must-fail
[ "DECIMAL: f.0" eval ] must-fail
+
+[ "$100.00" ] [ DECIMAL: 100.0 money>string ] unit-test
+[ "$0.00" ] [ DECIMAL: 0.0 money>string ] unit-test
continuations ;
IN: money
+SYMBOL: currency-token
+CHAR: $ \ currency-token set-global
+
: dollars/cents ( dollars -- dollars cents )
100 * 100 /mod round ;
+: (money>string) ( dollars cents -- string )
+ [ number>string ] bi@
+ [ <reversed> 3 group "," join <reversed> ]
+ [ 2 CHAR: 0 pad-left ] bi* "." glue ;
+
: money>string ( object -- string )
- dollars/cents [
- "$" %
- swap number>string
- <reversed> 3 group "," join <reversed> %
- "." % number>string 2 CHAR: 0 pad-left %
- ] "" make ;
+ dollars/cents (money>string) currency-token get prefix ;
-: money. ( object -- )
- money>string print ;
+: money. ( object -- ) money>string print ;
-ERROR: not-a-decimal x ;
+ERROR: not-an-integer x ;
: parse-decimal ( str -- ratio )
"." split1
- >r dup "-" head? [ drop t "0" ] [ f swap ] if r>
+ [ "-" ?head swap ] dip
[ [ "0" ] when-empty ] bi@
- dup length
- >r [ dup string>number [ nip ] [ not-a-decimal ] if* ] bi@ r>
+ [
+ [ dup string>number [ nip ] [ not-an-integer ] if* ] bi@
+ ] keep length
10 swap ^ / + swap [ neg ] when ;
: DECIMAL:
+++ /dev/null
-Alex Chapman
+++ /dev/null
-! Copyright (C) 2007 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: help.markup help.syntax ;
-IN: morse
-
-HELP: ch>morse
-{ $values
- { "ch" "A character that has a morse code translation" } { "str" "A string consisting of zero or more dots and dashes" } }
-{ $description "If the given character has a morse code translation, then return that translation, otherwise return an empty string." } ;
-
-HELP: morse>ch
-{ $values
- { "str" "A string of dots and dashes that represents a single character in morse code" } { "ch" "The translated character" } }
-{ $description "If the given string represents a morse code character, then return that character, otherwise return f" } ;
-
-HELP: >morse
-{ $values
- { "str" "A string of ASCII characters which can be translated into morse code" } { "str" "A string in morse code" } }
-{ $description "Translates ASCII text into morse code, represented by a series of dots, dashes, and slashes." }
-{ $see-also morse> ch>morse } ;
-
-HELP: morse>
-{ $values { "str" "A string of morse code, in which the character '.' represents dots, '-' dashes, ' ' spaces between letters, and ' / ' spaces between words." } { "str" "The ASCII translation of the given string" } }
-{ $description "Translates morse code into ASCII text" }
-{ $see-also >morse morse>ch } ;
-
-HELP: play-as-morse*
-{ $values { "str" "A string of ascii characters which can be translated into morse code" } { "unit-length" "The length of a dot" } }
-{ $description "Plays a string as morse code" } ;
-
-HELP: play-as-morse
-{ $values { "str" "A string of ascii characters which can be translated into morse code" } }
-{ $description "Plays a string as morse code" } ;
+++ /dev/null
-! Copyright (C) 2007 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: arrays morse strings tools.test ;
-
-[ "" ] [ CHAR: \\ ch>morse ] unit-test
-[ "..." ] [ CHAR: s ch>morse ] unit-test
-[ CHAR: s ] [ "..." morse>ch ] unit-test
-[ f ] [ "..--..--.." morse>ch ] unit-test
-[ "-- --- .-. ... . / -.-. --- -.. ." ] [ "morse code" >morse ] unit-test
-[ "morse code" ] [ "-- --- .-. ... . / -.-. --- -.. ." morse> ] unit-test
-[ "hello, world!" ] [ "Hello, World!" >morse morse> ] unit-test
-! [ ] [ "sos" 0.075 play-as-morse* ] unit-test
-! [ ] [ "Factor rocks!" play-as-morse ] unit-test
+++ /dev/null
-! Copyright (C) 2007, 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors assocs combinators hashtables kernel lists math
-namespaces make openal parser-combinators promises sequences
-strings symbols synth synth.buffers unicode.case ;
-IN: morse
-
-<PRIVATE
-: morse-codes ( -- array )
- {
- { CHAR: a ".-" }
- { CHAR: b "-..." }
- { CHAR: c "-.-." }
- { CHAR: d "-.." }
- { CHAR: e "." }
- { CHAR: f "..-." }
- { CHAR: g "--." }
- { CHAR: h "...." }
- { CHAR: i ".." }
- { CHAR: j ".---" }
- { CHAR: k "-.-" }
- { CHAR: l ".-.." }
- { CHAR: m "--" }
- { CHAR: n "-." }
- { CHAR: o "---" }
- { CHAR: p ".--." }
- { CHAR: q "--.-" }
- { CHAR: r ".-." }
- { CHAR: s "..." }
- { CHAR: t "-" }
- { CHAR: u "..-" }
- { CHAR: v "...-" }
- { CHAR: w ".--" }
- { CHAR: x "-..-" }
- { CHAR: y "-.--" }
- { CHAR: z "--.." }
- { CHAR: 1 ".----" }
- { CHAR: 2 "..---" }
- { CHAR: 3 "...--" }
- { CHAR: 4 "....-" }
- { CHAR: 5 "....." }
- { CHAR: 6 "-...." }
- { CHAR: 7 "--..." }
- { CHAR: 8 "---.." }
- { CHAR: 9 "----." }
- { CHAR: 0 "-----" }
- { CHAR: . ".-.-.-" }
- { CHAR: , "--..--" }
- { CHAR: ? "..--.." }
- { CHAR: ' ".----." }
- { CHAR: ! "-.-.--" }
- { CHAR: / "-..-." }
- { CHAR: ( "-.--." }
- { CHAR: ) "-.--.-" }
- { CHAR: & ".-..." }
- { CHAR: : "---..." }
- { CHAR: ; "-.-.-." }
- { CHAR: = "-...- " }
- { CHAR: + ".-.-." }
- { CHAR: - "-....-" }
- { CHAR: _ "..--.-" }
- { CHAR: " ".-..-." }
- { CHAR: $ "...-..-" }
- { CHAR: @ ".--.-." }
- { CHAR: \s "/" }
- } ;
-
-: ch>morse-assoc ( -- assoc )
- morse-codes >hashtable ;
-
-: morse>ch-assoc ( -- assoc )
- morse-codes [ reverse ] map >hashtable ;
-
-PRIVATE>
-
-: ch>morse ( ch -- str )
- ch>lower ch>morse-assoc at* swap "" ? ;
-
-: morse>ch ( str -- ch )
- morse>ch-assoc at* swap f ? ;
-
-: >morse ( str -- str )
- [
- [ CHAR: \s , ] [ ch>morse % ] interleave
- ] "" make ;
-
-<PRIVATE
-
-: dot-char ( -- ch ) CHAR: . ;
-: dash-char ( -- ch ) CHAR: - ;
-: char-gap-char ( -- ch ) CHAR: \s ;
-: word-gap-char ( -- ch ) CHAR: / ;
-
-: =parser ( obj -- parser )
- [ = ] curry satisfy ;
-
-LAZY: 'dot' ( -- parser )
- dot-char =parser ;
-
-LAZY: 'dash' ( -- parser )
- dash-char =parser ;
-
-LAZY: 'char-gap' ( -- parser )
- char-gap-char =parser ;
-
-LAZY: 'word-gap' ( -- parser )
- word-gap-char =parser ;
-
-LAZY: 'morse-char' ( -- parser )
- 'dot' 'dash' <|> <+> ;
-
-LAZY: 'morse-word' ( -- parser )
- 'morse-char' 'char-gap' list-of ;
-
-LAZY: 'morse-words' ( -- parser )
- 'morse-word' 'word-gap' list-of ;
-
-PRIVATE>
-
-: morse> ( str -- str )
- 'morse-words' parse car parsed>> [
- [
- >string morse>ch
- ] map >string
- ] map [ [ CHAR: \s , ] [ % ] interleave ] "" make ;
-
-<PRIVATE
-SYMBOLS: source dot-buffer dash-buffer intra-char-gap-buffer letter-gap-buffer ;
-
-: queue ( symbol -- )
- get source get swap queue-buffer ;
-
-: dot ( -- ) dot-buffer queue ;
-: dash ( -- ) dash-buffer queue ;
-: intra-char-gap ( -- ) intra-char-gap-buffer queue ;
-: letter-gap ( -- ) letter-gap-buffer queue ;
-
-: beep-freq 880 ;
-
-: <morse-buffer> ( -- buffer )
- half-sample-freq <8bit-mono-buffer> ;
-
-: sine-buffer ( seconds -- id )
- beep-freq swap <morse-buffer> >sine-wave-buffer
- send-buffer id>> ;
-
-: silent-buffer ( seconds -- id )
- <morse-buffer> >silent-buffer send-buffer id>> ;
-
-: make-buffers ( unit-length -- )
- {
- [ sine-buffer dot-buffer set ]
- [ 3 * sine-buffer dash-buffer set ]
- [ silent-buffer intra-char-gap-buffer set ]
- [ 3 * silent-buffer letter-gap-buffer set ]
- } cleave ;
-
-: playing-morse ( quot unit-length -- )
- [
- init-openal 1 gen-sources first source set make-buffers
- call
- source get source-play
- ] with-scope ;
-
-: play-char ( ch -- )
- [ intra-char-gap ] [
- {
- { dot-char [ dot ] }
- { dash-char [ dash ] }
- { word-gap-char [ intra-char-gap ] }
- } case
- ] interleave ;
-
-PRIVATE>
-
-: play-as-morse* ( str unit-length -- )
- [
- [ letter-gap ] [ ch>morse play-char ] interleave
- ] swap playing-morse ;
-
-: play-as-morse ( str -- )
- 0.05 play-as-morse* ;
+++ /dev/null
-Converts between text and morse code, and plays morse code.
--- /dev/null
+
+USING: accessors effects.parser kernel lexer multi-methods
+ parser sequences words ;
+
+IN: multi-method-syntax
+
+! A nicer specializer syntax to hold us over till multi-methods go in
+! officially.
+!
+! Use both 'multi-methods' and 'multi-method-syntax' in that order.
+
+: scan-specializer ( -- specializer )
+
+ scan drop ! eat opening parenthesis
+
+ ")" parse-effect in>> [ search ] map ;
+
+: CREATE-METHOD ( -- method )
+ scan-word scan-specializer swap create-method-in ;
+
+: (METHOD:) ( -- method def ) CREATE-METHOD parse-definition ;
+
+: METHOD: (METHOD:) define ; parsing
\ No newline at end of file
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math sequences vectors classes classes.algebra
combinators arrays words assocs parser namespaces make
-definitions prettyprint prettyprint.backend quotations
-generalizations debugger io compiler.units kernel.private
-effects accessors hashtables sorting shuffle math.order sets ;
+definitions prettyprint prettyprint.backend prettyprint.custom
+quotations generalizations debugger io compiler.units
+kernel.private effects accessors hashtables sorting shuffle
+math.order sets ;
IN: multi-methods
! PART I: Converting hook specializers
{ 0 [ [ dup ] ] }
{ 1 [ [ over ] ] }
{ 2 [ [ pick ] ] }
- [ 1- picker [ >r ] swap [ r> swap ] 3append ]
+ [ 1- picker [ >r ] [ r> swap ] surround ]
} case ;
: (multi-predicate) ( class picker -- quot )
+++ /dev/null
-USING: arrays kernel math opengl opengl.gl opengl.glu
-opengl.demo-support ui ui.gadgets ui.render ;
-IN: nehe.2
-
-TUPLE: nehe2-gadget < gadget ;
-
-: width 256 ;
-: height 256 ;
-
-: <nehe2-gadget> ( -- gadget )
- nehe2-gadget new-gadget ;
-
-M: nehe2-gadget pref-dim* ( gadget -- dim )
- drop width height 2array ;
-
-M: nehe2-gadget draw-gadget* ( gadget -- )
- drop
- GL_PROJECTION glMatrixMode
- glLoadIdentity
- 45.0 width height / >float 0.1 100.0 gluPerspective
- GL_MODELVIEW glMatrixMode
- glLoadIdentity
- GL_SMOOTH glShadeModel
- 0.0 0.0 0.0 0.0 glClearColor
- 1.0 glClearDepth
- GL_DEPTH_TEST glEnable
- GL_LEQUAL glDepthFunc
- GL_PERSPECTIVE_CORRECTION_HINT GL_NICEST glHint
- GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear
- glLoadIdentity
- -1.5 0.0 -6.0 glTranslatef
- GL_TRIANGLES [
- 0.0 1.0 0.0 glVertex3f
- -1.0 -1.0 0.0 glVertex3f
- 1.0 -1.0 0.0 glVertex3f
- ] do-state
- 3.0 0.0 0.0 glTranslatef
- GL_QUADS [
- -1.0 1.0 0.0 glVertex3f
- 1.0 1.0 0.0 glVertex3f
- 1.0 -1.0 0.0 glVertex3f
- -1.0 -1.0 0.0 glVertex3f
- ] do-state ;
-
-: run2 ( -- )
- <nehe2-gadget> "NeHe Tutorial 2" open-window ;
+++ /dev/null
-Chris Double
+++ /dev/null
-USING: arrays kernel math opengl opengl.gl opengl.glu
-opengl.demo-support ui ui.gadgets ui.render ;
-IN: nehe.3
-
-TUPLE: nehe3-gadget < gadget ;
-
-: width 256 ;
-: height 256 ;
-
-: <nehe3-gadget> ( -- gadget )
- nehe3-gadget new-gadget ;
-
-M: nehe3-gadget pref-dim* ( gadget -- dim )
- drop width height 2array ;
-
-M: nehe3-gadget draw-gadget* ( gadget -- )
- drop
- GL_PROJECTION glMatrixMode
- glLoadIdentity
- 45.0 width height / >float 0.1 100.0 gluPerspective
- GL_MODELVIEW glMatrixMode
- glLoadIdentity
- GL_SMOOTH glShadeModel
- 0.0 0.0 0.0 0.0 glClearColor
- 1.0 glClearDepth
- GL_DEPTH_TEST glEnable
- GL_LEQUAL glDepthFunc
- GL_PERSPECTIVE_CORRECTION_HINT GL_NICEST glHint
- GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear
- glLoadIdentity
- -1.5 0.0 -6.0 glTranslatef
- GL_TRIANGLES [
- 1.0 0.0 0.0 glColor3f
- 0.0 1.0 0.0 glVertex3f
- 0.0 1.0 0.0 glColor3f
- -1.0 -1.0 0.0 glVertex3f
- 0.0 0.0 1.0 glColor3f
- 1.0 -1.0 0.0 glVertex3f
- ] do-state
- 3.0 0.0 0.0 glTranslatef
- 0.5 0.5 1.0 glColor3f
- GL_QUADS [
- -1.0 1.0 0.0 glVertex3f
- 1.0 1.0 0.0 glVertex3f
- 1.0 -1.0 0.0 glVertex3f
- -1.0 -1.0 0.0 glVertex3f
- ] do-state ;
-
-: run3 ( -- )
- <nehe3-gadget> "NeHe Tutorial 3" open-window ;
+++ /dev/null
-Chris Double
+++ /dev/null
-USING: arrays kernel math opengl opengl.gl opengl.glu
-opengl.demo-support ui ui.gadgets ui.render threads accessors ;
-IN: nehe.4
-
-TUPLE: nehe4-gadget < gadget rtri rquad thread quit? ;
-
-: width 256 ;
-: height 256 ;
-: redraw-interval 10 ;
-
-: <nehe4-gadget> ( -- gadget )
- nehe4-gadget new-gadget
- 0.0 >>rtri
- 0.0 >>rquad ;
-
-M: nehe4-gadget pref-dim* ( gadget -- dim )
- drop width height 2array ;
-
-M: nehe4-gadget draw-gadget* ( gadget -- )
- GL_PROJECTION glMatrixMode
- glLoadIdentity
- 45.0 width height / >float 0.1 100.0 gluPerspective
- GL_MODELVIEW glMatrixMode
- glLoadIdentity
- GL_SMOOTH glShadeModel
- 0.0 0.0 0.0 0.0 glClearColor
- 1.0 glClearDepth
- GL_DEPTH_TEST glEnable
- GL_LEQUAL glDepthFunc
- GL_PERSPECTIVE_CORRECTION_HINT GL_NICEST glHint
- GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear
- glLoadIdentity
- -1.5 0.0 -6.0 glTranslatef
- dup rtri>> 0.0 1.0 0.0 glRotatef
-
- GL_TRIANGLES [
- 1.0 0.0 0.0 glColor3f
- 0.0 1.0 0.0 glVertex3f
- 0.0 1.0 0.0 glColor3f
- -1.0 -1.0 0.0 glVertex3f
- 0.0 0.0 1.0 glColor3f
- 1.0 -1.0 0.0 glVertex3f
- ] do-state
-
- glLoadIdentity
-
- 1.5 0.0 -6.0 glTranslatef
- dup rquad>> 1.0 0.0 0.0 glRotatef
- 0.5 0.5 1.0 glColor3f
- GL_QUADS [
- -1.0 1.0 0.0 glVertex3f
- 1.0 1.0 0.0 glVertex3f
- 1.0 -1.0 0.0 glVertex3f
- -1.0 -1.0 0.0 glVertex3f
- ] do-state
- [ 0.2 + ] change-rtri
- [ 0.15 - ] change-rquad drop ;
-
-: nehe4-update-thread ( gadget -- )
- dup quit?>> [ drop ] [
- redraw-interval sleep
- dup relayout-1
- nehe4-update-thread
- ] if ;
-
-M: nehe4-gadget graft* ( gadget -- )
- f >>quit?
- [ nehe4-update-thread ] curry in-thread ;
-
-M: nehe4-gadget ungraft* ( gadget -- )
- t >>quit? drop ;
-
-: run4 ( -- )
- <nehe4-gadget> "NeHe Tutorial 4" open-window ;
+++ /dev/null
-Chris Double
+++ /dev/null
-USING: arrays kernel math opengl opengl.gl opengl.glu\r
-opengl.demo-support ui ui.gadgets ui.render threads accessors ;\r
-IN: nehe.5\r
-\r
-TUPLE: nehe5-gadget < gadget rtri rquad thread quit? ;\r
-: width 256 ;\r
-: height 256 ;\r
-: redraw-interval 10 ;\r
-\r
-: <nehe5-gadget> ( -- gadget )\r
- nehe5-gadget new-gadget\r
- 0.0 >>rtri\r
- 0.0 >>rquad ;\r
-\r
-M: nehe5-gadget pref-dim* ( gadget -- dim )\r
- drop width height 2array ;\r
-\r
-M: nehe5-gadget draw-gadget* ( gadget -- )\r
- GL_PROJECTION glMatrixMode\r
- glLoadIdentity\r
- 45.0 width height / >float 0.1 100.0 gluPerspective\r
- GL_MODELVIEW glMatrixMode\r
- glLoadIdentity\r
- GL_SMOOTH glShadeModel\r
- 0.0 0.0 0.0 0.0 glClearColor\r
- 1.0 glClearDepth\r
- GL_DEPTH_TEST glEnable\r
- GL_LEQUAL glDepthFunc\r
- GL_PERSPECTIVE_CORRECTION_HINT GL_NICEST glHint\r
- GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear\r
- glLoadIdentity\r
- -1.5 0.0 -6.0 glTranslatef\r
- dup rtri>> 0.0 1.0 0.0 glRotatef\r
-\r
- GL_TRIANGLES [\r
- 1.0 0.0 0.0 glColor3f\r
- 0.0 1.0 0.0 glVertex3f\r
- 0.0 1.0 0.0 glColor3f\r
- -1.0 -1.0 1.0 glVertex3f\r
- 0.0 0.0 1.0 glColor3f\r
- 1.0 -1.0 1.0 glVertex3f\r
-\r
- 1.0 0.0 0.0 glColor3f\r
- 0.0 1.0 0.0 glVertex3f\r
- 0.0 0.0 1.0 glColor3f\r
- 1.0 -1.0 1.0 glVertex3f\r
- 0.0 1.0 0.0 glColor3f\r
- 1.0 -1.0 -1.0 glVertex3f\r
-\r
- 1.0 0.0 0.0 glColor3f\r
- 0.0 1.0 0.0 glVertex3f\r
- 0.0 1.0 0.0 glColor3f\r
- 1.0 -1.0 -1.0 glVertex3f\r
- 0.0 0.0 1.0 glColor3f\r
- -1.0 -1.0 -1.0 glVertex3f\r
-\r
- 1.0 0.0 0.0 glColor3f\r
- 0.0 1.0 0.0 glVertex3f\r
- 0.0 0.0 1.0 glColor3f\r
- -1.0 -1.0 -1.0 glVertex3f\r
- 0.0 1.0 0.0 glColor3f\r
- -1.0 -1.0 1.0 glVertex3f\r
- ] do-state\r
-\r
- glLoadIdentity\r
-\r
- 1.5 0.0 -7.0 glTranslatef\r
- dup rquad>> 1.0 0.0 0.0 glRotatef\r
- GL_QUADS [\r
- 0.0 1.0 0.0 glColor3f\r
- 1.0 1.0 -1.0 glVertex3f\r
- -1.0 1.0 -1.0 glVertex3f\r
- -1.0 1.0 1.0 glVertex3f\r
- 1.0 1.0 1.0 glVertex3f\r
-\r
- 1.0 0.5 0.0 glColor3f\r
- 1.0 -1.0 1.0 glVertex3f\r
- -1.0 -1.0 1.0 glVertex3f\r
- -1.0 -1.0 -1.0 glVertex3f\r
- 1.0 -1.0 -1.0 glVertex3f\r
-\r
- 1.0 0.0 0.0 glColor3f\r
- 1.0 1.0 1.0 glVertex3f\r
- -1.0 1.0 1.0 glVertex3f\r
- -1.0 -1.0 1.0 glVertex3f\r
- 1.0 -1.0 1.0 glVertex3f\r
-\r
- 1.0 1.0 0.0 glColor3f\r
- 1.0 -1.0 -1.0 glVertex3f\r
- -1.0 -1.0 -1.0 glVertex3f\r
- -1.0 1.0 -1.0 glVertex3f\r
- 1.0 1.0 -1.0 glVertex3f\r
-\r
- 0.0 0.0 1.0 glColor3f\r
- -1.0 1.0 1.0 glVertex3f\r
- -1.0 1.0 -1.0 glVertex3f\r
- -1.0 -1.0 -1.0 glVertex3f\r
- -1.0 -1.0 1.0 glVertex3f\r
-\r
- 1.0 0.0 1.0 glColor3f\r
- 1.0 1.0 -1.0 glVertex3f\r
- 1.0 1.0 1.0 glVertex3f\r
- 1.0 -1.0 1.0 glVertex3f\r
- 1.0 -1.0 -1.0 glVertex3f\r
- ] do-state \r
- [ 0.2 + ] change-rtri\r
- [ 0.15 - ] change-rquad drop ;\r
-\r
-: nehe5-update-thread ( gadget -- ) \r
- dup quit?>> [\r
- drop\r
- ] [\r
- redraw-interval sleep \r
- dup relayout-1 \r
- nehe5-update-thread \r
- ] if ;\r
-\r
-M: nehe5-gadget graft* ( gadget -- )\r
- f >>quit?\r
- [ nehe5-update-thread ] curry in-thread ;\r
-\r
-M: nehe5-gadget ungraft* ( gadget -- )\r
- t >>quit? drop ;\r
-\r
-\r
-: run5 ( -- )\r
- <nehe5-gadget> "NeHe Tutorial 5" open-window ;\r
+++ /dev/null
-Chris Double
+++ /dev/null
-Chris Double
+++ /dev/null
-USING: tools.deploy.config ;
-V{
- { deploy-ui? t }
- { deploy-io 1 }
- { deploy-reflection 1 }
- { deploy-compiler? t }
- { deploy-math? t }
- { deploy-word-props? f }
- { deploy-c-types? f }
- { "stop-after-last-window?" t }
- { deploy-name "NeHe OpenGL demos" }
-}
+++ /dev/null
-USING: ui.gadgets.buttons ui.gadgets.packs ui.gadgets ui
-nehe.2 nehe.3 nehe.4 nehe.5 kernel ;
-IN: nehe
-
-: nehe-window ( -- )
- [
- <filled-pile>
- "Nehe 2" [ drop run2 ] <bevel-button> add-gadget
- "Nehe 3" [ drop run3 ] <bevel-button> add-gadget
- "Nehe 4" [ drop run4 ] <bevel-button> add-gadget
- "Nehe 5" [ drop run5 ] <bevel-button> add-gadget
- "Nehe examples" open-window
- ] with-ui ;
-
-MAIN: nehe-window
+++ /dev/null
-NeHe OpenGL tutorials ported to Factor
+++ /dev/null
-Chris Double
+++ /dev/null
-Chris Double
+++ /dev/null
-USING: namespaces system ;
-IN: openal.backend
-
-HOOK: load-wav-file os ( filename -- format data size frequency )
+++ /dev/null
-Chris Double
+++ /dev/null
-! Copyright (C) 2007 Chris Double.\r
-! See http://factorcode.org/license.txt for BSD license.\r
-!\r
-IN: openal.example\r
-USING: openal kernel alien threads sequences ;\r
-\r
-: play-hello ( -- )\r
- init-openal\r
- 1 gen-sources\r
- first dup AL_BUFFER alutCreateBufferHelloWorld set-source-param\r
- source-play\r
- 1000 sleep ;\r
- \r
-: (play-file) ( source -- )\r
- 100 sleep\r
- dup source-playing? [ (play-file) ] [ drop ] if ;\r
-\r
-: play-file ( filename -- )\r
- init-openal\r
- create-buffer-from-file \r
- 1 gen-sources\r
- first dup >r AL_BUFFER rot set-source-param r>\r
- dup source-play\r
- check-error\r
- (play-file) ;\r
-\r
-: play-wav ( filename -- )\r
- init-openal\r
- create-buffer-from-wav \r
- 1 gen-sources\r
- first dup >r AL_BUFFER rot set-source-param r>\r
- dup source-play\r
- check-error\r
- (play-file) ;
\ No newline at end of file
+++ /dev/null
-Chris Double
+++ /dev/null
-! Copyright (C) 2007 Chris Double.
-! See http://factorcode.org/license.txt for BSD license.
-USING: alien.c-types kernel alien alien.syntax shuffle
-combinators.lib openal.backend namespaces system ;
-IN: openal.macosx
-
-LIBRARY: alut
-
-FUNCTION: void alutLoadWAVFile ( ALbyte* fileName, ALenum* format, void** data, ALsizei* size, ALsizei* frequency ) ;
-
-M: macosx load-wav-file ( path -- format data size frequency )
- 0 <int> f <void*> 0 <int> 0 <int>
- [ alutLoadWAVFile ] 4keep
- >r >r >r *int r> *void* r> *int r> *int ;
+++ /dev/null
-unportable
+++ /dev/null
-! Copyright (C) 2007 Chris Double.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel arrays alien system combinators alien.syntax namespaces
- alien.c-types sequences vocabs.loader shuffle combinators.lib
- openal.backend ;
-IN: openal
-
-<< "alut" {
- { [ os windows? ] [ "alut.dll" ] }
- { [ os macosx? ] [
- "/System/Library/Frameworks/OpenAL.framework/OpenAL"
- ] }
- { [ os unix? ] [ "libalut.so" ] }
- } cond "cdecl" add-library >>
-
-<< "openal" {
- { [ os windows? ] [ "OpenAL32.dll" ] }
- { [ os macosx? ] [
- "/System/Library/Frameworks/OpenAL.framework/OpenAL"
- ] }
- { [ os unix? ] [ "libopenal.so" ] }
- } cond "cdecl" add-library >>
-
-LIBRARY: openal
-
-TYPEDEF: char ALboolean
-TYPEDEF: char ALchar
-TYPEDEF: char ALbyte
-TYPEDEF: uchar ALubyte
-TYPEDEF: short ALshort
-TYPEDEF: ushort ALushort
-TYPEDEF: int ALint
-TYPEDEF: uint ALuint
-TYPEDEF: int ALsizei
-TYPEDEF: int ALenum
-TYPEDEF: float ALfloat
-TYPEDEF: double ALdouble
-
-: AL_INVALID ( -- number ) -1 ; inline
-: AL_NONE ( -- number ) 0 ; inline
-: AL_FALSE ( -- number ) 0 ; inline
-: AL_TRUE ( -- number ) 1 ; inline
-: AL_SOURCE_RELATIVE ( -- number ) HEX: 202 ; inline
-: AL_CONE_INNER_ANGLE ( -- nmber ) HEX: 1001 ; inline
-: AL_CONE_OUTER_ANGLE ( -- number ) HEX: 1002 ; inline
-: AL_PITCH ( -- number ) HEX: 1003 ; inline
-: AL_POSITION ( -- number ) HEX: 1004 ; inline
-: AL_DIRECTION ( -- number ) HEX: 1005 ; inline
-: AL_VELOCITY ( -- number ) HEX: 1006 ; inline
-: AL_LOOPING ( -- number ) HEX: 1007 ; inline
-: AL_BUFFER ( -- number ) HEX: 1009 ; inline
-: AL_GAIN ( -- number ) HEX: 100A ; inline
-: AL_MIN_GAIN ( -- number ) HEX: 100D ; inline
-: AL_MAX_GAIN ( -- number ) HEX: 100E ; inline
-: AL_ORIENTATION ( -- number ) HEX: 100F ; inline
-: AL_CHANNEL_MASK ( -- number ) HEX: 3000 ; inline
-: AL_SOURCE_STATE ( -- number ) HEX: 1010 ; inline
-: AL_INITIAL ( -- number ) HEX: 1011 ; inline
-: AL_PLAYING ( -- number ) HEX: 1012 ; inline
-: AL_PAUSED ( -- number ) HEX: 1013 ; inline
-: AL_STOPPED ( -- number ) HEX: 1014 ; inline
-: AL_BUFFERS_QUEUED ( -- number ) HEX: 1015 ; inline
-: AL_BUFFERS_PROCESSED ( -- number ) HEX: 1016 ; inline
-: AL_SEC_OFFSET ( -- number ) HEX: 1024 ; inline
-: AL_SAMPLE_OFFSET ( -- number ) HEX: 1025 ; inline
-: AL_BYTE_OFFSET ( -- number ) HEX: 1026 ; inline
-: AL_SOURCE_TYPE ( -- number ) HEX: 1027 ; inline
-: AL_STATIC ( -- number ) HEX: 1028 ; inline
-: AL_STREAMING ( -- number ) HEX: 1029 ; inline
-: AL_UNDETERMINED ( -- number ) HEX: 1030 ; inline
-: AL_FORMAT_MONO8 ( -- number ) HEX: 1100 ; inline
-: AL_FORMAT_MONO16 ( -- number ) HEX: 1101 ; inline
-: AL_FORMAT_STEREO8 ( -- number ) HEX: 1102 ; inline
-: AL_FORMAT_STEREO16 ( -- number ) HEX: 1103 ; inline
-: AL_REFERENCE_DISTANCE ( -- number ) HEX: 1020 ; inline
-: AL_ROLLOFF_FACTOR ( -- number ) HEX: 1021 ; inline
-: AL_CONE_OUTER_GAIN ( -- number ) HEX: 1022 ; inline
-: AL_MAX_DISTANCE ( -- number ) HEX: 1023 ; inline
-: AL_FREQUENCY ( -- number ) HEX: 2001 ; inline
-: AL_BITS ( -- number ) HEX: 2002 ; inline
-: AL_CHANNELS ( -- number ) HEX: 2003 ; inline
-: AL_SIZE ( -- number ) HEX: 2004 ; inline
-: AL_UNUSED ( -- number ) HEX: 2010 ; inline
-: AL_PENDING ( -- number ) HEX: 2011 ; inline
-: AL_PROCESSED ( -- number ) HEX: 2012 ; inline
-: AL_NO_ERROR ( -- number ) AL_FALSE ; inline
-: AL_INVALID_NAME ( -- number ) HEX: A001 ; inline
-: AL_ILLEGAL_ENUM ( -- number ) HEX: A002 ; inline
-: AL_INVALID_ENUM ( -- number ) HEX: A002 ; inline
-: AL_INVALID_VALUE ( -- number ) HEX: A003 ; inline
-: AL_ILLEGAL_COMMAND ( -- number ) HEX: A004 ; inline
-: AL_INVALID_OPERATION ( -- number ) HEX: A004 ; inline
-: AL_OUT_OF_MEMORY ( -- number ) HEX: A005 ; inline
-: AL_VENDOR ( -- number ) HEX: B001 ; inline
-: AL_VERSION ( -- number ) HEX: B002 ; inline
-: AL_RENDERER ( -- number ) HEX: B003 ; inline
-: AL_EXTENSIONS ( -- number ) HEX: B004 ; inline
-: AL_DOPPLER_FACTOR ( -- number ) HEX: C000 ; inline
-: AL_DOPPLER_VELOCITY ( -- number ) HEX: C001 ; inline
-: AL_SPEED_OF_SOUND ( -- number ) HEX: C003 ; inline
-: AL_DISTANCE_MODEL ( -- number ) HEX: D000 ; inline
-: AL_INVERSE_DISTANCE ( -- number ) HEX: D001 ; inline
-: AL_INVERSE_DISTANCE_CLAMPED ( -- number ) HEX: D002 ; inline
-: AL_LINEAR_DISTANCE ( -- number ) HEX: D003 ; inline
-: AL_LINEAR_DISTANCE_CLAMPED ( -- number ) HEX: D004 ; inline
-: AL_EXPONENT_DISTANCE ( -- number ) HEX: D005 ; inline
-: AL_EXPONENT_DISTANCE_CLAMPED ( -- number ) HEX: D006 ; inline
-
-FUNCTION: void alEnable ( ALenum capability ) ;
-FUNCTION: void alDisable ( ALenum capability ) ;
-FUNCTION: ALboolean alIsEnabled ( ALenum capability ) ;
-FUNCTION: ALchar* alGetString ( ALenum param ) ;
-FUNCTION: void alGetBooleanv ( ALenum param, ALboolean* data ) ;
-FUNCTION: void alGetIntegerv ( ALenum param, ALint* data ) ;
-FUNCTION: void alGetFloatv ( ALenum param, ALfloat* data ) ;
-FUNCTION: void alGetDoublev ( ALenum param, ALdouble* data ) ;
-FUNCTION: ALboolean alGetBoolean ( ALenum param ) ;
-FUNCTION: ALint alGetInteger ( ALenum param ) ;
-FUNCTION: ALfloat alGetFloat ( ALenum param ) ;
-FUNCTION: ALdouble alGetDouble ( ALenum param ) ;
-FUNCTION: ALenum alGetError ( ) ;
-FUNCTION: ALboolean alIsExtensionPresent ( ALchar* extname ) ;
-FUNCTION: void* alGetProcAddress ( ALchar* fname ) ;
-FUNCTION: ALenum alGetEnumValue ( ALchar* ename ) ;
-FUNCTION: void alListenerf ( ALenum param, ALfloat value ) ;
-FUNCTION: void alListener3f ( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ) ;
-FUNCTION: void alListenerfv ( ALenum param, ALfloat* values ) ;
-FUNCTION: void alListeneri ( ALenum param, ALint value ) ;
-FUNCTION: void alListener3i ( ALenum param, ALint value1, ALint value2, ALint value3 ) ;
-FUNCTION: void alListeneriv ( ALenum param, ALint* values ) ;
-FUNCTION: void alGetListenerf ( ALenum param, ALfloat* value ) ;
-FUNCTION: void alGetListener3f ( ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3 ) ;
-FUNCTION: void alGetListenerfv ( ALenum param, ALfloat* values ) ;
-FUNCTION: void alGetListeneri ( ALenum param, ALint* value ) ;
-FUNCTION: void alGetListener3i ( ALenum param, ALint* value1, ALint* value2, ALint* value3 ) ;
-FUNCTION: void alGetListeneriv ( ALenum param, ALint* values ) ;
-FUNCTION: void alGenSources ( ALsizei n, ALuint* sources ) ;
-FUNCTION: void alDeleteSources ( ALsizei n, ALuint* sources ) ;
-FUNCTION: ALboolean alIsSource ( ALuint sid ) ;
-FUNCTION: void alSourcef ( ALuint sid, ALenum param, ALfloat value ) ;
-FUNCTION: void alSource3f ( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ) ;
-FUNCTION: void alSourcefv ( ALuint sid, ALenum param, ALfloat* values ) ;
-FUNCTION: void alSourcei ( ALuint sid, ALenum param, ALint value ) ;
-FUNCTION: void alSource3i ( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ) ;
-FUNCTION: void alSourceiv ( ALuint sid, ALenum param, ALint* values ) ;
-FUNCTION: void alGetSourcef ( ALuint sid, ALenum param, ALfloat* value ) ;
-FUNCTION: void alGetSource3f ( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3) ;
-FUNCTION: void alGetSourcefv ( ALuint sid, ALenum param, ALfloat* values ) ;
-FUNCTION: void alGetSourcei ( ALuint sid, ALenum param, ALint* value ) ;
-FUNCTION: void alGetSource3i ( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3) ;
-FUNCTION: void alGetSourceiv ( ALuint sid, ALenum param, ALint* values ) ;
-FUNCTION: void alSourcePlayv ( ALsizei ns, ALuint* sids ) ;
-FUNCTION: void alSourceStopv ( ALsizei ns, ALuint* sids ) ;
-FUNCTION: void alSourceRewindv ( ALsizei ns, ALuint* sids ) ;
-FUNCTION: void alSourcePausev ( ALsizei ns, ALuint* sids ) ;
-FUNCTION: void alSourcePlay ( ALuint sid ) ;
-FUNCTION: void alSourceStop ( ALuint sid ) ;
-FUNCTION: void alSourceRewind ( ALuint sid ) ;
-FUNCTION: void alSourcePause ( ALuint sid ) ;
-FUNCTION: void alSourceQueueBuffers ( ALuint sid, ALsizei numEntries, ALuint* bids ) ;
-FUNCTION: void alSourceUnqueueBuffers ( ALuint sid, ALsizei numEntries, ALuint* bids ) ;
-FUNCTION: void alGenBuffers ( ALsizei n, ALuint* buffers ) ;
-FUNCTION: void alDeleteBuffers ( ALsizei n, ALuint* buffers ) ;
-FUNCTION: ALboolean alIsBuffer ( ALuint bid ) ;
-FUNCTION: void alBufferData ( ALuint bid, ALenum format, void* data, ALsizei size, ALsizei freq ) ;
-FUNCTION: void alBufferf ( ALuint bid, ALenum param, ALfloat value ) ;
-FUNCTION: void alBuffer3f ( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ) ;
-FUNCTION: void alBufferfv ( ALuint bid, ALenum param, ALfloat* values ) ;
-FUNCTION: void alBufferi ( ALuint bid, ALenum param, ALint value ) ;
-FUNCTION: void alBuffer3i ( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ) ;
-FUNCTION: void alBufferiv ( ALuint bid, ALenum param, ALint* values ) ;
-FUNCTION: void alGetBufferf ( ALuint bid, ALenum param, ALfloat* value ) ;
-FUNCTION: void alGetBuffer3f ( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3) ;
-FUNCTION: void alGetBufferfv ( ALuint bid, ALenum param, ALfloat* values ) ;
-FUNCTION: void alGetBufferi ( ALuint bid, ALenum param, ALint* value ) ;
-FUNCTION: void alGetBuffer3i ( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3) ;
-FUNCTION: void alGetBufferiv ( ALuint bid, ALenum param, ALint* values ) ;
-FUNCTION: void alDopplerFactor ( ALfloat value ) ;
-FUNCTION: void alDopplerVelocity ( ALfloat value ) ;
-FUNCTION: void alSpeedOfSound ( ALfloat value ) ;
-FUNCTION: void alDistanceModel ( ALenum distanceModel ) ;
-
-LIBRARY: alut
-
-: ALUT_API_MAJOR_VERSION ( -- number ) 1 ; inline
-: ALUT_API_MINOR_VERSION ( -- number ) 1 ; inline
-: ALUT_ERROR_NO_ERROR ( -- number ) 0 ; inline
-: ALUT_ERROR_OUT_OF_MEMORY ( -- number ) HEX: 200 ; inline
-: ALUT_ERROR_INVALID_ENUM ( -- number ) HEX: 201 ; inline
-: ALUT_ERROR_INVALID_VALUE ( -- number ) HEX: 202 ; inline
-: ALUT_ERROR_INVALID_OPERATION ( -- number ) HEX: 203 ; inline
-: ALUT_ERROR_NO_CURRENT_CONTEXT ( -- number ) HEX: 204 ; inline
-: ALUT_ERROR_AL_ERROR_ON_ENTRY ( -- number ) HEX: 205 ; inline
-: ALUT_ERROR_ALC_ERROR_ON_ENTRY ( -- number ) HEX: 206 ; inline
-: ALUT_ERROR_OPEN_DEVICE ( -- number ) HEX: 207 ; inline
-: ALUT_ERROR_CLOSE_DEVICE ( -- number ) HEX: 208 ; inline
-: ALUT_ERROR_CREATE_CONTEXT ( -- number ) HEX: 209 ; inline
-: ALUT_ERROR_MAKE_CONTEXT_CURRENT ( -- number ) HEX: 20A ; inline
-: ALUT_ERROR_DESTRY_CONTEXT ( -- number ) HEX: 20B ; inline
-: ALUT_ERROR_GEN_BUFFERS ( -- number ) HEX: 20C ; inline
-: ALUT_ERROR_BUFFER_DATA ( -- number ) HEX: 20D ; inline
-: ALUT_ERROR_IO_ERROR ( -- number ) HEX: 20E ; inline
-: ALUT_ERROR_UNSUPPORTED_FILE_TYPE ( -- number ) HEX: 20F ; inline
-: ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE ( -- number ) HEX: 210 ; inline
-: ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA ( -- number ) HEX: 211 ; inline
-: ALUT_WAVEFORM_SINE ( -- number ) HEX: 100 ; inline
-: ALUT_WAVEFORM_SQUARE ( -- number ) HEX: 101 ; inline
-: ALUT_WAVEFORM_SAWTOOTH ( -- number ) HEX: 102 ; inline
-: ALUT_WAVEFORM_WHITENOISE ( -- number ) HEX: 103 ; inline
-: ALUT_WAVEFORM_IMPULSE ( -- number ) HEX: 104 ; inline
-: ALUT_LOADER_BUFFER ( -- number ) HEX: 300 ; inline
-: ALUT_LOADER_MEMORY ( -- number ) HEX: 301 ; inline
-
-FUNCTION: ALboolean alutInit ( int* argcp, char** argv ) ;
-FUNCTION: ALboolean alutInitWithoutContext ( int* argcp, char** argv ) ;
-FUNCTION: ALboolean alutExit ( ) ;
-FUNCTION: ALenum alutGetError ( ) ;
-FUNCTION: char* alutGetErrorString ( ALenum error ) ;
-FUNCTION: ALuint alutCreateBufferFromFile ( char* fileName ) ;
-FUNCTION: ALuint alutCreateBufferFromFileImage ( void* data, ALsizei length ) ;
-FUNCTION: ALuint alutCreateBufferHelloWorld ( ) ;
-FUNCTION: ALuint alutCreateBufferWaveform ( ALenum waveshape, ALfloat frequency, ALfloat phase, ALfloat duration ) ;
-FUNCTION: void* alutLoadMemoryFromFile ( char* fileName, ALenum* format, ALsizei* size, ALfloat* frequency ) ;
-FUNCTION: void* alutLoadMemoryFromFileImage ( void* data, ALsizei length, ALenum* format, ALsizei* size, ALfloat* frequency ) ;
-FUNCTION: void* alutLoadMemoryHelloWorld ( ALenum* format, ALsizei* size, ALfloat* frequency ) ;
-FUNCTION: void* alutLoadMemoryWaveform ( ALenum waveshape, ALfloat frequency, ALfloat phase, ALfloat duration, ALenum* format, ALsizei* size, ALfloat* freq ) ;
-FUNCTION: char* alutGetMIMETypes ( ALenum loader ) ;
-FUNCTION: ALint alutGetMajorVersion ( ) ;
-FUNCTION: ALint alutGetMinorVersion ( ) ;
-FUNCTION: ALboolean alutSleep ( ALfloat duration ) ;
-
-FUNCTION: void alutUnloadWAV ( ALenum format, void* data, ALsizei size, ALsizei frequency ) ;
-
-SYMBOL: init
-
-: init-openal ( -- )
- init get-global expired? [
- f f alutInit 0 = [ "Could not initialize OpenAL" throw ] when
- 1337 <alien> init set-global
- ] when ;
-
-: exit-openal ( -- )
- init get-global expired? [
- alutExit 0 = [ "Could not close OpenAL" throw ] when
- f init set-global
- ] unless ;
-
-: <uint-array> ( n -- byte-array ) "ALuint" <c-array> ;
-
-: gen-sources ( size -- seq )
- dup <uint-array> 2dup alGenSources swap c-uint-array> ;
-
-: gen-buffers ( size -- seq )
- dup <uint-array> 2dup alGenBuffers swap c-uint-array> ;
-
-: gen-buffer ( -- buffer ) 1 gen-buffers first ;
-
-: create-buffer-from-file ( filename -- buffer )
- alutCreateBufferFromFile dup AL_NONE = [
- "create-buffer-from-file failed" throw
- ] when ;
-
-os macosx? "openal.macosx" "openal.other" ? require
-
-: create-buffer-from-wav ( filename -- buffer )
- gen-buffer dup rot load-wav-file
- [ alBufferData ] 4keep alutUnloadWAV ;
-
-: queue-buffers ( source buffers -- )
- [ length ] [ >c-uint-array ] bi alSourceQueueBuffers ;
-
-: queue-buffer ( source buffer -- )
- 1array queue-buffers ;
-
-: set-source-param ( source param value -- )
- alSourcei ;
-
-: get-source-param ( source param -- value )
- 0 <uint> dup >r alGetSourcei r> *uint ;
-
-: set-buffer-param ( source param value -- )
- alBufferi ;
-
-: get-buffer-param ( source param -- value )
- 0 <uint> dup >r alGetBufferi r> *uint ;
-
-: source-play ( source -- )
- alSourcePlay ;
-
-: source-stop ( source -- )
- alSourceStop ;
-
-: check-error ( -- )
- alGetError dup ALUT_ERROR_NO_ERROR = [
- drop
- ] [
- alGetString throw
- ] if ;
-
-: source-playing? ( source -- bool )
- AL_SOURCE_STATE get-source-param AL_PLAYING = ;
+++ /dev/null
-Chris Double
+++ /dev/null
-! Copyright (C) 2007 Chris Double.
-! See http://factorcode.org/license.txt for BSD license.
-USING: openal.backend alien.c-types kernel alien alien.syntax
-shuffle combinators.lib ;
-IN: openal.other
-
-LIBRARY: alut
-
-FUNCTION: void alutLoadWAVFile ( ALbyte* fileName, ALenum* format, void** data, ALsizei* size, ALsizei* frequency, ALboolean* looping ) ;
-
-M: object load-wav-file ( filename -- format data size frequency )
- 0 <int> f <void*> 0 <int> 0 <int>
- [ 0 <char> alutLoadWAVFile ] 4keep
- >r >r >r *int r> *void* r> *int r> *int ;
+++ /dev/null
-OpenAL 3D audio library binding
+++ /dev/null
-bindings
-audio
: FOV 2.0 sqrt 1+ ; inline
: MOUSE-MOTION-SCALE 0.5 ; inline
-: KEY-ROTATE-STEP 1.0 ; inline
+: KEY-ROTATE-STEP 10.0 ; inline
SYMBOL: last-drag-loc
cache-key* textures get delete-at*
[ tex>> delete-texture ] [ drop ] if ;
+: clear-textures ( -- )
+ textures get values [ tex>> delete-texture ] each
+ H{ } clone textures set-global
+ H{ } clone refcounts set-global ;
+
M: texture-gadget graft* ( gadget -- ) [ 1+ ] refcount-change ;
M: texture-gadget ungraft* ( gadget -- )
! See http://factorcode.org/license.txt for BSD license.
USING: kernel opengl.gl alien.c-types continuations namespaces
assocs alien alien.strings libc opengl math sequences combinators
-combinators.lib macros arrays io.encodings.ascii fry ;
+combinators.lib macros arrays io.encodings.ascii fry
+specialized-arrays.uint destructors accessors ;
IN: opengl.shaders
: with-gl-shader-source-ptr ( string quot -- )
: gl-shader-info-log ( shader -- log )
dup gl-shader-info-log-length dup [
+ 1 calloc &free
[ 0 <int> swap glGetShaderInfoLog ] keep
ascii alien>string
- ] with-malloc ;
+ ] with-destructors ;
: check-gl-shader ( shader -- shader )
dup gl-shader-ok? [ dup gl-shader-info-log throw ] unless ;
: gl-program-info-log ( program -- log )
dup gl-program-info-log-length dup [
+ 1 calloc &free
[ 0 <int> swap glGetProgramInfoLog ] keep
ascii alien>string
- ] with-malloc ;
+ ] with-destructors ;
: check-gl-program ( program -- program )
dup gl-program-ok? [ dup gl-program-info-log throw ] unless ;
: gl-program-shaders ( program -- shaders )
dup gl-program-shaders-length
- dup "GLuint" <c-array>
- 0 <int> swap
- [ glGetAttachedShaders ] { 3 1 } multikeep
- c-uint-array> ;
+ 0 <int>
+ over <uint-array>
+ [ underlying>> glGetAttachedShaders ] keep ;
: delete-gl-program-only ( program -- )
glDeleteProgram ; inline
USING: arrays combinators kernel lists math math.parser
-namespaces parser lexer parser-combinators parser-combinators.simple
-promises quotations sequences strings math.order
-assocs prettyprint.backend memoize unicode.case unicode.categories
-combinators.short-circuit accessors make io ;
+namespaces parser lexer parser-combinators
+parser-combinators.simple promises quotations sequences strings
+math.order assocs prettyprint.backend prettyprint.custom memoize
+unicode.case unicode.categories combinators.short-circuit
+accessors make io ;
IN: parser-combinators.regexp
<PRIVATE
"commonly used in markup languages to indicate bold "
"faced text." }
{ $example "USING: parser-combinators parser-combinators.simple prettyprint ;" "\"*foo*\" 'bold' parse-1 ." "\"foo\"" }
-{ $example "USING: kernel parser-combinators parser-combinators.simple prettyprint sequences ;" "\"*foo*\" 'bold' [ \"<strong>\" swap \"</strong>\" 3append ] <@ parse-1 ." "\"<strong>foo</strong>\"" } ;
+{ $example "USING: kernel parser-combinators parser-combinators.simple prettyprint sequences ;" "\"*foo*\" 'bold' [ \"<strong>\" \"</strong>\" surround ] <@ parse-1 ." "\"<strong>foo</strong>\"" } ;
HELP: 'italic'
{ $values
"faced text." }
{ $examples
{ $example "USING: parser-combinators parser-combinators.simple prettyprint ;" "\"_foo_\" 'italic' parse-1 ." "\"foo\"" }
-{ $example "USING: kernel parser-combinators parser-combinators.simple prettyprint sequences ;" "\"_foo_\" 'italic' [ \"<emphasis>\" swap \"</emphasis>\" 3append ] <@ parse-1 ." "\"<emphasis>foo</emphasis>\"" } } ;
+{ $example "USING: kernel parser-combinators parser-combinators.simple prettyprint sequences ;" "\"_foo_\" 'italic' [ \"<emphasis>\" \"</emphasis>\" surround ] <@ parse-1 ." "\"<emphasis>foo</emphasis>\"" } } ;
HELP: comma-list
{ $values
{ "element" "a parser object" } { "parser" "a parser object" } }
--- /dev/null
+
+USING: kernel accessors locals math math.intervals math.order
+ namespaces sequences threads
+ ui
+ ui.gadgets
+ ui.gestures
+ ui.render
+ calendar
+ multi-methods
+ multi-method-syntax
+ combinators.short-circuit.smart
+ combinators.cleave.enhanced
+ processing.shapes
+ flatland ;
+
+IN: pong
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!
+! Inspired by this Ruby/Shoes version by why: http://gist.github.com/26431
+!
+! Which was based on this Nodebox version: http://billmill.org/pong.html
+! by Bill Mill.
+!
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: clamp-to-interval ( x interval -- x )
+ [ from>> first max ] [ to>> first min ] bi ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+TUPLE: <play-field> < <rectangle> ;
+TUPLE: <paddle> < <rectangle> ;
+
+TUPLE: <computer> < <paddle> { speed initial: 10 } ;
+
+: computer-move-left ( computer -- ) dup speed>> move-left-by ;
+: computer-move-right ( computer -- ) dup speed>> move-right-by ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+TUPLE: <ball> < <vel>
+ { diameter initial: 20 }
+ { bounciness initial: 1.2 }
+ { max-speed initial: 10 } ;
+
+: above-lower-bound? ( ball field -- ? ) bottom 50 - above? ;
+: below-upper-bound? ( ball field -- ? ) top 50 + below? ;
+
+: in-bounds? ( ball field -- ? )
+ {
+ [ above-lower-bound? ]
+ [ below-upper-bound? ]
+ } && ;
+
+:: bounce-change-vertical-velocity ( BALL -- )
+
+ BALL vel>> y neg
+ BALL bounciness>> *
+
+ BALL max-speed>> min
+
+ BALL vel>> (y!) ;
+
+:: bounce-off-paddle ( BALL PADDLE -- )
+
+ BALL bounce-change-vertical-velocity
+
+ BALL x PADDLE center x - 0.25 * BALL vel>> (x!)
+
+ PADDLE top BALL pos>> (y!) ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: mouse-x ( -- x ) hand-loc get first ;
+
+:: valid-paddle-interval ( PADDLE PLAY-FIELD -- interval )
+
+ PLAY-FIELD [ left ] [ right ] bi PADDLE width - [a,b] ;
+
+:: align-paddle-with-mouse ( PADDLE PLAY-FIELD -- )
+
+ mouse-x
+
+ PADDLE PLAY-FIELD valid-paddle-interval
+
+ clamp-to-interval
+
+ PADDLE pos>> (x!) ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! Protocol for drawing PONG objects
+
+GENERIC: draw ( obj -- )
+
+METHOD: draw ( <paddle> -- ) [ bottom-left ] [ dim>> ] bi rectangle ;
+METHOD: draw ( <ball> -- ) [ pos>> ] [ diameter>> 2 / ] bi circle ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+USE: syntax ! Switch back to core 'TUPLE:' instead of the one provided
+ ! by multi-methods
+
+TUPLE: <pong> < gadget paused field ball player computer ;
+
+: pong ( -- gadget )
+ <pong> new-gadget
+ T{ <play-field> { pos { 0 0 } } { dim { 400 400 } } } clone >>field
+ T{ <ball> { pos { 50 50 } } { vel { 3 4 } } } clone >>ball
+ T{ <paddle> { pos { 200 396 } } { dim { 75 4 } } } clone >>player
+ T{ <computer> { pos { 200 0 } } { dim { 75 4 } } } clone >>computer ;
+
+M: <pong> pref-dim* ( <pong> -- dim ) drop { 400 400 } ;
+M: <pong> ungraft* ( <pong> -- ) t >>paused drop ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+M:: <pong> draw-gadget* ( PONG -- )
+
+ PONG computer>> draw
+ PONG player>> draw
+ PONG ball>> draw ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+:: iterate-system ( GADGET -- )
+
+ [let | FIELD [ GADGET field>> ]
+ BALL [ GADGET ball>> ]
+ PLAYER [ GADGET player>> ]
+ COMPUTER [ GADGET computer>> ] |
+
+ [wlet | align-player-with-mouse [ ( -- )
+ PLAYER FIELD align-paddle-with-mouse ]
+
+ move-ball [ ( -- ) BALL 1 move-for ]
+
+ player-blocked-ball? [ ( -- ? )
+ BALL PLAYER { [ above? ] [ in-between-horizontally? ] } && ]
+
+ computer-blocked-ball? [ ( -- ? )
+ BALL COMPUTER { [ below? ] [ in-between-horizontally? ] } && ]
+
+ bounce-off-wall? [ ( -- ? )
+ BALL FIELD in-between-horizontally? not ]
+
+ stop-game [ ( -- ) t GADGET (>>paused) ] |
+
+ BALL FIELD in-bounds?
+ [
+
+ align-player-with-mouse
+
+ move-ball
+
+ ! computer reaction
+
+ BALL COMPUTER to-the-left-of? [ COMPUTER computer-move-left ] when
+ BALL COMPUTER to-the-right-of? [ COMPUTER computer-move-right ] when
+
+ ! check if ball bounced off something
+
+ player-blocked-ball? [ BALL PLAYER bounce-off-paddle ] when
+ computer-blocked-ball? [ BALL COMPUTER bounce-off-paddle ] when
+ bounce-off-wall? [ BALL reverse-horizontal-velocity ] when
+ ]
+ [ stop-game ]
+ if
+
+ ] ] ( gadget -- ) ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+:: start-pong-thread ( GADGET -- )
+ f GADGET (>>paused)
+ [
+ [
+ GADGET paused>>
+ [ f ]
+ [ GADGET iterate-system GADGET relayout-1 25 milliseconds sleep t ]
+ if
+ ]
+ loop
+ ]
+ in-thread ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: pong-window ( -- ) pong [ "PONG" open-window ] [ start-pong-thread ] bi ;
+
+: pong-main ( -- ) [ pong-window ] with-ui ;
+
+MAIN: pong-window
\ No newline at end of file
[ 0 ] [ string>number ] if-empty ;
: pad-digits ( string digits -- string' )
- [ "." split1 ] dip [ CHAR: 0 pad-right ] [ head-slice ] bi "." swap 3append ;
+ [ "." split1 ] dip [ CHAR: 0 pad-right ] [ head-slice ] bi "." glue ;
: max-digits ( n digits -- n' )
10 swap ^ [ * round ] keep / ;
+++ /dev/null
-
-USING: kernel arrays sequences math math.order qualified
- sequences.lib circular processing ui newfx processing.shapes ;
-
-IN: processing.gallery.trails
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-! Example 33-15 from the Processing book
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: point-list ( n -- seq ) [ drop 0 0 2array ] map <circular> ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: dot ( pos percent -- ) 1 swap - 25 * 5 max circle ;
-
-: step ( seq -- )
-
- no-stroke
- { 1 0.4 } fill
-
- 0 background
-
- mouse push-circular
- [ dot ]
- each-percent ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: go* ( -- )
-
- 500 500 size*
-
- [
- 100 point-list
- [ step ]
- curry
- draw
- ] setup
-
- run ;
-
-: go ( -- ) [ go* ] with-ui ;
-
-MAIN: go
USING: kernel namespaces arrays sequences grouping
alien.c-types
math math.vectors math.geometry.rect
- opengl.gl opengl.glu opengl.demo-support opengl generalizations vars
+ opengl.gl opengl.glu opengl generalizations vars
combinators.cleave colors ;
IN: processing.shapes
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+: do-state ( mode quot -- ) swap glBegin call glEnd ; inline
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
VAR: fill-color
VAR: stroke-color
[ 4613732 ] [ euler002 ] unit-test
[ 4613732 ] [ euler002a ] unit-test
+[ 4613732 ] [ euler002b ] unit-test
-! Copyright (c) 2007 Aaron Schaefer, Alexander Solovyov.
+! Copyright (c) 2007, 2008 Aaron Schaefer, Alexander Solovyov, Vishal Talwar.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel math sequences shuffle ;
IN: project-euler.002
! [ euler002a ] 100 ave-time
! 0 ms ave run time - 0.2 SD (100 trials)
-MAIN: euler002a
+
+<PRIVATE
+
+: next-fibs ( x y -- y x+y )
+ tuck + ;
+
+: ?retotal ( total fib- fib+ -- retotal fib- fib+ )
+ dup even? [ [ nip + ] 2keep ] when ;
+
+: (sum-even-fibs-below) ( partial fib- fib+ max -- total )
+ 2dup > [
+ 3drop
+ ] [
+ [ ?retotal next-fibs ] dip (sum-even-fibs-below)
+ ] if ;
+
+PRIVATE>
+
+: sum-even-fibs-below ( max -- sum )
+ [ 0 0 1 ] dip (sum-even-fibs-below) ;
+
+: euler002b ( -- answer )
+ 4000000 sum-even-fibs-below ;
+
+! [ euler002b ] 100 ave-time
+! 0 ms ave run time - 0.0 SD (100 trials)
+
+MAIN: euler002b
<PRIVATE
: (consecutive) ( count goal test -- n )
- pick pick = [
+ 2over = [
swap - nip
] [
dup prime? [ [ drop 0 ] 2dip ] [
--- /dev/null
+USING: project-euler.050 project-euler.050.private tools.test ;
+IN: project-euler.050.tests
+
+[ 41 ] [ 100 solve ] unit-test
+[ 953 ] [ 1000 solve ] unit-test
+[ 997651 ] [ euler050 ] unit-test
--- /dev/null
+! Copyright (c) 2008 Aaron Schaefer.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays kernel locals math math.primes sequences ;
+IN: project-euler.050
+
+! http://projecteuler.net/index.php?section=problems&id=50
+
+! DESCRIPTION
+! -----------
+
+! The prime 41, can be written as the sum of six consecutive primes:
+
+! 41 = 2 + 3 + 5 + 7 + 11 + 13
+
+! This is the longest sum of consecutive primes that adds to a prime below
+! one-hundred.
+
+! The longest sum of consecutive primes below one-thousand that adds to a
+! prime, contains 21 terms, and is equal to 953.
+
+! Which prime, below one-million, can be written as the sum of the most
+! consecutive primes?
+
+
+! SOLUTION
+! --------
+
+! 1) Create an sequence of all primes under 1000000.
+! 2) Start summing elements in the sequence until the next number would put you
+! over 1000000.
+! 3) Check if that sum is prime, if not, subtract the last number added.
+! 4) Repeat step 3 until you get a prime number, and store it along with the
+! how many consecutive numbers from the original sequence it took to get there.
+! 5) Drop the first number from the sequence of primes, and do steps 2-4 again
+! 6) Compare the longest chain from the first run with the second run, and store
+! the longer of the two.
+! 7) If the sequence of primes is still longer than the longest chain, then
+! repeat steps 5-7...otherwise, you've found the longest sum of consecutive
+! primes!
+
+<PRIVATE
+
+:: sum-upto ( seq limit -- length sum )
+ 0 seq [ + dup limit > ] find
+ [ swapd - ] [ drop seq length swap ] if* ;
+
+: pop-until-prime ( seq sum -- seq prime )
+ over length 0 > [
+ [ unclip-last-slice ] dip swap -
+ dup prime? [ pop-until-prime ] unless
+ ] [
+ 2drop { } 0
+ ] if ;
+
+! a pair is { length of chain, prime the chain sums to }
+
+: longest-prime ( seq limit -- pair )
+ dupd sum-upto dup prime? [
+ 2array nip
+ ] [
+ [ head-slice ] dip pop-until-prime
+ [ length ] dip 2array
+ ] if ;
+
+: longest ( pair pair -- longest )
+ 2dup [ first ] bi@ > [ drop ] [ nip ] if ;
+
+: continue? ( pair seq -- ? )
+ [ first ] [ length 1- ] bi* < ;
+
+: (find-longest) ( best seq limit -- best )
+ [ longest-prime longest ] 2keep 2over continue? [
+ [ rest-slice ] dip (find-longest)
+ ] [ 2drop ] if ;
+
+: find-longest ( seq limit -- best )
+ { 1 2 } -rot (find-longest) ;
+
+: solve ( n -- answer )
+ [ primes-upto ] keep find-longest second ;
+
+PRIVATE>
+
+: euler050 ( -- answer )
+ 1000000 solve ;
+
+! [ euler050 ] 100 ave-time
+! 291 ms run / 20.6 ms GC ave time - 100 trials
+
+MAIN: euler050
--- /dev/null
+USING: project-euler.099 project-euler.099.private tools.test ;
+IN: project-euler.099.tests
+
+[ 2 ] [ { { 2 11 } { 3 7 } } solve ] unit-test
+[ 709 ] [ euler099 ] unit-test
--- /dev/null
+! Copyright (c) 2008 Aaron Schaefer.
+! See http://factorcode.org/license.txt for BSD license.
+USING: io.encodings.ascii io.files kernel math math.functions math.parser
+ math.vectors sequences splitting ;
+IN: project-euler.099
+
+! http://projecteuler.net/index.php?section=problems&id=99
+
+! DESCRIPTION
+! -----------
+
+! Comparing two numbers written in index form like 2^11 and 3^7 is not difficult,
+! as any calculator would confirm that 2^11 = 2048 < 3^7 = 2187.
+
+! However, confirming that 632382^518061 519432^525806 would be much more
+! difficult, as both numbers contain over three million digits.
+
+! Using base_exp.txt (right click and 'Save Link/Target As...'), a 22K text
+! file containing one thousand lines with a base/exponent pair on each line,
+! determine which line number has the greatest numerical value.
+
+! NOTE: The first two lines in the file represent the numbers in the example
+! given above.
+
+
+! SOLUTION
+! --------
+
+! Use logarithms to make the calculations necessary more manageable.
+
+<PRIVATE
+
+: source-099 ( -- seq )
+ "resource:extra/project-euler/099/base_exp.txt"
+ ascii file-lines [ "," split [ string>number ] map ] map ;
+
+: simplify ( seq -- seq )
+ #! exponent * log(base)
+ flip first2 swap [ log ] map v* ;
+
+: solve ( seq -- index )
+ simplify [ supremum ] keep index 1+ ;
+
+PRIVATE>
+
+: euler099 ( -- answer )
+ source-099 solve ;
+
+! [ euler099 ] 100 ave-time
+! 16 ms ave run timen - 1.67 SD (100 trials)
+
+MAIN: euler099
--- /dev/null
+519432,525806\r
+632382,518061\r
+78864,613712\r
+466580,530130\r
+780495,510032\r
+525895,525320\r
+15991,714883\r
+960290,502358\r
+760018,511029\r
+166800,575487\r
+210884,564478\r
+555151,523163\r
+681146,515199\r
+563395,522587\r
+738250,512126\r
+923525,503780\r
+595148,520429\r
+177108,572629\r
+750923,511482\r
+440902,532446\r
+881418,505504\r
+422489,534197\r
+979858,501616\r
+685893,514935\r
+747477,511661\r
+167214,575367\r
+234140,559696\r
+940238,503122\r
+728969,512609\r
+232083,560102\r
+900971,504694\r
+688801,514772\r
+189664,569402\r
+891022,505104\r
+445689,531996\r
+119570,591871\r
+821453,508118\r
+371084,539600\r
+911745,504251\r
+623655,518600\r
+144361,582486\r
+352442,541775\r
+420726,534367\r
+295298,549387\r
+6530,787777\r
+468397,529976\r
+672336,515696\r
+431861,533289\r
+84228,610150\r
+805376,508857\r
+444409,532117\r
+33833,663511\r
+381850,538396\r
+402931,536157\r
+92901,604930\r
+304825,548004\r
+731917,512452\r
+753734,511344\r
+51894,637373\r
+151578,580103\r
+295075,549421\r
+303590,548183\r
+333594,544123\r
+683952,515042\r
+60090,628880\r
+951420,502692\r
+28335,674991\r
+714940,513349\r
+343858,542826\r
+549279,523586\r
+804571,508887\r
+260653,554881\r
+291399,549966\r
+402342,536213\r
+408889,535550\r
+40328,652524\r
+375856,539061\r
+768907,510590\r
+165993,575715\r
+976327,501755\r
+898500,504795\r
+360404,540830\r
+478714,529095\r
+694144,514472\r
+488726,528258\r
+841380,507226\r
+328012,544839\r
+22389,690868\r
+604053,519852\r
+329514,544641\r
+772965,510390\r
+492798,527927\r
+30125,670983\r
+895603,504906\r
+450785,531539\r
+840237,507276\r
+380711,538522\r
+63577,625673\r
+76801,615157\r
+502694,527123\r
+597706,520257\r
+310484,547206\r
+944468,502959\r
+121283,591152\r
+451131,531507\r
+566499,522367\r
+425373,533918\r
+40240,652665\r
+39130,654392\r
+714926,513355\r
+469219,529903\r
+806929,508783\r
+287970,550487\r
+92189,605332\r
+103841,599094\r
+671839,515725\r
+452048,531421\r
+987837,501323\r
+935192,503321\r
+88585,607450\r
+613883,519216\r
+144551,582413\r
+647359,517155\r
+213902,563816\r
+184120,570789\r
+258126,555322\r
+502546,527130\r
+407655,535678\r
+401528,536306\r
+477490,529193\r
+841085,507237\r
+732831,512408\r
+833000,507595\r
+904694,504542\r
+581435,521348\r
+455545,531110\r
+873558,505829\r
+94916,603796\r
+720176,513068\r
+545034,523891\r
+246348,557409\r
+556452,523079\r
+832015,507634\r
+173663,573564\r
+502634,527125\r
+250732,556611\r
+569786,522139\r
+216919,563178\r
+521815,525623\r
+92304,605270\r
+164446,576167\r
+753413,511364\r
+11410,740712\r
+448845,531712\r
+925072,503725\r
+564888,522477\r
+7062,780812\r
+641155,517535\r
+738878,512100\r
+636204,517828\r
+372540,539436\r
+443162,532237\r
+571192,522042\r
+655350,516680\r
+299741,548735\r
+581914,521307\r
+965471,502156\r
+513441,526277\r
+808682,508700\r
+237589,559034\r
+543300,524025\r
+804712,508889\r
+247511,557192\r
+543486,524008\r
+504383,526992\r
+326529,545039\r
+792493,509458\r
+86033,609017\r
+126554,589005\r
+579379,521481\r
+948026,502823\r
+404777,535969\r
+265767,554022\r
+266876,553840\r
+46631,643714\r
+492397,527958\r
+856106,506581\r
+795757,509305\r
+748946,511584\r
+294694,549480\r
+409781,535463\r
+775887,510253\r
+543747,523991\r
+210592,564536\r
+517119,525990\r
+520253,525751\r
+247926,557124\r
+592141,520626\r
+346580,542492\r
+544969,523902\r
+506501,526817\r
+244520,557738\r
+144745,582349\r
+69274,620858\r
+292620,549784\r
+926027,503687\r
+736320,512225\r
+515528,526113\r
+407549,535688\r
+848089,506927\r
+24141,685711\r
+9224,757964\r
+980684,501586\r
+175259,573121\r
+489160,528216\r
+878970,505604\r
+969546,502002\r
+525207,525365\r
+690461,514675\r
+156510,578551\r
+659778,516426\r
+468739,529945\r
+765252,510770\r
+76703,615230\r
+165151,575959\r
+29779,671736\r
+928865,503569\r
+577538,521605\r
+927555,503618\r
+185377,570477\r
+974756,501809\r
+800130,509093\r
+217016,563153\r
+365709,540216\r
+774508,510320\r
+588716,520851\r
+631673,518104\r
+954076,502590\r
+777828,510161\r
+990659,501222\r
+597799,520254\r
+786905,509727\r
+512547,526348\r
+756449,511212\r
+869787,505988\r
+653747,516779\r
+84623,609900\r
+839698,507295\r
+30159,670909\r
+797275,509234\r
+678136,515373\r
+897144,504851\r
+989554,501263\r
+413292,535106\r
+55297,633667\r
+788650,509637\r
+486748,528417\r
+150724,580377\r
+56434,632490\r
+77207,614869\r
+588631,520859\r
+611619,519367\r
+100006,601055\r
+528924,525093\r
+190225,569257\r
+851155,506789\r
+682593,515114\r
+613043,519275\r
+514673,526183\r
+877634,505655\r
+878905,505602\r
+1926,914951\r
+613245,519259\r
+152481,579816\r
+841774,507203\r
+71060,619442\r
+865335,506175\r
+90244,606469\r
+302156,548388\r
+399059,536557\r
+478465,529113\r
+558601,522925\r
+69132,620966\r
+267663,553700\r
+988276,501310\r
+378354,538787\r
+529909,525014\r
+161733,576968\r
+758541,511109\r
+823425,508024\r
+149821,580667\r
+269258,553438\r
+481152,528891\r
+120871,591322\r
+972322,501901\r
+981350,501567\r
+676129,515483\r
+950860,502717\r
+119000,592114\r
+392252,537272\r
+191618,568919\r
+946699,502874\r
+289555,550247\r
+799322,509139\r
+703886,513942\r
+194812,568143\r
+261823,554685\r
+203052,566221\r
+217330,563093\r
+734748,512313\r
+391759,537328\r
+807052,508777\r
+564467,522510\r
+59186,629748\r
+113447,594545\r
+518063,525916\r
+905944,504492\r
+613922,519213\r
+439093,532607\r
+445946,531981\r
+230530,560399\r
+297887,549007\r
+459029,530797\r
+403692,536075\r
+855118,506616\r
+963127,502245\r
+841711,507208\r
+407411,535699\r
+924729,503735\r
+914823,504132\r
+333725,544101\r
+176345,572832\r
+912507,504225\r
+411273,535308\r
+259774,555036\r
+632853,518038\r
+119723,591801\r
+163902,576321\r
+22691,689944\r
+402427,536212\r
+175769,572988\r
+837260,507402\r
+603432,519893\r
+313679,546767\r
+538165,524394\r
+549026,523608\r
+61083,627945\r
+898345,504798\r
+992556,501153\r
+369999,539727\r
+32847,665404\r
+891292,505088\r
+152715,579732\r
+824104,507997\r
+234057,559711\r
+730507,512532\r
+960529,502340\r
+388395,537687\r
+958170,502437\r
+57105,631806\r
+186025,570311\r
+993043,501133\r
+576770,521664\r
+215319,563513\r
+927342,503628\r
+521353,525666\r
+39563,653705\r
+752516,511408\r
+110755,595770\r
+309749,547305\r
+374379,539224\r
+919184,503952\r
+990652,501226\r
+647780,517135\r
+187177,570017\r
+168938,574877\r
+649558,517023\r
+278126,552016\r
+162039,576868\r
+658512,516499\r
+498115,527486\r
+896583,504868\r
+561170,522740\r
+747772,511647\r
+775093,510294\r
+652081,516882\r
+724905,512824\r
+499707,527365\r
+47388,642755\r
+646668,517204\r
+571700,522007\r
+180430,571747\r
+710015,513617\r
+435522,532941\r
+98137,602041\r
+759176,511070\r
+486124,528467\r
+526942,525236\r
+878921,505604\r
+408313,535602\r
+926980,503640\r
+882353,505459\r
+566887,522345\r
+3326,853312\r
+911981,504248\r
+416309,534800\r
+392991,537199\r
+622829,518651\r
+148647,581055\r
+496483,527624\r
+666314,516044\r
+48562,641293\r
+672618,515684\r
+443676,532187\r
+274065,552661\r
+265386,554079\r
+347668,542358\r
+31816,667448\r
+181575,571446\r
+961289,502320\r
+365689,540214\r
+987950,501317\r
+932299,503440\r
+27388,677243\r
+746701,511701\r
+492258,527969\r
+147823,581323\r
+57918,630985\r
+838849,507333\r
+678038,515375\r
+27852,676130\r
+850241,506828\r
+818403,508253\r
+131717,587014\r
+850216,506834\r
+904848,504529\r
+189758,569380\r
+392845,537217\r
+470876,529761\r
+925353,503711\r
+285431,550877\r
+454098,531234\r
+823910,508003\r
+318493,546112\r
+766067,510730\r
+261277,554775\r
+421530,534289\r
+694130,514478\r
+120439,591498\r
+213308,563949\r
+854063,506662\r
+365255,540263\r
+165437,575872\r
+662240,516281\r
+289970,550181\r
+847977,506933\r
+546083,523816\r
+413252,535113\r
+975829,501767\r
+361540,540701\r
+235522,559435\r
+224643,561577\r
+736350,512229\r
+328303,544808\r
+35022,661330\r
+307838,547578\r
+474366,529458\r
+873755,505819\r
+73978,617220\r
+827387,507845\r
+670830,515791\r
+326511,545034\r
+309909,547285\r
+400970,536363\r
+884827,505352\r
+718307,513175\r
+28462,674699\r
+599384,520150\r
+253565,556111\r
+284009,551093\r
+343403,542876\r
+446557,531921\r
+992372,501160\r
+961601,502308\r
+696629,514342\r
+919537,503945\r
+894709,504944\r
+892201,505051\r
+358160,541097\r
+448503,531745\r
+832156,507636\r
+920045,503924\r
+926137,503675\r
+416754,534757\r
+254422,555966\r
+92498,605151\r
+826833,507873\r
+660716,516371\r
+689335,514746\r
+160045,577467\r
+814642,508425\r
+969939,501993\r
+242856,558047\r
+76302,615517\r
+472083,529653\r
+587101,520964\r
+99066,601543\r
+498005,527503\r
+709800,513624\r
+708000,513716\r
+20171,698134\r
+285020,550936\r
+266564,553891\r
+981563,501557\r
+846502,506991\r
+334,1190800\r
+209268,564829\r
+9844,752610\r
+996519,501007\r
+410059,535426\r
+432931,533188\r
+848012,506929\r
+966803,502110\r
+983434,501486\r
+160700,577267\r
+504374,526989\r
+832061,507640\r
+392825,537214\r
+443842,532165\r
+440352,532492\r
+745125,511776\r
+13718,726392\r
+661753,516312\r
+70500,619875\r
+436952,532814\r
+424724,533973\r
+21954,692224\r
+262490,554567\r
+716622,513264\r
+907584,504425\r
+60086,628882\r
+837123,507412\r
+971345,501940\r
+947162,502855\r
+139920,584021\r
+68330,621624\r
+666452,516038\r
+731446,512481\r
+953350,502619\r
+183157,571042\r
+845400,507045\r
+651548,516910\r
+20399,697344\r
+861779,506331\r
+629771,518229\r
+801706,509026\r
+189207,569512\r
+737501,512168\r
+719272,513115\r
+479285,529045\r
+136046,585401\r
+896746,504860\r
+891735,505067\r
+684771,514999\r
+865309,506184\r
+379066,538702\r
+503117,527090\r
+621780,518717\r
+209518,564775\r
+677135,515423\r
+987500,501340\r
+197049,567613\r
+329315,544673\r
+236756,559196\r
+357092,541226\r
+520440,525733\r
+213471,563911\r
+956852,502490\r
+702223,514032\r
+404943,535955\r
+178880,572152\r
+689477,514734\r
+691351,514630\r
+866669,506128\r
+370561,539656\r
+739805,512051\r
+71060,619441\r
+624861,518534\r
+261660,554714\r
+366137,540160\r
+166054,575698\r
+601878,519990\r
+153445,579501\r
+279899,551729\r
+379166,538691\r
+423209,534125\r
+675310,515526\r
+145641,582050\r
+691353,514627\r
+917468,504026\r
+284778,550976\r
+81040,612235\r
+161699,576978\r
+616394,519057\r
+767490,510661\r
+156896,578431\r
+427408,533714\r
+254849,555884\r
+737217,512182\r
+897133,504851\r
+203815,566051\r
+270822,553189\r
+135854,585475\r
+778805,510111\r
+784373,509847\r
+305426,547921\r
+733418,512375\r
+732087,512448\r
+540668,524215\r
+702898,513996\r
+628057,518328\r
+640280,517587\r
+422405,534204\r
+10604,746569\r
+746038,511733\r
+839808,507293\r
+457417,530938\r
+479030,529064\r
+341758,543090\r
+620223,518824\r
+251661,556451\r
+561790,522696\r
+497733,527521\r
+724201,512863\r
+489217,528217\r
+415623,534867\r
+624610,518548\r
+847541,506953\r
+432295,533249\r
+400391,536421\r
+961158,502319\r
+139173,584284\r
+421225,534315\r
+579083,521501\r
+74274,617000\r
+701142,514087\r
+374465,539219\r
+217814,562985\r
+358972,540995\r
+88629,607424\r
+288597,550389\r
+285819,550812\r
+538400,524385\r
+809930,508645\r
+738326,512126\r
+955461,502535\r
+163829,576343\r
+826475,507891\r
+376488,538987\r
+102234,599905\r
+114650,594002\r
+52815,636341\r
+434037,533082\r
+804744,508880\r
+98385,601905\r
+856620,506559\r
+220057,562517\r
+844734,507078\r
+150677,580387\r
+558697,522917\r
+621751,518719\r
+207067,565321\r
+135297,585677\r
+932968,503404\r
+604456,519822\r
+579728,521462\r
+244138,557813\r
+706487,513800\r
+711627,513523\r
+853833,506674\r
+497220,527562\r
+59428,629511\r
+564845,522486\r
+623621,518603\r
+242689,558077\r
+125091,589591\r
+363819,540432\r
+686453,514901\r
+656813,516594\r
+489901,528155\r
+386380,537905\r
+542819,524052\r
+243987,557841\r
+693412,514514\r
+488484,528271\r
+896331,504881\r
+336730,543721\r
+728298,512647\r
+604215,519840\r
+153729,579413\r
+595687,520398\r
+540360,524240\r
+245779,557511\r
+924873,503730\r
+509628,526577\r
+528523,525122\r
+3509,847707\r
+522756,525555\r
+895447,504922\r
+44840,646067\r
+45860,644715\r
+463487,530404\r
+398164,536654\r
+894483,504959\r
+619415,518874\r
+966306,502129\r
+990922,501212\r
+835756,507474\r
+548881,523618\r
+453578,531282\r
+474993,529410\r
+80085,612879\r
+737091,512193\r
+50789,638638\r
+979768,501620\r
+792018,509483\r
+665001,516122\r
+86552,608694\r
+462772,530469\r
+589233,520821\r
+891694,505072\r
+592605,520594\r
+209645,564741\r
+42531,649269\r
+554376,523226\r
+803814,508929\r
+334157,544042\r
+175836,572970\r
+868379,506051\r
+658166,516520\r
+278203,551995\r
+966198,502126\r
+627162,518387\r
+296774,549165\r
+311803,547027\r
+843797,507118\r
+702304,514032\r
+563875,522553\r
+33103,664910\r
+191932,568841\r
+543514,524006\r
+506835,526794\r
+868368,506052\r
+847025,506971\r
+678623,515342\r
+876139,505726\r
+571997,521984\r
+598632,520198\r
+213590,563892\r
+625404,518497\r
+726508,512738\r
+689426,514738\r
+332495,544264\r
+411366,535302\r
+242546,558110\r
+315209,546555\r
+797544,509219\r
+93889,604371\r
+858879,506454\r
+124906,589666\r
+449072,531693\r
+235960,559345\r
+642403,517454\r
+720567,513047\r
+705534,513858\r
+603692,519870\r
+488137,528302\r
+157370,578285\r
+63515,625730\r
+666326,516041\r
+619226,518883\r
+443613,532186\r
+597717,520257\r
+96225,603069\r
+86940,608450\r
+40725,651929\r
+460976,530625\r
+268875,553508\r
+270671,553214\r
+363254,540500\r
+384248,538137\r
+762889,510892\r
+377941,538833\r
+278878,551890\r
+176615,572755\r
+860008,506412\r
+944392,502967\r
+608395,519571\r
+225283,561450\r
+45095,645728\r
+333798,544090\r
+625733,518476\r
+995584,501037\r
+506135,526853\r
+238050,558952\r
+557943,522972\r
+530978,524938\r
+634244,517949\r
+177168,572616\r
+85200,609541\r
+953043,502630\r
+523661,525484\r
+999295,500902\r
+840803,507246\r
+961490,502312\r
+471747,529685\r
+380705,538523\r
+911180,504275\r
+334149,544046\r
+478992,529065\r
+325789,545133\r
+335884,543826\r
+426976,533760\r
+749007,511582\r
+667067,516000\r
+607586,519623\r
+674054,515599\r
+188534,569675\r
+565185,522464\r
+172090,573988\r
+87592,608052\r
+907432,504424\r
+8912,760841\r
+928318,503590\r
+757917,511138\r
+718693,513153\r
+315141,546566\r
+728326,512645\r
+353492,541647\r
+638429,517695\r
+628892,518280\r
+877286,505672\r
+620895,518778\r
+385878,537959\r
+423311,534113\r
+633501,517997\r
+884833,505360\r
+883402,505416\r
+999665,500894\r
+708395,513697\r
+548142,523667\r
+756491,511205\r
+987352,501340\r
+766520,510705\r
+591775,520647\r
+833758,507563\r
+843890,507108\r
+925551,503698\r
+74816,616598\r
+646942,517187\r
+354923,541481\r
+256291,555638\r
+634470,517942\r
+930904,503494\r
+134221,586071\r
+282663,551304\r
+986070,501394\r
+123636,590176\r
+123678,590164\r
+481717,528841\r
+423076,534137\r
+866246,506145\r
+93313,604697\r
+783632,509880\r
+317066,546304\r
+502977,527103\r
+141272,583545\r
+71708,618938\r
+617748,518975\r
+581190,521362\r
+193824,568382\r
+682368,515131\r
+352956,541712\r
+351375,541905\r
+505362,526909\r
+905165,504518\r
+128645,588188\r
+267143,553787\r
+158409,577965\r
+482776,528754\r
+628896,518282\r
+485233,528547\r
+563606,522574\r
+111001,595655\r
+115920,593445\r
+365510,540237\r
+959724,502374\r
+938763,503184\r
+930044,503520\r
+970959,501956\r
+913658,504176\r
+68117,621790\r
+989729,501253\r
+567697,522288\r
+820427,508163\r
+54236,634794\r
+291557,549938\r
+124961,589646\r
+403177,536130\r
+405421,535899\r
+410233,535417\r
+815111,508403\r
+213176,563974\r
+83099,610879\r
+998588,500934\r
+513640,526263\r
+129817,587733\r
+1820,921851\r
+287584,550539\r
+299160,548820\r
+860621,506386\r
+529258,525059\r
+586297,521017\r
+953406,502616\r
+441234,532410\r
+986217,501386\r
+781938,509957\r
+461247,530595\r
+735424,512277\r
+146623,581722\r
+839838,507288\r
+510667,526494\r
+935085,503327\r
+737523,512167\r
+303455,548204\r
+992779,501145\r
+60240,628739\r
+939095,503174\r
+794368,509370\r
+501825,527189\r
+459028,530798\r
+884641,505363\r
+512287,526364\r
+835165,507499\r
+307723,547590\r
+160587,577304\r
+735043,512300\r
+493289,527887\r
+110717,595785\r
+306480,547772\r
+318593,546089\r
+179810,571911\r
+200531,566799\r
+314999,546580\r
+197020,567622\r
+301465,548487\r
+237808,559000\r
+131944,586923\r
+882527,505449\r
+468117,530003\r
+711319,513541\r
+156240,578628\r
+965452,502162\r
+992756,501148\r
+437959,532715\r
+739938,512046\r
+614249,519196\r
+391496,537356\r
+62746,626418\r
+688215,514806\r
+75501,616091\r
+883573,505412\r
+558824,522910\r
+759371,511061\r
+173913,573489\r
+891351,505089\r
+727464,512693\r
+164833,576051\r
+812317,508529\r
+540320,524243\r
+698061,514257\r
+69149,620952\r
+471673,529694\r
+159092,577753\r
+428134,533653\r
+89997,606608\r
+711061,513557\r
+779403,510081\r
+203327,566155\r
+798176,509187\r
+667688,515963\r
+636120,517833\r
+137410,584913\r
+217615,563034\r
+556887,523038\r
+667229,515991\r
+672276,515708\r
+325361,545187\r
+172115,573985\r
+13846,725685
\ No newline at end of file
<PRIVATE
-: short ( seq n -- seq n )
- over length min ;
-
: next ( seq -- )
[ 4 short tail* sum ] keep push ;
-USING: project-euler.203 tools.test ;
+USING: project-euler.203 project-euler.203.private tools.test ;
IN: project-euler.203.tests
[ 105 ] [ 8 solve ] unit-test
-[ 34029210557338 ] [ 51 solve ] unit-test
+[ 34029210557338 ] [ euler203 ] unit-test
+! Copyright (c) 2008 Eric Mertens.
+! See http://factorcode.org/license.txt for BSD license.
USING: fry kernel math math.primes.factors sequences sets ;
IN: project-euler.203
-: iterate ( n initial quot -- results ) swapd '[ @ dup ] replicate nip ; inline
-: (generate) ( seq -- seq ) [ 0 prefix ] [ 0 suffix ] bi [ + ] 2map ;
-: generate ( n -- seq ) 1- { 1 } [ (generate) ] iterate concat prune ;
-: squarefree ( n -- ? ) factors duplicates empty? ;
-: solve ( n -- n ) generate [ squarefree ] filter sum ;
-: euler203 ( -- n ) 51 solve ;
+! http://projecteuler.net/index.php?section=problems&id=203
+
+! DESCRIPTION
+! -----------
+
+! The binomial coefficients nCk can be arranged in triangular form, Pascal's
+! triangle, like this:
+
+! 1
+! 1 1
+! 1 2 1
+! 1 3 3 1
+! 1 4 6 4 1
+! 1 5 10 10 5 1
+! 1 6 15 20 15 6 1
+! 1 7 21 35 35 21 7 1
+! .........
+
+! It can be seen that the first eight rows of Pascal's triangle contain twelve
+! distinct numbers: 1, 2, 3, 4, 5, 6, 7, 10, 15, 20, 21 and 35.
+
+! A positive integer n is called squarefree if no square of a prime divides n.
+! Of the twelve distinct numbers in the first eight rows of Pascal's triangle,
+! all except 4 and 20 are squarefree. The sum of the distinct squarefree numbers
+! in the first eight rows is 105.
+
+! Find the sum of the distinct squarefree numbers in the first 51 rows of
+! Pascal's triangle.
+
+
+! SOLUTION
+! --------
+
+<PRIVATE
+
+: iterate ( n initial quot -- results )
+ swapd '[ @ dup ] replicate nip ; inline
+
+: (generate) ( seq -- seq )
+ [ 0 prefix ] [ 0 suffix ] bi [ + ] 2map ;
+
+: generate ( n -- seq )
+ 1- { 1 } [ (generate) ] iterate concat prune ;
+
+: squarefree ( n -- ? )
+ factors all-unique? ;
+
+: solve ( n -- n )
+ generate [ squarefree ] filter sum ;
+
+PRIVATE>
+
+: euler203 ( -- n )
+ 51 solve ;
+
+! [ euler203 ] 100 ave-time
+! 12 ms ave run time - 1.6 SD (100 trials)
+
+MAIN: euler203
! -----------
! Consider the problem of building a wall out of 2x1 and 3x1 bricks
-! (horizontalvertical dimensions) such that, for extra strength, the gaps
+! (horizontal x vertical dimensions) such that, for extra strength, the gaps
! between horizontally-adjacent bricks never line up in consecutive layers,
! i.e. never form a "running crack".
-! Copyright (c) 2007 Aaron Schaefer.
+! Copyright (c) 2007, 2008 Aaron Schaefer.
! See http://factorcode.org/license.txt for BSD license.
USING: continuations fry io kernel make math math.functions math.parser
math.statistics memory tools.time ;
IN: project-euler.ave-time
+: nth-place ( x n -- y )
+ 10 swap ^ [ * round >integer ] keep /f ;
+
: collect-benchmarks ( quot n -- seq )
[
[ datastack ]
- [ '[ _ gc benchmark , ] tuck '[ _ _ with-datastack drop ] ]
+ [
+ '[ _ gc benchmark 1000 / , ] tuck
+ '[ _ _ with-datastack drop ]
+ ]
[ 1- ] tri* swap times call
] { } make ; inline
-: nth-place ( x n -- y )
- 10 swap ^ [ * round ] keep / ;
-
: ave-time ( quot n -- )
[ collect-benchmarks ] keep swap
- [ std 2 nth-place ] [ mean round ] bi [
+ [ std 2 nth-place ] [ mean round >integer ] bi [
# " ms ave run time - " % # " SD (" % # " trials)" %
] "" make print flush ; inline
project-euler.052 project-euler.053 project-euler.055 project-euler.056
project-euler.059 project-euler.067 project-euler.071 project-euler.073
project-euler.075 project-euler.076 project-euler.079 project-euler.092
- project-euler.097 project-euler.100 project-euler.116 project-euler.117
- project-euler.134 project-euler.148 project-euler.150 project-euler.151
- project-euler.164 project-euler.169 project-euler.173 project-euler.175
- project-euler.186 project-euler.190 project-euler.215 ;
+ project-euler.097 project-euler.099 project-euler.100 project-euler.116
+ project-euler.117 project-euler.134 project-euler.148 project-euler.150
+ project-euler.151 project-euler.164 project-euler.169 project-euler.173
+ project-euler.175 project-euler.186 project-euler.190 project-euler.203
+ project-euler.215 ;
IN: project-euler
<PRIVATE
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-: start-service ( name -- ) "/etc/init.d/" swap " start" 3append system drop ;
-: stop-service ( name -- ) "/etc/init.d/" swap " stop" 3append system drop ;
+: start-service ( name -- ) "/etc/init.d/" " start" surround system drop ;
+: stop-service ( name -- ) "/etc/init.d/" " stop" surround system drop ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! See http://factorcode.org/license.txt for BSD license.\r
USING: accessors assocs math kernel shuffle generalizations\r
words quotations arrays combinators sequences math.vectors\r
-io.styles prettyprint vocabs sorting io generic locals.private\r
-math.statistics math.order combinators.lib ;\r
+io.styles prettyprint vocabs sorting io generic\r
+math.statistics math.order combinators.lib locals.types\r
+locals.definitions ;\r
IN: reports.noise\r
\r
: badness ( word -- n )\r
--- /dev/null
+USING: help.markup help.syntax math multiline
+sequences sequences.complex-components ;
+IN: sequences.complex-components
+
+ARTICLE: "sequences.complex-components" "Complex component virtual sequences"
+"The " { $link complex-components } " class wraps a sequence of " { $link complex } " number values, presenting a sequence of " { $link real } " values made by interleaving the real and imaginary parts of the complex values in the original sequence."
+{ $subsection complex-components }
+{ $subsection <complex-components> } ;
+
+ABOUT: "sequences.complex-components"
+
+HELP: complex-components
+{ $class-description "Sequence wrapper class that transforms a sequence of " { $link complex } " number values into a sequence of " { $link real } " values, interleaving the real and imaginary parts of the complex values in the original sequence." }
+{ $examples { $example <"
+USING: prettyprint sequences arrays sequences.complex-components ;
+{ C{ 1.0 -1.0 } -2.0 C{ 3.0 1.0 } } <complex-components> >array .
+"> "{ 1.0 -1.0 -2.0 0 3.0 1.0 }" } } ;
+
+HELP: <complex-components>
+{ $values { "sequence" sequence } { "complex-components" complex-components } }
+{ $description "Wraps " { $snippet "sequence" } " in a " { $link complex-components } " wrapper." }
+{ $examples
+{ $example <"
+USING: prettyprint sequences arrays
+sequences.complex-components ;
+{ C{ 1.0 -1.0 } -2.0 C{ 3.0 1.0 } } <complex-components> third .
+"> "-2.0" }
+{ $example <"
+USING: prettyprint sequences arrays
+sequences.complex-components ;
+{ C{ 1.0 -1.0 } -2.0 C{ 3.0 1.0 } } <complex-components> fourth .
+"> "0" }
+} ;
+
+{ complex-components <complex-components> } related-words
--- /dev/null
+USING: sequences.complex-components
+kernel sequences tools.test arrays accessors ;
+IN: sequences.complex-components.tests
+
+: test-array ( -- x )
+ { C{ 1.0 2.0 } 3.0 C{ 5.0 6.0 } } <complex-components> ;
+
+[ 6 ] [ test-array length ] unit-test
+
+[ 1.0 ] [ test-array first ] unit-test
+[ 2.0 ] [ test-array second ] unit-test
+[ 3.0 ] [ test-array third ] unit-test
+[ 0 ] [ test-array fourth ] unit-test
+
+[ { 1.0 2.0 3.0 0 5.0 6.0 } ] [ test-array >array ] unit-test
+
--- /dev/null
+USING: accessors kernel math math.functions combinators
+sequences sequences.private ;
+IN: sequences.complex-components
+
+TUPLE: complex-components seq ;
+INSTANCE: complex-components sequence
+
+: <complex-components> ( sequence -- complex-components )
+ complex-components boa ; inline
+
+<PRIVATE
+
+: complex-components@ ( n seq -- remainder n' seq' )
+ [ [ 1 bitand ] [ -1 shift ] bi ] [ seq>> ] bi* ; inline
+: complex-component ( remainder complex -- component )
+ swap {
+ { 0 [ real-part ] }
+ { 1 [ imaginary-part ] }
+ } case ;
+
+PRIVATE>
+
+M: complex-components length
+ seq>> length 1 shift ;
+M: complex-components nth-unsafe
+ complex-components@ nth-unsafe complex-component ;
+M: complex-components set-nth-unsafe
+ immutable ;
--- /dev/null
+Virtual sequence wrapper to convert complex values into real value pairs
--- /dev/null
+sequences
+math
--- /dev/null
+USING: help.markup help.syntax math multiline
+sequences sequences.complex ;
+IN: sequences.complex
+
+ARTICLE: "sequences.complex" "Complex virtual sequences"
+"The " { $link complex-sequence } " class wraps a sequence of " { $link real } " number values, presenting a sequence of " { $link complex } " values made by treating the underlying sequence as pairs of alternating real and imaginary values."
+{ $subsection complex-sequence }
+{ $subsection <complex-sequence> } ;
+
+ABOUT: "sequences.complex"
+
+HELP: complex-sequence
+{ $class-description "Sequence wrapper class that transforms a sequence of " { $link real } " number values into a sequence of " { $link complex } " values, treating the underlying sequence as pairs of alternating real and imaginary values." }
+{ $examples { $example <"
+USING: prettyprint
+specialized-arrays.double sequences.complex
+sequences arrays ;
+double-array{ 1.0 -1.0 -2.0 2.0 3.0 0.0 } <complex-sequence> >array .
+"> "{ C{ 1.0 -1.0 } C{ -2.0 2.0 } C{ 3.0 0.0 } }" } } ;
+
+HELP: <complex-sequence>
+{ $values { "sequence" sequence } { "complex-sequence" complex-sequence } }
+{ $description "Wraps " { $snippet "sequence" } " in a " { $link complex-sequence } "." }
+{ $examples { $example <"
+USING: prettyprint
+specialized-arrays.double sequences.complex
+sequences arrays ;
+double-array{ 1.0 -1.0 -2.0 2.0 3.0 0.0 } <complex-sequence> second .
+"> "C{ -2.0 2.0 }" } } ;
+
+{ complex-sequence <complex-sequence> } related-words
--- /dev/null
+USING: specialized-arrays.float sequences.complex
+kernel sequences tools.test arrays accessors ;
+IN: sequences.complex.tests
+
+: test-array ( -- x )
+ float-array{ 1.0 2.0 3.0 4.0 } clone <complex-sequence> ;
+: odd-length-test-array ( -- x )
+ float-array{ 1.0 2.0 3.0 4.0 5.0 } clone <complex-sequence> ;
+
+[ 2 ] [ test-array length ] unit-test
+[ 2 ] [ odd-length-test-array length ] unit-test
+
+[ C{ 1.0 2.0 } ] [ test-array first ] unit-test
+[ C{ 3.0 4.0 } ] [ test-array second ] unit-test
+
+[ { C{ 1.0 2.0 } C{ 3.0 4.0 } } ]
+[ test-array >array ] unit-test
+
+[ float-array{ 1.0 2.0 5.0 6.0 } ]
+[ test-array [ C{ 5.0 6.0 } 1 rot set-nth ] [ seq>> ] bi ]
+unit-test
+
+[ float-array{ 7.0 0.0 3.0 4.0 } ]
+[ test-array [ 7.0 0 rot set-nth ] [ seq>> ] bi ]
+unit-test
+
--- /dev/null
+USING: accessors kernel math math.functions
+sequences sequences.private ;
+IN: sequences.complex
+
+TUPLE: complex-sequence seq ;
+INSTANCE: complex-sequence sequence
+
+: <complex-sequence> ( sequence -- complex-sequence )
+ complex-sequence boa ; inline
+
+<PRIVATE
+
+: complex@ ( n seq -- n' seq' )
+ [ 1 shift ] [ seq>> ] bi* ; inline
+
+PRIVATE>
+
+M: complex-sequence length
+ seq>> length -1 shift ;
+M: complex-sequence nth-unsafe
+ complex@ [ nth-unsafe ] [ [ 1+ ] dip nth-unsafe ] 2bi rect> ;
+M: complex-sequence set-nth-unsafe
+ complex@
+ [ [ real-part ] [ ] [ ] tri* set-nth-unsafe ]
+ [ [ imaginary-part ] [ 1+ ] [ ] tri* set-nth-unsafe ] 3bi ;
--- /dev/null
+Virtual sequence wrapper to convert real pairs into complex values
--- /dev/null
+sequences
+math
assocs random sequences.private shuffle math.functions arrays
math.parser math.private sorting strings ascii macros assocs.lib
quotations hashtables math.order locals generalizations
-math.ranges random ;
+math.ranges random fry ;
IN: sequences.lib
: each-withn ( seq quot n -- ) nwith each ; inline
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: each-percent ( seq quot -- )
- >r
- dup length
- dup [ / ] curry
- [ 1+ ] prepose
- r> compose
+ [
+ dup length
+ dup [ / ] curry
+ [ 1+ ] prepose
+ ] dip compose
2each ; inline
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: minmax ( seq -- min max )
#! find the min and max of a seq in one pass
- 1/0. -1/0. rot [ tuck max >r min r> ] each ;
+ 1/0. -1/0. rot [ tuck max [ min ] dip ] each ;
! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
: (monotonic-split) ( seq quot -- newseq )
[
- >r dup unclip suffix r>
+ [ dup unclip suffix ] dip
v, [ pick ,, call [ v, ] unless ] curry 2each ,v
] { } make ;
ERROR: element-not-found ;
: split-around ( seq quot -- before elem after )
dupd find over [ element-not-found ] unless
- >r cut rest r> swap ; inline
-
-: (map-until) ( quot pred -- quot )
- [ dup ] swap 3compose
- [ [ drop t ] [ , f ] if ] compose [ find 2drop ] curry ;
+ [ cut rest ] dip swap ; inline
: map-until ( seq quot pred -- newseq )
- (map-until) { } make ;
+ '[ [ @ dup @ [ drop t ] [ , f ] if ] find 2drop ] { } make ;
: take-while ( seq quot -- newseq )
[ not ] compose
PRIVATE>
: exact-strings ( alphabet length -- seqs )
- >r dup length r> exact-number-strings map-alphabet ;
+ [ dup length ] dip exact-number-strings map-alphabet ;
: strings ( alphabet length -- seqs )
- >r dup length r> number-strings map-alphabet ;
+ [ dup length ] dip number-strings map-alphabet ;
: switches ( seq1 seq -- subseq )
! seq1 is a sequence of ones and zeroes
- >r [ length ] keep [ nth 1 = ] curry filter r>
+ [ [ length ] keep [ nth 1 = ] curry filter ] dip
[ nth ] curry { } map-as ;
: power-set ( seq -- subsets )
dup length 1 (a,b] [ dup random pick exchange ] each ;
: enumerate ( seq -- seq' ) <enum> >alist ;
-
-: splice ( left-seq right-seq seq -- newseq ) swap 3append ;
-
-: surround ( seq left-seq right-seq -- newseq ) swapd 3append ;
: $divider ( -- )
[
<gadget>
- T{ gradient f
- {
- T{ rgba f 0.25 0.25 0.25 1.0 }
- T{ rgba f 1.0 1.0 1.0 0.0 }
- }
- } >>interior
+ {
+ T{ rgba f 0.25 0.25 0.25 1.0 }
+ T{ rgba f 1.0 1.0 1.0 0.0 }
+ } <gradient> >>interior
{ 800 10 } >>dim
{ 1 0 } >>orientation
gadget.
] ($block) ;
: page-theme ( gadget -- )
- T{ gradient f { T{ rgba f 0.8 0.8 1.0 1.0 } T{ rgba f 0.8 1.0 1.0 1.0 } } }
+ { T{ rgba f 0.8 0.8 1.0 1.0 } T{ rgba f 0.8 1.0 1.0 1.0 } } <gradient>
>>interior drop ;
: <page> ( list -- gadget )
;
STRING: plane-fragment-shader
+uniform float checker_size_inv;
+uniform vec4 checker_color_1, checker_color_2;
varying vec3 object_position;
+
+bool
+checker_color(vec3 p)
+{
+ vec3 pprime = checker_size_inv * object_position;
+ return fract((floor(pprime.x) + floor(pprime.z)) * 0.5) == 0.0;
+}
+
void
main()
{
float distance_factor = (gl_FragCoord.z * 0.5 + 0.5);
distance_factor = pow(distance_factor, 500.0)*0.5;
- gl_FragColor = fract((floor(0.125*object_position.x)+floor(0.125*object_position.z)) * 0.5) == 0.0
- ? vec4(1.0, 1.0 - distance_factor, 1.0 - distance_factor, 1.0)
- : vec4(1.0, distance_factor, distance_factor, 1.0);
+ gl_FragColor = checker_color(object_position)
+ ? mix(checker_color_1, checker_color_2, distance_factor)
+ : mix(checker_color_2, checker_color_1, distance_factor);
}
;
TUPLE: spheres-gadget < demo-gadget
plane-program solid-sphere-program texture-sphere-program
reflection-framebuffer reflection-depthbuffer
- reflection-texture ;
+ reflection-texture initialized? ;
: <spheres-gadget> ( -- gadget )
20.0 10.0 20.0 spheres-gadget new-demo-gadget ;
(make-reflection-texture) >>reflection-texture
(make-reflection-depthbuffer) [ >>reflection-depthbuffer ] keep
(make-reflection-framebuffer) >>reflection-framebuffer
+ t >>initialized?
drop ;
M: spheres-gadget ungraft* ( gadget -- )
+ f >>initialized?
dup find-gl-context
{
[ reflection-framebuffer>> [ delete-framebuffer ] when* ]
] with-gl-program
] [
plane-program>> [
- drop
+ {
+ [ "checker_size_inv" glGetUniformLocation 0.125 glUniform1f ]
+ [ "checker_color_1" glGetUniformLocation 1.0 0.0 0.0 1.0 glUniform4f ]
+ [ "checker_color_2" glGetUniformLocation 1.0 1.0 1.0 1.0 glUniform4f ]
+ } cleave
GL_QUADS [
-1000.0 -30.0 1000.0 glVertex3f
-1000.0 -30.0 -1000.0 glVertex3f
] bi ;
: reflection-frustum ( gadget -- -x x -y y near far )
- [ near-plane ] [ far-plane ] bi [
- drop dup [ -+ ] bi@
- ] 2keep ;
+ [ near-plane ] [ far-plane ] bi
+ [ drop dup [ -+ ] bi@ ] 2keep ;
: (reflection-face) ( gadget face -- )
swap reflection-texture>> >r >r
[ dim>> 0 0 rot first2 glViewport ]
} cleave ] with-framebuffer ;
-M: spheres-gadget draw-gadget* ( gadget -- )
+: (draw-gadget) ( gadget -- )
GL_DEPTH_TEST glEnable
GL_SCISSOR_TEST glDisable
0.15 0.15 1.0 1.0 glClearColor {
]
} cleave ;
+M: spheres-gadget draw-gadget* ( gadget -- )
+ dup initialized?>> [ (draw-gadget) ] [ drop ] if ;
+
: spheres-window ( -- )
[ <spheres-gadget> "Spheres" open-window ] with-ui ;
+++ /dev/null
-Doug Coleman
+++ /dev/null
-USING: kernel state-tables tools.test ;
-IN: state-tables.tests
-
-: test-table
- <table>
- "a" "c" "z" <entry> over set-entry
- "a" "o" "y" <entry> over set-entry
- "a" "l" "x" <entry> over set-entry
- "b" "o" "y" <entry> over set-entry
- "b" "l" "x" <entry> over set-entry
- "b" "s" "u" <entry> over set-entry ;
-
-[
- T{
- table
- f
- H{
- { "a" H{ { "l" "x" } { "c" "z" } { "o" "y" } } }
- { "b" H{ { "l" "x" } { "s" "u" } { "o" "y" } } }
- }
- H{ { "l" t } { "s" t } { "c" t } { "o" t } }
- f
- H{ }
- }
-] [ test-table ] unit-test
-
-[ "x" t ] [ "a" "l" test-table get-entry ] unit-test
-[ "har" t ] [
- "a" "z" "har" <entry> test-table [ set-entry ] keep
- >r "a" "z" r> get-entry
-] unit-test
-
-: vector-test-table
- <vector-table>
- "a" "c" "z" <entry> over add-entry
- "a" "c" "r" <entry> over add-entry
- "a" "o" "y" <entry> over add-entry
- "a" "l" "x" <entry> over add-entry
- "b" "o" "y" <entry> over add-entry
- "b" "l" "x" <entry> over add-entry
- "b" "s" "u" <entry> over add-entry ;
-
-[
-T{ vector-table f
- H{
- { "a"
- H{ { "l" "x" } { "c" V{ "z" "r" } } { "o" "y" } } }
- { "b"
- H{ { "l" "x" } { "s" "u" } { "o" "y" } } }
- }
- H{ { "l" t } { "s" t } { "c" t } { "o" t } }
- f
- H{ }
-}
-] [ vector-test-table ] unit-test
-
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: kernel namespaces make sequences vectors assocs accessors ;
-IN: state-tables
-
-TUPLE: table rows columns start-state final-states ;
-TUPLE: entry row-key column-key value ;
-
-GENERIC: add-entry ( entry table -- )
-
-: make-table ( class -- obj )
- new
- H{ } clone >>rows
- H{ } clone >>columns
- H{ } clone >>final-states ;
-
-: <table> ( -- obj )
- table make-table ;
-
-C: <entry> entry
-
-: (add-row) ( row-key table -- row )
- 2dup rows>> at* [
- 2nip
- ] [
- drop H{ } clone [ -rot rows>> set-at ] keep
- ] if ;
-
-: add-row ( row-key table -- )
- (add-row) drop ;
-
-: add-column ( column-key table -- )
- t -rot columns>> set-at ;
-
-: set-row ( row row-key table -- )
- rows>> set-at ;
-
-: lookup-row ( row-key table -- row/f ? )
- rows>> at* ;
-
-: row-exists? ( row-key table -- ? )
- lookup-row nip ;
-
-: lookup-column ( column-key table -- column/f ? )
- columns>> at* ;
-
-: column-exists? ( column-key table -- ? )
- lookup-column nip ;
-
-ERROR: no-row key ;
-ERROR: no-column key ;
-
-: get-row ( row-key table -- row )
- dupd lookup-row [
- nip
- ] [
- drop no-row
- ] if ;
-
-: get-column ( column-key table -- column )
- dupd lookup-column [
- nip
- ] [
- drop no-column
- ] if ;
-
-: get-entry ( row-key column-key table -- obj ? )
- swapd lookup-row [
- at*
- ] [
- 2drop f f
- ] if ;
-
-: (set-entry) ( entry table -- value column-key row )
- [ >r column-key>> r> add-column ] 2keep
- dupd >r row-key>> r> (add-row)
- >r [ value>> ] keep column-key>> r> ;
-
-: set-entry ( entry table -- )
- (set-entry) set-at ;
-
-: delete-entry ( entry table -- )
- >r [ column-key>> ] [ row-key>> ] bi r>
- lookup-row [ delete-at ] [ 2drop ] if ;
-
-: swap-rows ( row-key1 row-key2 table -- )
- [ tuck get-row >r get-row r> ] 3keep
- >r >r rot r> r> [ set-row ] keep set-row ;
-
-: member?* ( obj obj -- bool )
- 2dup = [ 2drop t ] [ member? ] if ;
-
-: find-by-column ( column-key data table -- seq )
- swapd 2dup lookup-column 2drop
- [
- rows>> [
- pick swap at* [
- >r pick r> member?* [ , ] [ drop ] if
- ] [
- 2drop
- ] if
- ] assoc-each
- ] { } make 2nip ;
-
-
-TUPLE: vector-table < table ;
-: <vector-table> ( -- obj )
- vector-table make-table ;
-
-: add-hash-vector ( value key hash -- )
- 2dup at* [
- dup vector? [
- 2nip push
- ] [
- V{ } clone [ push ] keep
- -rot >r >r [ push ] keep r> r> set-at
- ] if
- ] [
- drop set-at
- ] if ;
-
-M: vector-table add-entry ( entry table -- )
- (set-entry) add-hash-vector ;
--- /dev/null
+
+USING: kernel lexer parser words quotations compiler.units ;
+
+IN: sto
+
+! Use 'sto' to bind a value on the stack to a word.
+!
+! Example:
+!
+! 10 sto A
+
+: sto
+ \ 1quotation parsed
+ scan
+ current-vocab create
+ dup set-word
+ literalize parsed
+ \ swap parsed
+ [ define ] parsed
+ \ with-compilation-unit parsed ; parsing
+++ /dev/null
-Alex Chapman
+++ /dev/null
-Alex Chapman
+++ /dev/null
-! Copyright (C) 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors alien.c-types combinators kernel locals math math.ranges openal sequences sequences.merged ;
-IN: synth.buffers
-
-TUPLE: buffer sample-freq 8bit? id ;
-
-: <buffer> ( sample-freq 8bit? -- buffer )
- f buffer boa ;
-
-TUPLE: mono-buffer < buffer data ;
-
-: <mono-buffer> ( sample-freq 8bit? -- buffer )
- f f mono-buffer boa ;
-
-: <8bit-mono-buffer> ( sample-freq -- buffer ) t <mono-buffer> ;
-: <16bit-mono-buffer> ( sample-freq -- buffer ) f <mono-buffer> ;
-
-TUPLE: stereo-buffer < buffer left-data right-data ;
-
-: <stereo-buffer> ( sample-freq 8bit? -- buffer )
- f f f stereo-buffer boa ;
-
-: <8bit-stereo-buffer> ( sample-freq -- buffer ) t <stereo-buffer> ;
-: <16bit-stereo-buffer> ( sample-freq -- buffer ) f <stereo-buffer> ;
-
-PREDICATE: 8bit-buffer < buffer 8bit?>> ;
-PREDICATE: 16bit-buffer < buffer 8bit?>> not ;
-INTERSECTION: 8bit-mono-buffer 8bit-buffer mono-buffer ;
-INTERSECTION: 16bit-mono-buffer 16bit-buffer mono-buffer ;
-INTERSECTION: 8bit-stereo-buffer 8bit-buffer stereo-buffer ;
-INTERSECTION: 16bit-stereo-buffer 16bit-buffer stereo-buffer ;
-
-GENERIC: buffer-format ( buffer -- format )
-M: 8bit-mono-buffer buffer-format drop AL_FORMAT_MONO8 ;
-M: 16bit-mono-buffer buffer-format drop AL_FORMAT_MONO16 ;
-M: 8bit-stereo-buffer buffer-format drop AL_FORMAT_STEREO8 ;
-M: 16bit-stereo-buffer buffer-format drop AL_FORMAT_STEREO16 ;
-
-: 8bit-buffer-data ( seq -- data size )
- [ 128 * >integer 128 + ] map [ >c-uchar-array ] [ length ] bi ;
-
-: 16bit-buffer-data ( seq -- data size )
- [ 32768 * >integer ] map [ >c-short-array ] [ length 2 * ] bi ;
-
-: stereo-data ( stereo-buffer -- left right )
- [ left-data>> ] [ right-data>> ] bi@ ;
-
-: interleaved-stereo-data ( stereo-buffer -- data )
- stereo-data <2merged> ;
-
-GENERIC: buffer-data ( buffer -- data size )
-M: 8bit-mono-buffer buffer-data data>> 8bit-buffer-data ;
-M: 16bit-mono-buffer buffer-data data>> 16bit-buffer-data ;
-M: 8bit-stereo-buffer buffer-data
- interleaved-stereo-data 8bit-buffer-data ;
-M: 16bit-stereo-buffer buffer-data
- interleaved-stereo-data 16bit-buffer-data ;
-
-: telephone-sample-freq 8000 ;
-: half-sample-freq 22050 ;
-: cd-sample-freq 44100 ;
-: digital-sample-freq 48000 ;
-: professional-sample-freq 88200 ;
-
-: send-buffer ( buffer -- buffer )
- {
- [ gen-buffer dup [ >>id ] dip ]
- [ buffer-format ]
- [ buffer-data ]
- [ sample-freq>> alBufferData ]
- } cleave ;
-
-: ?send-buffer ( buffer -- buffer )
- dup id>> [ send-buffer ] unless ;
-
+++ /dev/null
-Alex Chapman
+++ /dev/null
-! Copyright (C) 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays kernel namespaces make openal sequences
-synth synth.buffers ;
-IN: synth.example
-
-: play-sine-wave ( freq seconds sample-freq -- )
- init-openal
- <16bit-mono-buffer> >sine-wave-buffer send-buffer id>>
- 1 gen-sources first
- [ AL_BUFFER rot set-source-param ] [ source-play ] bi
- check-error ;
-
-: test-instrument1 ( -- harmonics )
- [
- 1 0.5 <harmonic> ,
- 2 0.125 <harmonic> ,
- 3 0.0625 <harmonic> ,
- 4 0.03125 <harmonic> ,
- ] { } make ;
-
-: test-instrument2 ( -- harmonics )
- [
- 1 0.25 <harmonic> ,
- 2 0.25 <harmonic> ,
- 3 0.25 <harmonic> ,
- 4 0.25 <harmonic> ,
- ] { } make ;
-
-: sine-instrument ( -- harmonics )
- 1 1 <harmonic> 1array ;
-
-: test-note-buffer ( note -- )
- init-openal
- test-instrument2 swap cd-sample-freq <16bit-mono-buffer>
- >note send-buffer id>>
- 1 gen-sources first [ swap queue-buffer ] [ source-play ] bi
- check-error ;
+++ /dev/null
-Simple sound synthesis using OpenAL.
+++ /dev/null
-! Copyright (C) 2008 Alex Chapman
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel locals math math.constants math.functions memoize openal synth.buffers sequences sequences.modified sequences.repeating ;
-IN: synth
-
-MEMO: single-sine-wave ( samples/wave -- seq )
- pi 2 * over / [ * sin ] curry map ;
-
-: (sine-wave) ( samples/wave n-samples -- seq )
- [ single-sine-wave ] dip <repeating> ;
-
-: sine-wave ( sample-freq freq seconds -- seq )
- pick * >integer [ /i ] dip (sine-wave) ;
-
-: >sine-wave-buffer ( freq seconds buffer -- buffer )
- [ sample-freq>> -rot sine-wave ] keep swap >>data ;
-
-: >silent-buffer ( seconds buffer -- buffer )
- tuck sample-freq>> * >integer 0 <repetition> >>data ;
-
-TUPLE: harmonic n amplitude ;
-C: <harmonic> harmonic
-
-TUPLE: note hz secs ;
-C: <note> note
-
-: harmonic-freq ( note harmonic -- freq )
- n>> swap hz>> * ;
-
-:: note-harmonic-data ( harmonic note buffer -- data )
- buffer sample-freq>> note harmonic harmonic-freq note secs>> sine-wave
- harmonic amplitude>> <scaled> ;
-
-: >note ( harmonics note buffer -- buffer )
- dup -roll [ note-harmonic-data ] 2curry map <summed> >>data ;
-
--- /dev/null
+Doug Coleman
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: system ;
+IN: system-info.backend
+
+HOOK: cpus os ( -- n )
+HOOK: cpu-mhz os ( -- n )
+HOOK: memory-load os ( -- n )
+HOOK: physical-mem os ( -- n )
+HOOK: available-mem os ( -- n )
+HOOK: total-page-file os ( -- n )
+HOOK: available-page-file os ( -- n )
+HOOK: total-virtual-mem os ( -- n )
+HOOK: available-virtual-mem os ( -- n )
+HOOK: available-virtual-extended-mem os ( -- n )
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: unix alien alien.c-types kernel math sequences strings
+io.unix.backend splitting ;
+IN: system-info.linux
+
+: (uname) ( buf -- int )
+ "int" f "uname" { "char*" } alien-invoke ;
+
+: uname ( -- seq )
+ 65536 "char" <c-array> [ (uname) io-error ] keep
+ "\0" split harvest [ >string ] map
+ 6 "" pad-right ;
+
+: sysname ( -- string ) uname first ;
+: nodename ( -- string ) uname second ;
+: release ( -- string ) uname third ;
+: version ( -- string ) uname fourth ;
+: machine ( -- string ) uname 4 swap nth ;
+: domainname ( -- string ) uname 5 swap nth ;
+
+: kernel-version ( -- seq )
+ release ".-" split harvest 5 "" pad-right ;
--- /dev/null
+unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types alien.strings alien.syntax
+byte-arrays kernel namespaces sequences unix
+system-info.backend system io.unix.backend io.encodings.utf8 ;
+IN: system-info.macosx
+
+! See /usr/include/sys/sysctl.h for constants
+
+LIBRARY: libc
+FUNCTION: int sysctl ( int* name, uint namelen, void* oldp, size_t* oldlenp, void* newp, size_t newlen ) ;
+
+: make-int-array ( seq -- byte-array )
+ [ <int> ] map concat ;
+
+: (sysctl-query) ( name namelen oldp oldlenp -- oldp )
+ over [ f 0 sysctl io-error ] dip ;
+
+: sysctl-query ( seq n -- byte-array )
+ [ [ make-int-array ] [ length ] bi ] dip
+ [ <byte-array> ] [ <uint> ] bi (sysctl-query) ;
+
+: sysctl-query-string ( seq -- n )
+ 4096 sysctl-query utf8 alien>string ;
+
+: sysctl-query-uint ( seq -- n )
+ 4 sysctl-query *uint ;
+
+: sysctl-query-ulonglong ( seq -- n )
+ 8 sysctl-query *ulonglong ;
+
+: machine ( -- str ) { 6 1 } sysctl-query-string ;
+: model ( -- str ) { 6 2 } sysctl-query-string ;
+M: macosx cpus ( -- n ) { 6 3 } sysctl-query-uint ;
+: byte-order ( -- n ) { 6 4 } sysctl-query-uint ;
+M: macosx physical-mem ( -- n ) { 6 5 } sysctl-query-uint ;
+: user-mem ( -- n ) { 6 6 } sysctl-query-uint ;
+: page-size ( -- n ) { 6 7 } sysctl-query-uint ;
+: disknames ( -- n ) { 6 8 } 8 sysctl-query ;
+: diskstats ( -- n ) { 6 9 } 8 sysctl-query ;
+: epoch ( -- n ) { 6 10 } sysctl-query-uint ;
+: floating-point ( -- n ) { 6 11 } sysctl-query-uint ;
+: machine-arch ( -- n ) { 6 12 } sysctl-query-string ;
+: vector-unit ( -- n ) { 6 13 } sysctl-query-uint ;
+: bus-frequency ( -- n ) { 6 14 } sysctl-query-uint ;
+M: macosx cpu-mhz ( -- n ) { 6 15 } sysctl-query-uint ;
+: cacheline-size ( -- n ) { 6 16 } sysctl-query-uint ;
+: l1-icache-size ( -- n ) { 6 17 } sysctl-query-uint ;
+: l1-dcache-size ( -- n ) { 6 18 } sysctl-query-uint ;
+: l2-cache-settings ( -- n ) { 6 19 } sysctl-query-uint ;
+: l2-cache-size ( -- n ) { 6 20 } sysctl-query-uint ;
+: l3-cache-settings ( -- n ) { 6 21 } sysctl-query-uint ;
+: l3-cache-size ( -- n ) { 6 22 } sysctl-query-uint ;
+: tb-frequency ( -- n ) { 6 23 } sysctl-query-uint ;
+: mem-size ( -- n ) { 6 24 } sysctl-query-ulonglong ;
+: available-cpus ( -- n ) { 6 25 } sysctl-query-uint ;
--- /dev/null
+unportable
--- /dev/null
+Query the operating system for hardware information in a platform-independent way
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.syntax kernel math prettyprint io math.parser
+combinators vocabs.loader system-info.backend system ;
+IN: system-info
+
+: write-unit ( x n str -- )
+ [ 2^ /f number>string write bl ] [ write ] bi* ;
+
+: kb ( x -- ) 10 "kB" write-unit ;
+: megs ( x -- ) 20 "MB" write-unit ;
+: gigs ( x -- ) 30 "GB" write-unit ;
+: ghz ( x -- ) 1000000000 /f number>string write bl "GHz" write ;
+
+<< {
+ { [ os windows? ] [ "system-info.windows" ] }
+ { [ os linux? ] [ "system-info.linux" ] }
+ { [ os macosx? ] [ "system-info.macosx" ] }
+ [ f ]
+} cond [ require ] when* >>
+
+: system-report. ( -- )
+ "CPUs: " write cpus number>string write nl
+ "CPU Speed: " write cpu-mhz ghz nl
+ "Physical RAM: " write physical-mem megs nl ;
--- /dev/null
+Doug Coleman
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.c-types system-info kernel math namespaces
+windows windows.kernel32 system-info.backend system ;
+IN: system-info.windows.ce
+
+: memory-status ( -- MEMORYSTATUS )
+ "MEMORYSTATUS" <c-object>
+ "MEMORYSTATUS" heap-size over set-MEMORYSTATUS-dwLength
+ dup GlobalMemoryStatus ;
+
+M: wince cpus ( -- n ) 1 ;
+
+M: wince memory-load ( -- n )
+ memory-status MEMORYSTATUS-dwMemoryLoad ;
+
+M: wince physical-mem ( -- n )
+ memory-status MEMORYSTATUS-dwTotalPhys ;
+
+M: wince available-mem ( -- n )
+ memory-status MEMORYSTATUS-dwAvailPhys ;
+
+M: wince total-page-file ( -- n )
+ memory-status MEMORYSTATUS-dwTotalPageFile ;
+
+M: wince available-page-file ( -- n )
+ memory-status MEMORYSTATUS-dwAvailPageFile ;
+
+M: wince total-virtual-mem ( -- n )
+ memory-status MEMORYSTATUS-dwTotalVirtual ;
+
+M: wince available-virtual-mem ( -- n )
+ memory-status MEMORYSTATUS-dwAvailVirtual ;
--- /dev/null
+unportable
--- /dev/null
+Doug Coleman
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types alien.strings
+kernel libc math namespaces system-info.backend
+system-info.windows windows windows.advapi32
+windows.kernel32 system byte-arrays ;
+IN: system-info.windows.nt
+
+M: winnt cpus ( -- n )
+ system-info SYSTEM_INFO-dwNumberOfProcessors ;
+
+: memory-status ( -- MEMORYSTATUSEX )
+ "MEMORYSTATUSEX" <c-object>
+ "MEMORYSTATUSEX" heap-size over set-MEMORYSTATUSEX-dwLength
+ dup GlobalMemoryStatusEx win32-error=0/f ;
+
+M: winnt memory-load ( -- n )
+ memory-status MEMORYSTATUSEX-dwMemoryLoad ;
+
+M: winnt physical-mem ( -- n )
+ memory-status MEMORYSTATUSEX-ullTotalPhys ;
+
+M: winnt available-mem ( -- n )
+ memory-status MEMORYSTATUSEX-ullAvailPhys ;
+
+M: winnt total-page-file ( -- n )
+ memory-status MEMORYSTATUSEX-ullTotalPageFile ;
+
+M: winnt available-page-file ( -- n )
+ memory-status MEMORYSTATUSEX-ullAvailPageFile ;
+
+M: winnt total-virtual-mem ( -- n )
+ memory-status MEMORYSTATUSEX-ullTotalVirtual ;
+
+M: winnt available-virtual-mem ( -- n )
+ memory-status MEMORYSTATUSEX-ullAvailVirtual ;
+
+: computer-name ( -- string )
+ MAX_COMPUTERNAME_LENGTH 1+
+ [ <byte-array> dup ] keep <uint>
+ GetComputerName win32-error=0/f alien>native-string ;
+
+: username ( -- string )
+ UNLEN 1+
+ [ <byte-array> dup ] keep <uint>
+ GetUserName win32-error=0/f alien>native-string ;
--- /dev/null
+unportable
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2008 Doug Coleman.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien alien.c-types kernel libc math namespaces
+windows windows.kernel32 windows.advapi32
+words combinators vocabs.loader system-info.backend
+system alien.strings ;
+IN: system-info.windows
+
+: system-info ( -- SYSTEM_INFO )
+ "SYSTEM_INFO" <c-object> [ GetSystemInfo ] keep ;
+
+: page-size ( -- n )
+ system-info SYSTEM_INFO-dwPageSize ;
+
+! 386, 486, 586, 2200 (IA64), 8664 (AMD_X8664)
+: processor-type ( -- n )
+ system-info SYSTEM_INFO-dwProcessorType ;
+
+! 0 = x86, 6 = Intel Itanium, 9 = x64 (AMD or Intel), 10 = WOW64, 0xffff = Unk
+: processor-architecture ( -- n )
+ system-info SYSTEM_INFO-dwOemId HEX: ffff0000 bitand ;
+
+: os-version ( -- os-version )
+ "OSVERSIONINFO" <c-object>
+ "OSVERSIONINFO" heap-size over set-OSVERSIONINFO-dwOSVersionInfoSize
+ dup GetVersionEx win32-error=0/f ;
+
+: windows-major ( -- n )
+ os-version OSVERSIONINFO-dwMajorVersion ;
+
+: windows-minor ( -- n )
+ os-version OSVERSIONINFO-dwMinorVersion ;
+
+: windows-build# ( -- n )
+ os-version OSVERSIONINFO-dwBuildNumber ;
+
+: windows-platform-id ( -- n )
+ os-version OSVERSIONINFO-dwPlatformId ;
+
+: windows-service-pack ( -- string )
+ os-version OSVERSIONINFO-szCSDVersion alien>native-string ;
+
+: feature-present? ( n -- ? )
+ IsProcessorFeaturePresent zero? not ;
+
+: sse2? ( -- ? )
+ PF_XMMI64_INSTRUCTIONS_AVAILABLE feature-present? ;
+
+: sse3? ( -- ? )
+ PF_SSE3_INSTRUCTIONS_AVAILABLE feature-present? ;
+
+: <u16-string-object> ( n -- obj )
+ "ushort" <c-array> ;
+
+: get-directory ( word -- str )
+ [ MAX_UNICODE_PATH [ <u16-string-object> ] keep dupd ] dip
+ execute win32-error=0/f alien>native-string ; inline
+
+: windows-directory ( -- str )
+ \ GetWindowsDirectory get-directory ;
+
+: system-directory ( -- str )
+ \ GetSystemDirectory get-directory ;
+
+: system-windows-directory ( -- str )
+ \ GetSystemWindowsDirectory get-directory ;
+
+<<
+{
+ { [ os wince? ] [ "system-info.windows.ce" ] }
+ { [ os winnt? ] [ "system-info.windows.nt" ] }
+} cond require >>
USING: kernel money tools.test
taxes.usa taxes.usa.federal taxes.usa.mn
-taxes.utils taxes.usa.w4 usa-cities ;
+calendar taxes.usa.w4 usa-cities math.finance ;
IN: taxes.usa.tests
[
+++ /dev/null
-! Copyright (C) 2008 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: math ;
-IN: taxes.utils
-
-: monthly ( x -- y ) 12 / ;
-: semimonthly ( x -- y ) 24 / ;
-: biweekly ( x -- y ) 26 / ;
-: weekly ( x -- y ) 52 / ;
-: daily ( x -- y ) 360 / ;
--- /dev/null
+John Benediktsson
--- /dev/null
+
+USING: help.syntax help.markup kernel prettyprint sequences strings ;
+
+IN: time
+
+HELP: strftime
+{ $values { "format-string" string } }
+{ $description "Writes the timestamp (specified on the stack) formatted according to the format string." }
+;
+
+ARTICLE: "strftime" "Formatted timestamps"
+"The " { $vocab-link "time" } " vocabulary is used for formatted timestamps.\n"
+{ $subsection strftime }
+"\n"
+"Several format specifications exist for handling arguments of different types, and specifying attributes for the result string, including such things as maximum width, padding, and decimals.\n"
+{ $table
+ { "%a" "Abbreviated weekday name." }
+ { "%A" "Full weekday name." }
+ { "%b" "Abbreviated month name." }
+ { "%B" "Full month name." }
+ { "%c" "Date and time representation." }
+ { "%d" "Day of the month as a decimal number [01,31]." }
+ { "%H" "Hour (24-hour clock) as a decimal number [00,23]." }
+ { "%I" "Hour (12-hour clock) as a decimal number [01,12]." }
+ { "%j" "Day of the year as a decimal number [001,366]." }
+ { "%m" "Month as a decimal number [01,12]." }
+ { "%M" "Minute as a decimal number [00,59]." }
+ { "%p" "Either AM or PM." }
+ { "%S" "Second as a decimal number [00,59]." }
+ { "%U" "Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]." }
+ { "%w" "Weekday as a decimal number [0(Sunday),6]." }
+ { "%W" "Week number of the year (Monday as the first day of the week) as a decimal number [00,53]." }
+ { "%x" "Date representation." }
+ { "%X" "Time representation." }
+ { "%y" "Year without century as a decimal number [00,99]." }
+ { "%Y" "Year with century as a decimal number." }
+ { "%Z" "Time zone name (no characters if no time zone exists)." }
+ { "%%" "A literal '%' character." }
+} ;
+
+ABOUT: "strftime"
+
+
--- /dev/null
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: kernel time tools.test calendar ;
+
+IN: time.tests
+
+[ "%H:%M:%S" strftime ] must-infer
+
+: testtime ( -- timestamp )
+ 2008 10 9 12 3 15 instant <timestamp> ;
+
+[ t ] [ "12:03:15" testtime "%H:%M:%S" strftime = ] unit-test
+[ t ] [ "12:03:15" testtime "%X" strftime = ] unit-test
+
+[ t ] [ "10/09/2008" testtime "%m/%d/%Y" strftime = ] unit-test
+[ t ] [ "10/09/2008" testtime "%x" strftime = ] unit-test
+
+[ t ] [ "Thu" testtime "%a" strftime = ] unit-test
+[ t ] [ "Thursday" testtime "%A" strftime = ] unit-test
+
+[ t ] [ "Oct" testtime "%b" strftime = ] unit-test
+[ t ] [ "October" testtime "%B" strftime = ] unit-test
+
--- /dev/null
+! Copyright (C) 2008 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: accessors arrays calendar io kernel fry macros math
+math.functions math.parser peg.ebnf sequences strings vectors ;
+
+IN: time
+
+: >timestring ( timestamp -- string )
+ [ hour>> ] keep [ minute>> ] keep second>> 3array
+ [ number>string 2 CHAR: 0 pad-left ] map ":" join ; inline
+
+: >datestring ( timestamp -- string )
+ [ month>> ] keep [ day>> ] keep year>> 3array
+ [ number>string 2 CHAR: 0 pad-left ] map "/" join ; inline
+
+: (week-of-year) ( timestamp day -- n )
+ [ dup clone 1 >>month 1 >>day day-of-week dup ] dip > [ 7 swap - ] when
+ [ day-of-year ] dip 2dup < [ 0 2nip ] [ - 7 / 1+ >fixnum ] if ;
+
+: week-of-year-sunday ( timestamp -- n ) 0 (week-of-year) ; inline
+
+: week-of-year-monday ( timestamp -- n ) 1 (week-of-year) ; inline
+
+
+<PRIVATE
+
+EBNF: parse-format-string
+
+fmt-% = "%" => [[ [ "%" ] ]]
+fmt-a = "a" => [[ [ dup day-of-week day-abbreviation3 ] ]]
+fmt-A = "A" => [[ [ dup day-of-week day-name ] ]]
+fmt-b = "b" => [[ [ dup month>> month-abbreviation ] ]]
+fmt-B = "B" => [[ [ dup month>> month-name ] ]]
+fmt-c = "c" => [[ [ "Not yet implemented" throw ] ]]
+fmt-d = "d" => [[ [ dup day>> number>string 2 CHAR: 0 pad-left ] ]]
+fmt-H = "H" => [[ [ dup hour>> number>string 2 CHAR: 0 pad-left ] ]]
+fmt-I = "I" => [[ [ dup hour>> 12 > [ 12 - ] when number>string 2 CHAR: 0 pad-left ] ]]
+fmt-j = "j" => [[ [ dup day-of-year number>string ] ]]
+fmt-m = "m" => [[ [ dup month>> number>string 2 CHAR: 0 pad-left ] ]]
+fmt-M = "M" => [[ [ dup minute>> number>string 2 CHAR: 0 pad-left ] ]]
+fmt-p = "p" => [[ [ dup hour>> 12 < [ "AM" ] [ "PM" ] ? ] ]]
+fmt-S = "S" => [[ [ dup second>> round number>string 2 CHAR: 0 pad-left ] ]]
+fmt-U = "U" => [[ [ dup week-of-year-sunday ] ]]
+fmt-w = "w" => [[ [ dup day-of-week number>string ] ]]
+fmt-W = "W" => [[ [ dup week-of-year-monday ] ]]
+fmt-x = "x" => [[ [ dup >datestring ] ]]
+fmt-X = "X" => [[ [ dup >timestring ] ]]
+fmt-y = "y" => [[ [ dup year>> 100 mod number>string ] ]]
+fmt-Y = "Y" => [[ [ dup year>> number>string ] ]]
+fmt-Z = "Z" => [[ [ "Not yet implemented" throw ] ]]
+unknown = (.)* => [[ "Unknown directive" throw ]]
+
+formats_ = fmt-%|fmt-a|fmt-A|fmt-b|fmt-B|fmt-c|fmt-d|fmt-H|fmt-I|
+ fmt-j|fmt-m|fmt-M|fmt-p|fmt-S|fmt-U|fmt-w|fmt-W|fmt-x|
+ fmt-X|fmt-y|fmt-Y|fmt-Z|unknown
+
+formats = "%" (formats_) => [[ second '[ _ dip ] ]]
+
+plain-text = (!("%").)+ => [[ >string '[ _ swap ] ]]
+
+text = (formats|plain-text)* => [[ reverse [ [ [ push ] keep ] append ] map ]]
+
+;EBNF
+
+PRIVATE>
+
+MACRO: strftime ( format-string -- )
+ parse-format-string [ length ] keep [ ] join
+ '[ _ <vector> @ reverse concat nip ] ;
+
+
--- /dev/null
+
+USING: kernel accessors locals namespaces sequences sequences.lib threads
+ math math.order math.vectors
+ calendar
+ colors opengl ui ui.gadgets ui.gestures ui.render
+ circular
+ processing.shapes ;
+
+IN: trails
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! Example 33-15 from the Processing book
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! Return the mouse location relative to the current gadget
+
+: mouse ( -- point ) hand-loc get hand-gadget get screen-loc v- ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: point-list ( n -- seq ) [ drop { 0 0 } ] map <circular> ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: percent->radius ( percent -- radius ) neg 1 + 25 * 5 max ;
+
+: dot ( pos percent -- ) percent->radius circle ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+TUPLE: <trails-gadget> < gadget paused points ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+:: iterate-system ( GADGET -- )
+
+ ! Add a valid point if the mouse is in the gadget
+ ! Otherwise, add an "invisible" point
+
+ hand-gadget get GADGET =
+ [ mouse GADGET points>> push-circular ]
+ [ { -10 -10 } GADGET points>> push-circular ]
+ if ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+:: start-trails-thread ( GADGET -- )
+ GADGET f >>paused drop
+ [
+ [
+ GADGET paused>>
+ [ f ]
+ [ GADGET iterate-system GADGET relayout-1 1 milliseconds sleep t ]
+ if
+ ]
+ loop
+ ]
+ in-thread ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+M: <trails-gadget> pref-dim* ( <trails-gadget> -- dim ) drop { 500 500 } ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+M:: <trails-gadget> draw-gadget* ( GADGET -- )
+ origin get
+ [
+ T{ rgba f 1 1 1 0.4 } \ fill-color set ! White, with some transparency
+ T{ rgba f 0 0 0 0 } \ stroke-color set ! no stroke
+
+ black gl-clear
+
+ GADGET points>> [ dot ] each-percent
+ ]
+ with-translation ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: trails-gadget ( -- <trails-gadget> )
+
+ <trails-gadget> new-gadget
+
+ 300 point-list >>points
+
+ t >>clipped?
+
+ dup start-trails-thread ;
+
+: trails-window ( -- ) [ trails-gadget "Trails" open-window ] with-ui ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+MAIN: trails-window
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel accessors ui ui.gadgets ui.gadgets.buttons ui.render ;
+IN: ui.gadgets.broken
+
+! An intentionally broken gadget -- used to test UI error handling,
+! make sure that one bad gadget doesn't bring the whole system down
+
+: <bad-button> ( -- button )
+ "Click me if you dare"
+ [ "Haha" throw ]
+ <bevel-button> ;
+
+TUPLE: bad-gadget < gadget ;
+
+M: bad-gadget draw-gadget* "Lulz" throw ;
+
+M: bad-gadget pref-dim* drop { 100 100 } ;
+
+: <bad-gadget> ( -- gadget ) bad-gadget new-gadget ;
+
+: bad-gadget-test ( -- )
+ <bad-button> "Test 1" open-window
+ <bad-gadget> "Test 2" open-window ;
+
+MAIN: bad-gadget-test
+++ /dev/null
-
-USING: kernel quotations arrays sequences math math.ranges fry
- opengl opengl.gl ui.render ui.gadgets.cartesian processing.shapes
- accessors ;
-
-IN: ui.gadgets.plot
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-TUPLE: plot < cartesian functions points ;
-
-: init-plot ( plot -- plot )
- init-cartesian
- { } >>functions
- 100 >>points ;
-
-: <plot> ( -- plot ) plot new init-plot ;
-
-: step-size ( plot -- step-size )
- [ [ x-max>> ] [ x-min>> ] bi - ] [ points>> ] bi / ;
-
-: plot-range ( plot -- range )
- [ x-min>> ] [ x-max>> ] [ step-size ] tri <range> ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-TUPLE: function function color ;
-
-GENERIC: plot-function ( plot object -- plot )
-
-M: callable plot-function ( plot quotation -- plot )
- >r dup plot-range r> '[ dup @ 2array ] map line-strip ;
-
-M: function plot-function ( plot function -- plot )
- dup color>> dup [ >stroke-color ] [ drop ] if
- >r dup plot-range r> function>> '[ dup @ 2array ] map line-strip ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: plot-functions ( plot -- plot ) dup functions>> [ plot-function ] each ;
-
-: draw-axis ( plot -- plot )
- dup
- [ [ x-min>> ] [ drop 0 ] bi 2array ]
- [ [ x-max>> ] [ drop 0 ] bi 2array ] bi line*
- dup
- [ [ drop 0 ] [ y-min>> ] bi 2array ]
- [ [ drop 0 ] [ y-max>> ] bi 2array ] bi line* ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-USING: ui.gadgets.slate ;
-
-M: plot draw-slate ( plot -- plot )
- 2 glLineWidth
- draw-axis
- plot-functions
- fill-mode
- 1 glLineWidth ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: add-function ( plot function -- plot )
- over functions>> swap suffix >>functions ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: x-span ( plot -- span ) [ x-max>> ] [ x-min>> ] bi - ;
-: y-span ( plot -- span ) [ y-max>> ] [ y-min>> ] bi - ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-USING: ui.gestures ui.gadgets ;
-
-: left ( plot -- plot )
- dup [ x-min>> ] [ x-span 1/10 * ] bi - >>x-min
- dup [ x-max>> ] [ x-span 1/10 * ] bi - >>x-max
- dup relayout-1 ;
-
-: right ( plot -- plot )
- dup [ x-min>> ] [ x-span 1/10 * ] bi + >>x-min
- dup [ x-max>> ] [ x-span 1/10 * ] bi + >>x-max
- dup relayout-1 ;
-
-: down ( plot -- plot )
- dup [ y-min>> ] [ y-span 1/10 * ] bi - >>y-min
- dup [ y-max>> ] [ y-span 1/10 * ] bi - >>y-max
- dup relayout-1 ;
-
-: up ( plot -- plot )
- dup [ y-min>> ] [ y-span 1/10 * ] bi + >>y-min
- dup [ y-max>> ] [ y-span 1/10 * ] bi + >>y-max
- dup relayout-1 ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: zoom-in-horizontal ( plot -- plot )
- dup [ x-min>> ] [ x-span 1/10 * ] bi + >>x-min
- dup [ x-max>> ] [ x-span 1/10 * ] bi - >>x-max ;
-
-: zoom-in-vertical ( plot -- plot )
- dup [ y-min>> ] [ y-span 1/10 * ] bi + >>y-min
- dup [ y-max>> ] [ y-span 1/10 * ] bi - >>y-max ;
-
-: zoom-in ( plot -- plot )
- zoom-in-horizontal
- zoom-in-vertical
- dup relayout-1 ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: zoom-out-horizontal ( plot -- plot )
- dup [ x-min>> ] [ x-span 1/10 * ] bi - >>x-min
- dup [ x-max>> ] [ x-span 1/10 * ] bi + >>x-max ;
-
-: zoom-out-vertical ( plot -- plot )
- dup [ y-min>> ] [ y-span 1/10 * ] bi - >>y-min
- dup [ y-max>> ] [ y-span 1/10 * ] bi + >>y-max ;
-
-: zoom-out ( plot -- plot )
- zoom-out-horizontal
- zoom-out-vertical
- dup relayout-1 ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-plot
- H{
- { T{ mouse-enter } [ request-focus ] }
- { T{ key-down f f "LEFT" } [ left drop ] }
- { T{ key-down f f "RIGHT" } [ right drop ] }
- { T{ key-down f f "DOWN" } [ down drop ] }
- { T{ key-down f f "UP" } [ up drop ] }
- { T{ key-down f f "a" } [ zoom-in drop ] }
- { T{ key-down f f "z" } [ zoom-out drop ] }
- }
-set-gestures
\ No newline at end of file
\r
DEFER: (del-page)\r
\r
-:: add-toggle ( model n name toggler -- )\r
+:: add-toggle ( n name model toggler -- )\r
<frame>\r
- n name toggler parent>> '[ _ _ _ (del-page) ] "X" swap <bevel-button>\r
+ n name toggler parent>> '[ drop _ _ _ (del-page) ] "X" swap <bevel-button>\r
@right grid-add\r
n model name <toggle-button> @center grid-add\r
toggler swap add-gadget drop ;\r
[ names>> ] [ model>> ] [ toggler>> ] tri\r
[ clear-gadget ] keep\r
[ [ length ] keep ] 2dip\r
- '[ [ _ ] 2dip _ add-toggle ] 2each ;\r
+ '[ _ _ add-toggle ] 2each ;\r
\r
: refresh-book ( tabbed -- )\r
model>> [ ] change-model ;\r
\r
: add-page ( page name tabbed -- )\r
[ names>> push ] 2keep\r
- [ [ model>> swap ]\r
- [ names>> length 1 - swap ]\r
+ [ [ names>> length 1 - swap ]\r
+ [ model>> ]\r
[ toggler>> ] tri add-toggle ]\r
[ content>> swap add-gadget drop ]\r
[ refresh-book ] tri ;\r
--- /dev/null
+! Copyright (C) 2008 Joe Groff.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax kernel quotations ui.gadgets
+graphics.bitmap strings ui.gadgets.worlds ;
+IN: ui.offscreen
+
+HELP: <offscreen-world>
+{ $values
+ { "gadget" gadget } { "title" string } { "status" "a boolean" }
+ { "world" offscreen-world }
+}
+{ $description "Constructs an " { $link offscreen-world } " gadget with " { $snippet "gadget" } " as its only child. Generally you should use " { $link open-offscreen } " or " { $link do-offscreen } " instead of calling this word directly." } ;
+
+HELP: close-offscreen
+{ $values
+ { "world" offscreen-world }
+}
+{ $description "Releases the resources used by the rendering buffer for " { $snippet "world" } "." } ;
+
+HELP: do-offscreen
+{ $values
+ { "gadget" gadget } { "quot" quotation }
+}
+{ $description "Constructs an " { $link offscreen-world } " around " { $snippet "gadget" } " with " { $link open-offscreen } ", calls " { $snippet "quotation" } " with the world on the top of the stack, and cleans up the world with " { $link close-offscreen } " at the end of " { $snippet "quotation" } "." } ;
+
+HELP: gadget>bitmap
+{ $values
+ { "gadget" gadget }
+ { "bitmap" bitmap }
+}
+{ $description "Renders " { $snippet "gadget" } " to an " { $link offscreen-world } " and creates a " { $link bitmap } " from its contents." } ;
+
+HELP: offscreen-world
+{ $class-description "The class of " { $link world } " objects that render to an offscreen buffer." } ;
+
+HELP: offscreen-world>bitmap
+{ $values
+ { "world" offscreen-world }
+ { "bitmap" bitmap }
+}
+{ $description "Saves a copy of the contents of " { $snippet "world" } " to a " { $link bitmap } " object." } ;
+
+HELP: open-offscreen
+{ $values
+ { "gadget" gadget }
+ { "world" offscreen-world }
+}
+{ $description "Creates and sets up an " { $link offscreen-world } " with " { $snippet "gadget" } " as its only child." } ;
+
+{ offscreen-world open-offscreen close-offscreen do-offscreen } related-words
+
+ARTICLE: "ui.offscreen" "Offscreen UI rendering"
+"The " { $vocab-link "ui.offscreen" } " provides words for rendering gadgets to an offscreen buffer so that bitmaps can be made from their contents."
+{ $subsection offscreen-world }
+"Opening gadgets offscreen:"
+{ $subsection open-offscreen }
+{ $subsection close-offscreen }
+{ $subsection do-offscreen }
+"Creating bitmaps from offscreen buffers:"
+{ $subsection offscreen-world>bitmap }
+{ $subsection gadget>bitmap } ;
+
+ABOUT: "ui.offscreen"
--- /dev/null
+! (c) 2008 Joe Groff, see license for details
+USING: accessors continuations graphics.bitmap kernel math
+sequences ui.gadgets ui.gadgets.worlds ui ui.backend
+destructors ;
+IN: ui.offscreen
+
+TUPLE: offscreen-world < world ;
+
+: <offscreen-world> ( gadget title status -- world )
+ offscreen-world new-world ;
+
+M: offscreen-world graft*
+ (open-offscreen-buffer) ;
+
+M: offscreen-world ungraft*
+ [ (ungraft-world) ]
+ [ handle>> (close-offscreen-buffer) ]
+ [ reset-world ] tri ;
+
+: open-offscreen ( gadget -- world )
+ "" f <offscreen-world>
+ [ open-world-window dup relayout-1 ] keep
+ notify-queued ;
+
+: close-offscreen ( world -- )
+ ungraft notify-queued ;
+
+: offscreen-world>bitmap ( world -- bitmap )
+ offscreen-pixels bgra>bitmap ;
+
+: do-offscreen ( gadget quot: ( offscreen-world -- ) -- )
+ [ open-offscreen ] dip
+ over [ slip ] [ close-offscreen ] [ ] cleanup ; inline
+
+: gadget>bitmap ( gadget -- bitmap )
+ [ offscreen-world>bitmap ] do-offscreen ;
--- /dev/null
+Offscreen world gadgets for rendering UI elements to bitmaps
--- /dev/null
+unportable
+ui
+graphics
--- /dev/null
+! Copyright (C) 2008 Slava Pestov.
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors colors arrays kernel sequences math byte-arrays
+namespaces grouping fry cap graphics.bitmap
+ui.gadgets ui.gadgets.packs ui.gadgets.borders ui.gadgets.grids
+ui.gadgets.grid-lines ui.gadgets.labels ui.gadgets.buttons
+ui.render ui opengl opengl.gl ;
+IN: ui.render.test
+
+SINGLETON: line-test
+
+M: line-test draw-interior
+ 2drop { 0 0 } { 0 10 } gl-line ;
+
+: <line-gadget> ( -- gadget )
+ <gadget>
+ line-test >>interior
+ { 1 10 } >>dim ;
+
+: message-window ( text -- )
+ <label> "Message" open-window ;
+
+SYMBOL: render-output
+
+: twiddle ( bytes -- bytes )
+ #! On Windows, white is { 253 253 253 } ?
+ [ 10 /i ] map ;
+
+: stride ( bitmap -- n ) width>> 3 * ;
+
+: bitmap= ( bitmap1 bitmap2 -- ? )
+ [
+ [ [ array>> ] [ stride 4 align ] bi group ] [ stride ] bi
+ '[ _ head twiddle ] map
+ ] bi@ = ;
+
+: check-rendering ( gadget -- )
+ screenshot
+ [ render-output set-global ]
+ [
+ "resource:extra/ui/render/test/reference.bmp" load-bitmap
+ bitmap= "is perfect" "needs work" ?
+ "Your UI rendering " prepend
+ message-window
+ ] bi ;
+
+TUPLE: take-screenshot { first-time? initial: t } ;
+
+M: take-screenshot draw-boundary
+ dup first-time?>> [
+ over check-rendering
+ f >>first-time?
+ ] when
+ 2drop ;
+
+: <ui-render-test> ( -- gadget )
+ <shelf>
+ take-screenshot new >>boundary
+ <gadget>
+ black <solid> >>interior
+ { 98 98 } >>dim
+ 1 <border> add-gadget
+ <gadget>
+ gray <solid> >>boundary
+ { 94 94 } >>dim
+ 3 <border>
+ red <solid> >>boundary
+ add-gadget
+ <line-gadget> <line-gadget> <line-gadget> 3array
+ <line-gadget> <line-gadget> <line-gadget> 3array
+ <line-gadget> <line-gadget> <line-gadget> 3array
+ 3array <grid>
+ { 5 5 } >>gap
+ blue <grid-lines> >>boundary
+ add-gadget
+ <gadget>
+ { 14 14 } >>dim
+ black <checkmark-paint> >>interior
+ black <solid> >>boundary
+ 4 <border>
+ add-gadget ;
+
+: ui-render-test ( -- )
+ <ui-render-test> "Test" open-window ;
+
+MAIN: ui-render-test
: git-pull-master ( -- )
image parent-directory
[
- { "git" "pull" "git://factorcode.org/git/factor.git" "master" }
+ { "git" "pull" "http://factorcode.org/git/factor.git" "master" }
run-command
]
with-directory ;
--- /dev/null
+Slava Pestov
--- /dev/null
+Slides from a talk at VPRI by Slava Pestov, October 2008
TUPLE: post < entity title comments ;
M: post feed-entry-title
- [ author>> ] [ title>> ] bi ": " swap 3append ;
+ [ author>> ] [ title>> ] bi ": " glue ;
M: post entity-url
id>> view-post-url ;
! See http://factorcode.org/license.txt for BSD license.
USING: kernel accessors http.server.dispatchers
http.server.static furnace.actions furnace.redirection urls
-validators locals io.files html.forms help.html ;
+validators locals io.files html.forms html.components help.html ;
IN: webapps.help
TUPLE: help-webapp < dispatcher ;
+M: result link-title title>> ;
+
+M: result link-href href>> ;
+
:: <search-action> ( help-dir -- action )
<page-action>
{ help-webapp "search" } >>template
{ "search" [ 1 v-min-length 50 v-max-length v-one-line ] }
} validate-params
- help-dir set-current-directory
-
- "search" value article-apropos "articles" set-value
- "search" value word-apropos "words" set-value
- "search" value vocab-apropos "vocabs" set-value
+ help-dir [
+ "search" value article-apropos "articles" set-value
+ "search" value word-apropos "words" set-value
+ "search" value vocab-apropos "vocabs" set-value
+ ] with-directory
{ help-webapp "search" } <chloe-content>
] >>submit ;
<t:form t:action="$help-webapp/search">
<t:field t:name="search" />
- <button>Search</button>
+ <button type="submit">Search</button>
</t:form>
<t:if t:value="articles">
! Copyright (C) 2008 Doug Coleman.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors furnace.actions http.server
-http.server.dispatchers html.forms io.servers.connection
+http.server.dispatchers html.forms io.sockets
namespaces prettyprint ;
IN: webapps.ip
</tr>
</table>
- <p> <button>Submit</button> </p>
+ <p> <button type="submit">Submit</button> </p>
</t:form>
</t:chloe>
</tr>
</table>
- <p> <button>Done</button> </p>
+ <p> <button type="submit">Done</button> </p>
</t:form>
<th class="field-label big-field-label">Capabilities:</th>
<td>
<t:each t:name="capabilities">
- <li><t:checkbox t:name="@value" t:label="@value" /><br/>
+ <t:checkbox t:name="@value" t:label="@value" /><br/>
</t:each>
</td>
</tr>
<t:form t:action="$wee-url">
<p>Shorten URL: <t:field t:name="url" t:size="40" /></p>
- <button>Shorten</button>
+ <button type="submit">Shorten</button>
</t:form>
</t:chloe>
! Copyright (C) 2007 Doug Coleman.
! Copyright (C) 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
-USING: math.ranges sequences random accessors combinators.lib
+USING: math.ranges sequences random accessors
kernel namespaces fry db.types db.tuples urls validators
html.components html.forms http http.server.dispatchers furnace
-furnace.actions furnace.boilerplate furnace.redirection ;
+furnace.actions furnace.boilerplate furnace.redirection
+furnace.utilities continuations ;
IN: webapps.wee-url
TUPLE: wee-url < dispatcher ;
</p>
<p>
- <button>Save</button>
+ <button type="submit">Save</button>
</p>
</t:form>
</tr>
</table>
- <button>View</button>
+ <button type="submit">View</button>
</t:form>
</t:chloe>
html.components html.forms
http.server
http.server.dispatchers
-furnace
furnace.actions
+furnace.utilities
furnace.redirection
furnace.auth
furnace.auth.login
[ list-revisions ] >>entries ;
: rollback-description ( description -- description' )
- [ "Rollback of '" swap "'" 3append ] [ "Rollback" ] if* ;
+ [ "Rollback of '" "'" surround ] [ "Rollback" ] if* ;
: <rollback-action> ( -- action )
<action>
USING: kernel sequences namespaces make math assocs words arrays
-tools.annotations vocabs sorting prettyprint io micros
-math.statistics accessors ;
+tools.annotations vocabs sorting prettyprint io system
+math.statistics accessors tools.time ;
IN: wordtimer
SYMBOL: *wordtimes*
*calling* get-global at ; inline
: timed-call ( quot word -- )
- [ calling ] [ >r micro-time r> register-time ] [ finished ] tri ; inline
+ [ calling ] [ >r benchmark r> register-time ] [ finished ] tri ; inline
: time-unless-recursing ( quot word -- )
dup called-recursively? not
: dummy-word ( -- ) ;
: time-dummy-word ( -- n )
- [ 100000 [ [ dummy-word ] micro-time , ] times ] { } make median ;
+ [ 100000 [ [ dummy-word ] benchmark , ] times ] { } make median ;
: subtract-overhead ( {oldtime,n} overhead -- {newtime,n} )
[ first2 ] dip
: wordtimer-call ( quot -- )
reset-word-timer
- [ call ] micro-time >r
+ benchmark >r
correct-for-timing-overhead
"total time:" write r> pprint nl
print-word-timings nl ;
over [ reset-vocab ] [ add-timers ] bi
reset-word-timer
"executing quotation..." print flush
- [ call ] micro-time >r
+ benchmark >r
"resetting annotations..." print flush
reset-vocab
correct-for-timing-overhead
+++ /dev/null
-! Copyright (C) 2008 Daniel Ehrenberg.
-! See http://factorcode.org/license.txt for BSD license.
-USING: lexer parser splitting kernel quotations namespaces make
-sequences assocs sequences.lib xml.generator xml.utilities
-xml.data ;
-IN: xml.syntax
-
-: parsed-name ( accum -- accum )
- scan ":" split1 [ f <name> ] [ <simple-name> ] if* parsed ;
-
-: run-combinator ( accum quot1 quot2 -- accum )
- >r [ ] like parsed r> [ parsed ] each ;
-
-: parse-tag-contents ( accum contained? -- accum )
- [ \ contained*, parsed ] [
- scan-word \ [ =
- [ POSTPONE: [ \ tag*, parsed ]
- [ "Expected [ missing" throw ] if
- ] if ;
-
-DEFER: >>
-
-: attributes-parsed ( accum quot -- accum )
- [ f parsed ] [
- >r \ >r parsed r> parsed
- [ H{ } make-assoc r> swap ] [ parsed ] each
- ] if-empty ;
-
-: <<
- parsed-name [
- \ >> parse-until >quotation
- attributes-parsed \ contained? get
- ] with-scope parse-tag-contents ; parsing
-
-: ==
- \ call parsed parsed-name \ set parsed ; parsing
-
-: //
- \ contained? on ; parsing
-
-: parse-special ( accum end-token word -- accum )
- >r parse-tokens " " join parsed r> parsed ;
-
-: <!-- "-->" \ comment, parse-special ; parsing
-
-: <! ">" \ directive, parse-special ; parsing
-
-: <? "?>" \ instruction, parse-special ; parsing
-
-: >xml-document ( seq -- xml )
- dup first prolog? [ unclip-slice ] [ standard-prolog ] if swap
- [ tag? ] split-around <xml> ;
-
-DEFER: XML>
-
-: <XML
- \ XML> [ >quotation ] parse-literal
- { } parsed \ make parsed \ >xml-document parsed ; parsing
(require 'font-lock)
(require 'comint)
+(require 'view)
+(require 'ring)
;;; Customization:
:type '(file :must-match t)
:group 'factor)
+(defcustom factor-use-doc-window t
+ "When on, use a separate window to display help information.
+Disable to see that information in the factor-listener comint
+window."
+ :type 'boolean
+ :group 'factor)
+
+(defcustom factor-listener-use-other-window t
+ "Use a window other than the current buffer's when switching to
+the factor-listener buffer."
+ :type 'boolean
+ :group 'factor)
+
+(defcustom factor-listener-window-allow-split t
+ "Allow window splitting when switching to the factor-listener
+buffer."
+ :type 'boolean
+ :group 'factor)
+
+(defcustom factor-help-always-ask t
+ "When enabled, always ask for confirmation in help prompts."
+ :type 'boolean
+ :group 'factor)
+
+(defcustom factor-help-use-minibuffer t
+ "When enabled, use the minibuffer for short help messages."
+ :type 'boolean
+ :group 'factor)
+
(defcustom factor-display-compilation-output t
"Display the REPL buffer before compiling files."
:type 'boolean
:type 'hook
:group 'factor)
+(defcustom factor-help-mode-hook nil
+ "Hook run by `factor-help-mode'."
+ :type 'hook
+ :group 'factor)
+
(defgroup factor-faces nil
"Faces used in Factor mode"
:group 'factor
:group 'faces)
-(defsubst factor--face (face) `((t ,(face-attr-construct face))))
-
-(defface factor-font-lock-parsing-word (factor--face font-lock-keyword-face)
+(defface factor-font-lock-parsing-word (face-default-spec font-lock-keyword-face)
"Face for parsing words."
:group 'factor-faces)
-(defface factor-font-lock-comment (factor--face font-lock-comment-face)
+(defface factor-font-lock-declaration (face-default-spec font-lock-keyword-face)
+ "Face for declaration words (inline, parsing ...)."
+ :group 'factor-faces)
+
+(defface factor-font-lock-comment (face-default-spec font-lock-comment-face)
"Face for comments."
:group 'factor-faces)
-(defface factor-font-lock-string (factor--face font-lock-string-face)
+(defface factor-font-lock-string (face-default-spec font-lock-string-face)
"Face for strings."
:group 'factor-faces)
-(defface factor-font-lock-stack-effect (factor--face font-lock-comment-face)
+(defface factor-font-lock-stack-effect (face-default-spec font-lock-comment-face)
"Face for stack effect specifications."
:group 'factor-faces)
-(defface factor-font-lock-word-definition (factor--face font-lock-function-name-face)
+(defface factor-font-lock-word-definition (face-default-spec font-lock-function-name-face)
"Face for word, generic or method being defined."
:group 'factor-faces)
-(defface factor-font-lock-symbol-definition (factor--face font-lock-variable-name-face)
+(defface factor-font-lock-symbol-definition (face-default-spec font-lock-variable-name-face)
"Face for name of symbol being defined."
:group 'factor-faces)
-(defface factor-font-lock-vocabulary-name (factor--face font-lock-constant-face)
+(defface factor-font-lock-vocabulary-name (face-default-spec font-lock-constant-face)
"Face for names of vocabularies in USE or USING."
:group 'factor-faces)
-(defface factor-font-lock-type-definition (factor--face font-lock-type-face)
+(defface factor-font-lock-type-definition (face-default-spec font-lock-type-face)
"Face for type (tuple) names."
:group 'factor-faces)
-(defface factor-font-lock-parsing-word (factor--face font-lock-keyword-face)
+(defface factor-font-lock-constructor (face-default-spec font-lock-type-face)
+ "Face for constructors (<foo>)."
+ :group 'factor-faces)
+
+(defface factor-font-lock-setter-word (face-default-spec font-lock-function-name-face)
+ "Face for setter words (>>foo)."
+ :group 'factor-faces)
+
+(defface factor-font-lock-parsing-word (face-default-spec font-lock-keyword-face)
"Face for parsing words."
:group 'factor-faces)
+(defface factor-font-lock-help-mode-headlines '((t (:bold t :weight bold)))
+ "Face for headlines in help buffers."
+ :group 'factor-faces)
+
+\f
+;;; Compatibility
+(when (not (fboundp 'ring-member))
+ (defun ring-member (ring item)
+ (catch 'found
+ (dotimes (ind (ring-length ring) nil)
+ (when (equal item (ring-ref ring ind))
+ (throw 'found ind))))))
+
\f
;;; Factor mode font lock:
"OCT:" "POSTPONE:" "PREDICATE:" "PRIMITIVE:" "PRIVATE>" "PROVIDE:"
"REQUIRE:" "REQUIRES:" "SINGLETON:" "SLOT:" "SYMBOL:" "SYMBOLS:"
"TUPLE:" "T{" "t\\??" "TYPEDEF:"
- "UNION:" "USE:" "USING:" "V{" "VAR:" "VARS:" "W{"))
+ "UNION:" "USE:" "USING:" "V{" "VARS:" "W{"))
(defconst factor--regex-parsing-words-ext
- (regexp-opt '("B" "call-next-method" "delimiter" "f" "flushable" "foldable"
- "initial:" "inline" "parsing" "read-only" "recursive")
+ (regexp-opt '("B" "call-next-method" "delimiter" "f" "initial:" "read-only")
'words))
+(defconst factor--declaration-words
+ '("flushable" "foldable" "inline" "parsing" "recursive"))
+
+(defconst factor--regex-declaration-words
+ (regexp-opt factor--declaration-words 'words))
+
(defsubst factor--regex-second-word (prefixes)
(format "^%s +\\([^ \r\n]+\\)" (regexp-opt prefixes t)))
+(defconst factor--regex-method-definition
+ "^M: +\\([^ ]+\\) +\\([^ ]+\\)")
+
(defconst factor--regex-word-definition
- (factor--regex-second-word '(":" "::" "M:" "GENERIC:")))
+ (factor--regex-second-word '(":" "::" "GENERIC:")))
(defconst factor--regex-type-definition
- (factor--regex-second-word '("TUPLE:")))
+ (factor--regex-second-word '("TUPLE:" "SINGLETON:")))
+
+(defconst factor--regex-parent-type "^TUPLE: +[^ ]+ +< +\\([^ ]+\\)")
+
+(defconst factor--regex-constructor "<[^ >]+>")
+
+(defconst factor--regex-setter "\\W>>[^ ]+\\b")
(defconst factor--regex-symbol-definition
- (factor--regex-second-word '("SYMBOL:")))
+ (factor--regex-second-word '("SYMBOL:" "VAR:")))
+
+(defconst factor--regex-stack-effect " ( .* )")
+
+(defconst factor--regex-using-lines "^USING: +\\(\\([^;]\\|[\n\r\f]\\)*\\);")
-(defconst factor--regex-using-line "^USING: +\\([^;]*\\);")
(defconst factor--regex-use-line "^USE: +\\(.*\\)$")
-(defconst factor-font-lock-keywords
- `(("#!.*$" . 'factor-font-lock-comment)
- ("!( .* )" . 'factor-font-lock-comment)
- ("^!.*$" . 'factor-font-lock-comment)
- (" !.*$" . 'factor-font-lock-comment)
- ("( .* )" . 'factor-font-lock-stack-effect)
- ("\"\\(\\\\\"\\|[^\"]\\)*\"" . 'factor-font-lock-string)
+(defconst factor--font-lock-keywords
+ `((,factor--regex-stack-effect . 'factor-font-lock-stack-effect)
("\\(P\\|SBUF\\)\"" 1 'factor-font-lock-parsing-word)
,@(mapcar #'(lambda (w) (cons (concat "\\(^\\| \\)\\(" w "\\)\\($\\| \\)")
'(2 'factor-font-lock-parsing-word)))
factor--parsing-words)
(,factor--regex-parsing-words-ext . 'factor-font-lock-parsing-word)
+ (,factor--regex-declaration-words 1 'factor-font-lock-declaration)
(,factor--regex-word-definition 2 'factor-font-lock-word-definition)
(,factor--regex-type-definition 2 'factor-font-lock-type-definition)
+ (,factor--regex-method-definition (1 'factor-font-lock-type-definition)
+ (2 'factor-font-lock-word-definition))
+ (,factor--regex-parent-type 1 'factor-font-lock-type-definition)
+ (,factor--regex-constructor . 'factor-font-lock-constructor)
+ (,factor--regex-setter . 'factor-font-lock-setter-word)
(,factor--regex-symbol-definition 2 'factor-font-lock-symbol-definition)
- (,factor--regex-using-line 1 'factor-font-lock-vocabulary-name)
(,factor--regex-use-line 1 'factor-font-lock-vocabulary-name))
"Font lock keywords definition for Factor mode.")
\f
;;; Factor mode syntax:
+(defconst factor--regex-definition-starters
+ (regexp-opt '("VARS" "TUPLE" "MACRO" "MACRO:" "M" ":" "")))
+
+(defconst factor--regex-definition-start
+ (format "^\\(%s:\\) " factor--regex-definition-starters))
+
+(defconst factor--regex-definition-end
+ (format "\\(;\\( +%s\\)*\\)" factor--regex-declaration-words))
+
+(defconst factor--font-lock-syntactic-keywords
+ `(("\\(#!\\)" (1 "<"))
+ (" \\(!\\)" (1 "<"))
+ ("^\\(!\\)" (1 "<"))
+ ("\\(!(\\) .* \\()\\)" (1 "<") (2 ">"))))
+
(defvar factor-mode-syntax-table nil
"Syntax table used while in Factor mode.")
;; Whitespace
(modify-syntax-entry ?\t " " factor-mode-syntax-table)
- (modify-syntax-entry ?\n ">" factor-mode-syntax-table)
(modify-syntax-entry ?\f " " factor-mode-syntax-table)
(modify-syntax-entry ?\r " " factor-mode-syntax-table)
(modify-syntax-entry ? " " factor-mode-syntax-table)
+ ;; (end of) Comments
+ (modify-syntax-entry ?\n ">" factor-mode-syntax-table)
+
+ ;; Parenthesis
(modify-syntax-entry ?\[ "(] " factor-mode-syntax-table)
(modify-syntax-entry ?\] ")[ " factor-mode-syntax-table)
(modify-syntax-entry ?{ "(} " factor-mode-syntax-table)
(modify-syntax-entry ?\( "()" factor-mode-syntax-table)
(modify-syntax-entry ?\) ")(" factor-mode-syntax-table)
- (modify-syntax-entry ?\" "\" " factor-mode-syntax-table)))
+
+ ;; Strings
+ (modify-syntax-entry ?\" "\"" factor-mode-syntax-table)
+ (modify-syntax-entry ?\\ "/" factor-mode-syntax-table)))
+
+\f
+;;; symbol-at-point
+
+(defun factor--beginning-of-symbol ()
+ "Move point to the beginning of the current symbol."
+ (while (eq (char-before) ?:) (backward-char))
+ (skip-syntax-backward "w_"))
+
+(defun factor--end-of-symbol ()
+ "Move point to the end of the current symbol."
+ (skip-syntax-forward "w_")
+ (while (looking-at ":") (forward-char)))
+
+(put 'factor-symbol 'end-op 'factor--end-of-symbol)
+(put 'factor-symbol 'beginning-op 'factor--beginning-of-symbol)
+
+(defsubst factor--symbol-at-point ()
+ (let ((s (substring-no-properties (thing-at-point 'factor-symbol))))
+ (and (> (length s) 0) s)))
+
+\f
+;;; Factor mode indentation:
+
+(make-variable-buffer-local
+ (defvar factor-indent-width factor-default-indent-width
+ "Indentation width in factor buffers. A local variable."))
+
+(defun factor--guess-indent-width ()
+ "Chooses an indentation value from existing code."
+ (let ((word-cont "^ +[^ ]")
+ (iw))
+ (save-excursion
+ (beginning-of-buffer)
+ (while (not iw)
+ (if (not (re-search-forward factor--regex-definition-start nil t))
+ (setq iw factor-default-indent-width)
+ (forward-line)
+ (when (looking-at word-cont)
+ (setq iw (current-indentation))))))
+ iw))
+
+(defsubst factor--ppss-brackets-depth ()
+ (nth 0 (syntax-ppss)))
+
+(defsubst factor--ppss-brackets-start ()
+ (nth 1 (syntax-ppss)))
+
+(defun factor--ppss-brackets-end ()
+ (save-excursion
+ (goto-char (factor--ppss-brackets-start))
+ (condition-case nil
+ (progn (forward-sexp)
+ (1- (point)))
+ (error -1))))
+
+(defsubst factor--indentation-at (pos)
+ (save-excursion (goto-char pos) (current-indentation)))
+
+(defsubst factor--at-first-char-p ()
+ (= (- (point) (line-beginning-position)) (current-indentation)))
+
+(defconst factor--regex-single-liner
+ (format "^%s" (regexp-opt '("DEFER:" "GENERIC:" "IN:"
+ "PRIVATE>" "<PRIVATE"
+ "SINGLETON:" "SYMBOL:" "USE:" "VAR:"))))
+
+(defconst factor--regex-begin-of-def
+ (format "^USING: \\|\\(%s\\)\\|\\(%s .*\\)"
+ factor--regex-definition-start
+ factor--regex-single-liner))
+
+(defconst factor--regex-end-of-def-line
+ (format "^.*%s" factor--regex-definition-end))
+
+(defconst factor--regex-end-of-def
+ (format "\\(%s\\)\\|\\(%s .*\\)"
+ factor--regex-end-of-def-line
+ factor--regex-single-liner))
+
+(defsubst factor--at-begin-of-def ()
+ (looking-at factor--regex-begin-of-def))
+
+(defsubst factor--at-end-of-def ()
+ (looking-at factor--regex-end-of-def))
+
+(defsubst factor--looking-at-emptiness ()
+ (looking-at "^[ \t]*$"))
+
+(defun factor--at-setter-line ()
+ (save-excursion
+ (beginning-of-line)
+ (if (not (factor--looking-at-emptiness))
+ (re-search-forward factor--regex-setter (line-end-position) t)
+ (forward-line -1)
+ (or (factor--at-constructor-line)
+ (factor--at-setter-line)))))
+
+(defun factor--at-constructor-line ()
+ (save-excursion
+ (beginning-of-line)
+ (re-search-forward factor--regex-constructor (line-end-position) t)))
+
+(defsubst factor--increased-indentation (&optional i)
+ (+ (or i (current-indentation)) factor-indent-width))
+(defsubst factor--decreased-indentation (&optional i)
+ (- (or i (current-indentation)) factor-indent-width))
+
+(defun factor--indent-in-brackets ()
+ (save-excursion
+ (beginning-of-line)
+ (when (> (factor--ppss-brackets-depth) 0)
+ (let ((op (factor--ppss-brackets-start))
+ (cl (factor--ppss-brackets-end))
+ (ln (line-number-at-pos)))
+ (when (> ln (line-number-at-pos op))
+ (if (and (> cl 0) (= ln (line-number-at-pos cl)))
+ (factor--indentation-at op)
+ (factor--increased-indentation (factor--indentation-at op))))))))
+
+(defun factor--indent-definition ()
+ (save-excursion
+ (beginning-of-line)
+ (when (factor--at-begin-of-def) 0)))
+
+(defun factor--indent-setter-line ()
+ (when (factor--at-setter-line)
+ (save-excursion
+ (let ((indent (and (factor--at-constructor-line) (current-indentation))))
+ (while (not (or indent
+ (bobp)
+ (factor--at-begin-of-def)
+ (factor--at-end-of-def)))
+ (if (factor--at-constructor-line)
+ (setq indent (factor--increased-indentation))
+ (forward-line -1)))
+ indent))))
+
+(defun factor--indent-continuation ()
+ (save-excursion
+ (forward-line -1)
+ (while (and (not (bobp)) (factor--looking-at-emptiness))
+ (forward-line -1))
+ (if (or (factor--at-end-of-def) (factor--at-setter-line))
+ (factor--decreased-indentation)
+ (if (and (factor--at-begin-of-def)
+ (not (looking-at factor--regex-using-lines)))
+ (factor--increased-indentation)
+ (current-indentation)))))
+
+(defun factor--calculate-indentation ()
+ "Calculate Factor indentation for line at point."
+ (or (and (bobp) 0)
+ (factor--indent-definition)
+ (factor--indent-in-brackets)
+ (factor--indent-setter-line)
+ (factor--indent-continuation)
+ 0))
+
+(defun factor--indent-line ()
+ "Indent current line as Factor code"
+ (let ((target (factor--calculate-indentation))
+ (pos (- (point-max) (point))))
+ (if (= target (current-indentation))
+ (if (< (current-column) (current-indentation))
+ (back-to-indentation))
+ (beginning-of-line)
+ (delete-horizontal-space)
+ (indent-to target)
+ (if (> (- (point-max) pos) (point))
+ (goto-char (- (point-max) pos))))))
+
+\f
+;; Factor mode:
+(defvar factor-mode-map (make-sparse-keymap)
+ "Key map used by Factor mode.")
+
+(defsubst factor--beginning-of-defun (&optional times)
+ (re-search-backward factor--regex-begin-of-def nil t times))
+
+(defsubst factor--end-of-defun ()
+ (re-search-forward factor--regex-end-of-def nil t))
+
+;;;###autoload
+(defun factor-mode ()
+ "A mode for editing programs written in the Factor programming language.
+\\{factor-mode-map}"
+ (interactive)
+ (kill-all-local-variables)
+ (use-local-map factor-mode-map)
+ (setq major-mode 'factor-mode)
+ (setq mode-name "Factor")
+ ;; Font locking
+ (set (make-local-variable 'comment-start) "! ")
+ (set (make-local-variable 'parse-sexp-lookup-properties) t)
+ (set (make-local-variable 'font-lock-comment-face) 'factor-font-lock-comment)
+ (set (make-local-variable 'font-lock-string-face) 'factor-font-lock-string)
+ (set (make-local-variable 'font-lock-defaults)
+ `(factor--font-lock-keywords
+ nil nil nil nil
+ (font-lock-syntactic-keywords . ,factor--font-lock-syntactic-keywords)))
+
+ (set-syntax-table factor-mode-syntax-table)
+ ;; Defun navigation
+ (set (make-local-variable 'beginning-of-defun-function) 'factor--beginning-of-defun)
+ (set (make-local-variable 'end-of-defun-function) 'factor--end-of-defun)
+ (set (make-local-variable 'open-paren-in-column-0-is-defun-start) nil)
+ ;; Indentation
+ (set (make-local-variable 'indent-line-function) 'factor--indent-line)
+ (setq factor-indent-width (factor--guess-indent-width))
+ (setq indent-tabs-mode nil)
+ ;; ElDoc
+ (set (make-local-variable 'eldoc-documentation-function) 'factor--eldoc)
+
+ (run-hooks 'factor-mode-hook))
+
+(add-to-list 'auto-mode-alist '("\\.factor\\'" . factor-mode))
\f
-;;; Factor mode commands:
+;;; Factor listener mode:
+
+;;;###autoload
+(define-derived-mode factor-listener-mode comint-mode "Factor Listener"
+ "Major mode for interacting with an inferior Factor listener process.
+\\{factor-listener-mode-map}"
+ (set (make-local-variable 'comint-prompt-regexp) "^( [^)]+ ) "))
+
+(defvar factor--listener-buffer nil
+ "The buffer in which the Factor listener is running.")
+
+(defun factor--listener-start-process ()
+ "Start an inferior Factor listener process, using
+`factor-binary' and `factor-image'."
+ (setq factor--listener-buffer
+ (apply 'make-comint "factor" (expand-file-name factor-binary) nil
+ `("-run=listener" ,(format "-i=%s" (expand-file-name factor-image)))))
+ (with-current-buffer factor--listener-buffer
+ (factor-listener-mode)))
+
+(defun factor--listener-process (&optional start)
+ (or (and (buffer-live-p factor--listener-buffer)
+ (get-buffer-process factor--listener-buffer))
+ (if (not start)
+ (error "No running factor listener. Try M-x run-factor.")
+ (factor--listener-start-process)
+ (factor--listener-process t))))
+
+;;;###autoload
+(defalias 'switch-to-factor 'run-factor)
+;;;###autoload
+(defun run-factor (&optional arg)
+ "Show the factor-listener buffer, starting the process if needed."
+ (interactive)
+ (let ((buf (process-buffer (factor--listener-process t)))
+ (pop-up-windows factor-listener-window-allow-split))
+ (if factor-listener-use-other-window
+ (pop-to-buffer buf)
+ (switch-to-buffer buf))))
(defun factor-telnet-to-port (port)
(interactive "nPort: ")
(interactive)
(factor-telnet-to-port 9010))
+\f
+;;; Factor listener interaction:
+
+(defun factor--listener-send-cmd (cmd)
+ (let ((proc (factor--listener-process)))
+ (when proc
+ (let* ((out (get-buffer-create "*factor messages*"))
+ (beg (with-current-buffer out (goto-char (point-max)))))
+ (comint-redirect-send-command-to-process cmd out proc nil t)
+ (with-current-buffer factor--listener-buffer
+ (while (not comint-redirect-completed) (sleep-for 0 1)))
+ (with-current-buffer out
+ (split-string (buffer-substring-no-properties beg (point-max))
+ "[\"\f\n\r\v]+" t))))))
+
+;;;;; Current vocabulary:
+(make-variable-buffer-local
+ (defvar factor--current-vocab nil
+ "Current vocabulary."))
+
+(defconst factor--regexp-current-vocab "^IN: +\\([^ \r\n\f]+\\)")
+
+(defun factor--current-buffer-vocab ()
+ (save-excursion
+ (when (or (re-search-backward factor--regexp-current-vocab nil t)
+ (re-search-forward factor--regexp-current-vocab nil t))
+ (setq factor--current-vocab (match-string-no-properties 1)))))
+
+(defun factor--current-listener-vocab ()
+ (car (factor--listener-send-cmd "USING: parser ; in get .")))
+
+(defun factor--set-current-listener-vocab (&optional vocab)
+ (factor--listener-send-cmd
+ (format "IN: %s" (or vocab (factor--current-buffer-vocab))))
+ t)
+
+(defmacro factor--with-vocab (vocab &rest body)
+ (let ((current (make-symbol "current")))
+ `(let ((,current (factor--current-listener-vocab)))
+ (factor--set-current-listener-vocab ,vocab)
+ (prog1 (condition-case nil (progn . ,body) (error nil))
+ (factor--set-current-listener-vocab ,current)))))
+
+(put 'factor--with-vocab 'lisp-indent-function 1)
+
+;;;;; Synchronous interaction:
+
+(defsubst factor--listener-vocab-cmds (cmds &optional vocab)
+ (factor--with-vocab vocab
+ (mapcar #'factor--listener-send-cmd cmds)))
+
+(defsubst factor--listener-vocab-cmd (cmd &optional vocab)
+ (factor--with-vocab vocab
+ (factor--listener-send-cmd cmd)))
+
+\f
+;;;;; Buffer cycling and docs
+
+
+(defconst factor--cycle-endings
+ '(".factor" "-tests.factor" "-docs.factor"))
+
+(defconst factor--regex-cycle-endings
+ (format "\\(.*?\\)\\(%s\\)$"
+ (regexp-opt factor--cycle-endings)))
+
+(defconst factor--cycle-endings-ring
+ (let ((ring (make-ring (length factor--cycle-endings))))
+ (dolist (e factor--cycle-endings ring)
+ (ring-insert ring e))))
+
+(defun factor--cycle-next (file)
+ (let* ((match (string-match factor--regex-cycle-endings file))
+ (base (and match (match-string-no-properties 1 file)))
+ (ending (and match (match-string-no-properties 2 file)))
+ (idx (and ending (ring-member factor--cycle-endings-ring ending)))
+ (gfl (lambda (i) (concat base (ring-ref factor--cycle-endings-ring i)))))
+ (if (not idx) file
+ (let ((l (length factor--cycle-endings)) (i 1) next)
+ (while (and (not next) (< i l))
+ (when (file-exists-p (funcall gfl (+ idx i)))
+ (setq next (+ idx i)))
+ (setq i (1+ i)))
+ (funcall gfl (or next idx))))))
+
+(defun factor-visit-other-file (&optional file)
+ "Cycle between code, tests and docs factor files."
+ (interactive)
+ (find-file (factor--cycle-next (or file (buffer-file-name)))))
+
+\f
+;;;;; Interface: See
+
+(defconst factor--regex-error-marker "^Type :help for debugging")
+(defconst factor--regex-data-stack "^--- Data stack:")
+
+(defun factor--prune-ans-strings (ans)
+ (nreverse
+ (catch 'done
+ (let ((res))
+ (dolist (a ans res)
+ (cond ((string-match factor--regex-stack-effect a)
+ (throw 'done (cons a res)))
+ ((string-match factor--regex-data-stack a)
+ (throw 'done res))
+ ((string-match factor--regex-error-marker a)
+ (throw 'done nil))
+ (t (push a res))))))))
+
+(defun factor--see-ans-to-string (ans)
+ (let ((s (mapconcat #'identity (factor--prune-ans-strings ans) " "))
+ (font-lock-verbose nil))
+ (and (> (length s) 0)
+ (with-temp-buffer
+ (insert s)
+ (factor-mode)
+ (font-lock-fontify-buffer)
+ (buffer-string)))))
+
+(defun factor--see-current-word (&optional word)
+ (let ((word (or word (factor--symbol-at-point))))
+ (when word
+ (let ((answer (factor--listener-send-cmd (format "\\ %s see" word))))
+ (and answer (factor--see-ans-to-string answer))))))
+
+(defalias 'factor--eldoc 'factor--see-current-word)
+
+(defun factor-see-current-word (&optional word)
+ "Echo in the minibuffer information about word at point."
+ (interactive)
+ (let* ((proc (factor--listener-process))
+ (word (or word (factor--symbol-at-point)))
+ (msg (factor--see-current-word word)))
+ (if msg (message "%s" msg)
+ (if word (message "No help found for '%s'" word)
+ (message "No word at point")))))
+
+;;; to fix:
(defun factor-run-file ()
(interactive)
(when (and (buffer-modified-p)
- (y-or-n-p (format "Save file %s? " (buffer-file-name))))
- (save-buffer))
+ (y-or-n-p (format "Save file %s? " (buffer-file-name))))
+ (save-buffer))
(when factor-display-compilation-output
- (factor-display-output-buffer))
+ (factor-display-output-buffer))
(comint-send-string "*factor*" (format "\"%s\"" (buffer-file-name)))
(comint-send-string "*factor*" " run-file\n"))
(defun factor-display-output-buffer ()
(with-current-buffer "*factor*"
- (goto-char (point-max))
- (unless (get-buffer-window (current-buffer) t)
- (display-buffer (current-buffer) t))))
+ (goto-char (point-max))
+ (unless (get-buffer-window (current-buffer) t)
+ (display-buffer (current-buffer) t))))
(defun factor-send-string (str)
(let ((n (length (split-string str "\n"))))
(factor-send-region (search-backward ":")
(search-forward ";")))
-(defun factor-see ()
- (interactive)
- (comint-send-string "*factor*" "\\ ")
- (comint-send-string "*factor*" (thing-at-point 'sexp))
- (comint-send-string "*factor*" " see\n"))
-
-(defun factor-help ()
- (interactive)
- (comint-send-string "*factor*" "\\ ")
- (comint-send-string "*factor*" (thing-at-point 'sexp))
- (comint-send-string "*factor*" " help\n"))
-
(defun factor-edit ()
(interactive)
(comint-send-string "*factor*" "\\ ")
(beginning-of-line)
(insert "! "))
-(defvar factor-mode-map (make-sparse-keymap)
- "Key map used by Factor mode.")
-
-(define-key factor-mode-map "\C-c\C-f" 'factor-run-file)
-(define-key factor-mode-map "\C-c\C-r" 'factor-send-region)
-(define-key factor-mode-map "\C-c\C-d" 'factor-send-definition)
-(define-key factor-mode-map "\C-c\C-s" 'factor-see)
-(define-key factor-mode-map "\C-ce" 'factor-edit)
-(define-key factor-mode-map "\C-c\C-h" 'factor-help)
-(define-key factor-mode-map "\C-cc" 'comment-region)
-(define-key factor-mode-map [return] 'newline-and-indent)
-(define-key factor-mode-map [tab] 'indent-for-tab-command)
-
-\f
-;;; Factor mode indentation:
-
-(defvar factor-indent-width factor-default-indent-width
- "Indentation width in factor buffers. A local variable.")
-
-(make-variable-buffer-local 'factor-indent-width)
-
-(defconst factor--regexp-word-start
- (let ((sws '("" ":" "TUPLE" "MACRO" "MACRO:" "M")))
- (format "^\\(%s\\): " (mapconcat 'identity sws "\\|"))))
-
-(defun factor--guess-indent-width ()
- "Chooses an indentation value from existing code."
- (let ((word-cont "^ +[^ ]")
- (iw))
- (save-excursion
- (beginning-of-buffer)
- (while (not iw)
- (if (not (re-search-forward factor--regexp-word-start nil t))
- (setq iw factor-default-indent-width)
- (forward-line)
- (when (looking-at word-cont)
- (setq iw (current-indentation))))))
- iw))
-
-(defun factor--brackets-depth ()
- "Returns number of brackets, not closed on previous lines."
- (syntax-ppss-depth
- (save-excursion
- (syntax-ppss (line-beginning-position)))))
-
-(defun factor--calculate-indentation ()
- "Calculate Factor indentation for line at point."
- (let ((not-indented t)
- (cur-indent 0))
- (save-excursion
- (beginning-of-line)
- (if (bobp)
- (setq cur-indent 0)
- (save-excursion
- (while not-indented
- ;; Check that we are inside open brackets
- (save-excursion
- (let ((cur-depth (factor--brackets-depth)))
- (forward-line -1)
- (setq cur-indent (+ (current-indentation)
- (* factor-indent-width
- (- cur-depth (factor--brackets-depth)))))
- (setq not-indented nil)))
- (forward-line -1)
- ;; Check that we are after the end of previous word
- (if (looking-at ".*;[ \t]*$")
- (progn
- (setq cur-indent (- (current-indentation) factor-indent-width))
- (setq not-indented nil))
- ;; Check that we are after the start of word
- (if (looking-at factor--regexp-word-start)
- (progn
- (message "inword")
- (setq cur-indent (+ (current-indentation) factor-indent-width))
- (setq not-indented nil))
- (if (bobp)
- (setq not-indented nil))))))))
- cur-indent))
-
-(defun factor-indent-line ()
- "Indent current line as Factor code"
- (let ((target (factor--calculate-indentation))
- (pos (- (point-max) (point))))
- (if (= target (current-indentation))
- (if (< (current-column) (current-indentation))
- (back-to-indentation))
- (beginning-of-line)
- (delete-horizontal-space)
- (indent-to target)
- (if (> (- (point-max) pos) (point))
- (goto-char (- (point-max) pos))))))
-
\f
-;; Factor mode:
-
-;;;###autoload
-(defun factor-mode ()
- "A mode for editing programs written in the Factor programming language.
-\\{factor-mode-map}"
+;;;; Factor help mode:
+
+(defvar factor-help-mode-map (make-sparse-keymap)
+ "Keymap for Factor help mode.")
+
+(defconst factor--help-headlines
+ (regexp-opt '("Definition"
+ "Examples"
+ "Generic word contract"
+ "Inputs and outputs"
+ "Parent topics:"
+ "See also"
+ "Syntax"
+ "Vocabulary"
+ "Warning"
+ "Word description")
+ t))
+
+(defconst factor--help-headlines-regexp (format "^%s" factor--help-headlines))
+
+(defconst factor--help-font-lock-keywords
+ `((,factor--help-headlines-regexp . 'factor-font-lock-help-mode-headlines)
+ ,@factor--font-lock-keywords))
+
+(defun factor-help-mode ()
+ "Major mode for displaying Factor help messages.
+\\{factor-help-mode-map}"
(interactive)
(kill-all-local-variables)
- (use-local-map factor-mode-map)
- (setq major-mode 'factor-mode)
- (setq mode-name "Factor")
- (set (make-local-variable 'indent-line-function) #'factor-indent-line)
- (set (make-local-variable 'comment-start) "! ")
+ (use-local-map factor-help-mode-map)
+ (setq mode-name "Factor Help")
+ (setq major-mode 'factor-help-mode)
(set (make-local-variable 'font-lock-defaults)
- '(factor-font-lock-keywords t nil nil nil))
- (set-syntax-table factor-mode-syntax-table)
- (set (make-local-variable 'indent-line-function) 'factor-indent-line)
- (setq factor-indent-width (factor--guess-indent-width))
- (setq indent-tabs-mode nil)
- (run-hooks 'factor-mode-hook))
+ '(factor--help-font-lock-keywords t nil nil nil))
+ (set (make-local-variable 'comint-redirect-subvert-readonly) t)
+ (set (make-local-variable 'comint-redirect-echo-input) nil)
+ (set (make-local-variable 'view-no-disable-on-exit) t)
+ (view-mode)
+ (setq view-exit-action
+ (lambda (buffer)
+ ;; Use `with-current-buffer' to make sure that `bury-buffer'
+ ;; also removes BUFFER from the selected window.
+ (with-current-buffer buffer
+ (bury-buffer))))
+ (run-mode-hooks 'factor-help-mode-hook))
+
+(defun factor--listener-help-buffer ()
+ (with-current-buffer (get-buffer-create "*factor-help*")
+ (let ((inhibit-read-only t)) (erase-buffer))
+ (factor-help-mode)
+ (current-buffer)))
+
+(defvar factor--help-history nil)
+
+(defun factor--listener-show-help (&optional see)
+ (let* ((proc (factor--listener-process))
+ (def (factor--symbol-at-point))
+ (prompt (format "See%s help on%s: " (if see " short" "")
+ (if def (format " (%s)" def) "")))
+ (ask (or (not (eq major-mode 'factor-mode))
+ (not def)
+ factor-help-always-ask))
+ (cmd (format "\\ %s %s"
+ (if ask (read-string prompt nil 'factor--help-history def) def)
+ (if see "see" "help")))
+ (hb (factor--listener-help-buffer)))
+ (comint-redirect-send-command-to-process cmd hb proc nil)
+ (pop-to-buffer hb)
+ (beginning-of-buffer hb)))
+
+;;;; Interface: see/help commands
+
+(defun factor-see (&optional arg)
+ "See a help summary of symbol at point.
+By default, the information is shown in the minibuffer. When
+called with a prefix argument, the information is displayed in a
+separate help buffer."
+ (interactive "P")
+ (if (if factor-help-use-minibuffer (not arg) arg)
+ (factor-see-current-word)
+ (factor--listener-show-help t)))
-(add-to-list 'auto-mode-alist '("\\.factor\\'" . factor-mode))
+(defun factor-help ()
+ "Show extended help about the symbol at point, using a help
+buffer."
+ (interactive)
+ (factor--listener-show-help))
\f
-;;; Factor listener mode
-
-(define-derived-mode factor-listener-mode comint-mode "Factor Listener")
-
-(define-key factor-listener-mode-map [f8] 'factor-refresh-all)
-
-(defun run-factor ()
- (interactive)
- (switch-to-buffer
- (make-comint-in-buffer "factor" nil (expand-file-name factor-binary) nil
- (concat "-i=" (expand-file-name factor-image))
- "-run=listener"))
- (factor-listener-mode))
(defun factor-refresh-all ()
+ "Reload source files and documentation for all loaded
+vocabularies which have been modified on disk."
(interactive)
(comint-send-string "*factor*" "refresh-all\n"))
\f
+;;; Key bindings:
+
+(defun factor--define-key (key cmd &optional both)
+ (let ((ms (list factor-mode-map)))
+ (when both (push factor-help-mode-map ms))
+ (dolist (m ms)
+ (define-key m (vector '(control ?c) key) cmd)
+ (define-key m (vector '(control ?c) `(control ,key)) cmd))))
+
+(defun factor--define-auto-indent-key (key)
+ (define-key factor-mode-map (vector key)
+ (lambda (n)
+ (interactive "p")
+ (self-insert-command n)
+ (indent-for-tab-command))))
+
+(factor--define-key ?f 'factor-run-file)
+(factor--define-key ?r 'factor-send-region)
+(factor--define-key ?d 'factor-send-definition)
+(factor--define-key ?s 'factor-see t)
+(factor--define-key ?e 'factor-edit)
+(factor--define-key ?z 'switch-to-factor t)
+(factor--define-key ?o 'factor-visit-other-file)
+(factor--define-key ?c 'comment-region)
+
+(factor--define-auto-indent-key ?\])
+(factor--define-auto-indent-key ?\})
+
+(define-key factor-mode-map "\C-ch" 'factor-help)
+(define-key factor-help-mode-map "\C-ch" 'factor-help)
+(define-key factor-mode-map "\C-m" 'newline-and-indent)
+
+(define-key factor-listener-mode-map [f8] 'factor-refresh-all)
+
+\f
(provide 'factor)
;;; factor.el ends here
--- /dev/null
+FUEL, Factor's Ultimate Emacs Library
+-------------------------------------
+
+FUEL provides a complete environment for your Factor coding pleasure
+inside Emacs, including source code edition and interaction with a
+Factor listener instance running within Emacs.
+
+FUEL was started by Jose A Ortega as an extension to Ed Cavazos'
+original factor.el code.
+
+Installation
+------------
+
+FUEL comes bundled with Factor's distribution. The folder misc/fuel
+contains Elisp code, and there's a fuel vocabulary in extras/fuel.
+
+To install FUEL, either add this line to your Emacs initialisation:
+
+ (load-file "<path/to/factor/installation>/misc/fuel/fu.el")
+
+or
+
+ (add-to-list load-path "<path/to/factor/installation>/fuel")
+ (require 'fuel)
+
+If all you want is a major mode for editing Factor code with pretty
+font colors and indentation, without running the factor listener
+inside Emacs, you can use instead:
+
+ (add-to-list load-path "<path/to/factor/installation>/fuel")
+ (setq factor-mode-use-fuel nil)
+ (require 'factor-mode)
+
+Basic usage
+-----------
+
+If you're using the default factor binary and images locations inside
+the Factor's source tree, that should be enough to start using FUEL.
+Editing any file with the extension .factor will put you in
+factor-mode; try C-hm for a summary of available commands.
+
+To start the listener, try M-x run-factor.
+
+Many aspects of the environment can be customized:
+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)).
+
+* In factor files:
+
+ - C-cz : switch to listener
+ - C-co : cycle between code, tests and docs factor files
+
+ - M-. : edit word at point in Emacs (also in listener)
+
+ - C-cr, C-cC-er : eval region
+ - C-M-r, C-cC-ee : eval region, extending it to definition boundaries
+ - C-M-x, C-cC-ex : eval definition around point
+ - C-ck, C-cC-ek : compile file
+
+ - C-cC-da : toggle autodoc mode
+ - C-cC-dd : help for word at point
+ - C-cC-ds : short help word at point
+
+* In the debugger (it pops up upon eval/compilation errors):
+
+ - g : go to error
+ - <digit> : invoke nth restart
+ - q : bury buffer
+
+
--- /dev/null
+;;; factor-mode.el -- mode for editing Factor source
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages, fuel, factor
+;; Start date: Tue Dec 02, 2008 21:32
+
+;;; Comentary:
+
+;; Definition of factor-mode, a major Emacs for editing Factor source
+;; code.
+
+;;; Code:
+
+(require 'fuel-base)
+(require 'fuel-syntax)
+(require 'fuel-font-lock)
+
+(require 'ring)
+
+\f
+;;; Customization:
+
+(defgroup factor-mode nil
+ "Major mode for Factor source code"
+ :group 'fuel)
+
+(defcustom factor-mode-use-fuel t
+ "Whether to use the full FUEL facilities in factor mode.
+
+Set this variable to nil if you just want to use Emacs as the
+external editor of your Factor environment, e.g., by putting
+these lines in your .emacs:
+
+ (add-to-list 'load-path \"/path/to/factor/misc/fuel\")
+ (setq factor-mode-use-fuel nil)
+ (require 'factor-mode)
+"
+ :type 'boolean
+ :group 'factor-mode)
+
+(defcustom factor-mode-default-indent-width 4
+ "Default indentation width for factor-mode.
+
+This value will be used for the local variable
+`factor-mode-indent-width' in new factor buffers. For existing
+code, we first check if `factor-mode-indent-width' is set
+explicitly in a local variable section or line (e.g.
+'! -*- factor-mode-indent-witdth: 2 -*-'). If that's not the case,
+`factor-mode' tries to infer its correct value from the existing
+code in the buffer."
+ :type 'integer
+ :group 'fuel)
+
+(defcustom factor-mode-hook nil
+ "Hook run when entering Factor mode."
+ :type 'hook
+ :group 'factor-mode)
+
+\f
+;;; Faces:
+
+(fuel-font-lock--define-faces
+ factor-font-lock font-lock factor-mode
+ ((comment comment "comments")
+ (constructor type "constructors (<foo>)")
+ (declaration keyword "declaration words")
+ (parsing-word keyword "parsing words")
+ (setter-word function-name "setter words (>>foo)")
+ (stack-effect comment "stack effect specifications")
+ (string string "strings")
+ (symbol variable-name "name of symbol being defined")
+ (type-name type "type names")
+ (vocabulary-name constant "vocabulary names")
+ (word function-name "word, generic or method being defined")))
+
+\f
+;;; Syntax table:
+
+(defun factor-mode--syntax-setup ()
+ (set-syntax-table fuel-syntax--syntax-table)
+ (set (make-local-variable 'beginning-of-defun-function)
+ 'fuel-syntax--beginning-of-defun)
+ (set (make-local-variable 'end-of-defun-function) 'fuel-syntax--end-of-defun)
+ (set (make-local-variable 'open-paren-in-column-0-is-defun-start) nil)
+ (fuel-syntax--enable-usings))
+
+\f
+;;; Indentation:
+
+(make-variable-buffer-local
+ (defvar factor-mode-indent-width factor-mode-default-indent-width
+ "Indentation width in factor buffers. A local variable."))
+
+(defun factor-mode--guess-indent-width ()
+ "Chooses an indentation value from existing code."
+ (let ((word-cont "^ +[^ ]")
+ (iw))
+ (save-excursion
+ (beginning-of-buffer)
+ (while (not iw)
+ (if (not (re-search-forward fuel-syntax--definition-start-regex nil t))
+ (setq iw factor-mode-default-indent-width)
+ (forward-line)
+ (when (looking-at word-cont)
+ (setq iw (current-indentation))))))
+ iw))
+
+(defun factor-mode--indent-in-brackets ()
+ (save-excursion
+ (beginning-of-line)
+ (when (> (fuel-syntax--brackets-depth) 0)
+ (let ((op (fuel-syntax--brackets-start))
+ (cl (fuel-syntax--brackets-end))
+ (ln (line-number-at-pos)))
+ (when (> ln (line-number-at-pos op))
+ (if (and (> cl 0) (= ln (line-number-at-pos cl)))
+ (fuel-syntax--indentation-at op)
+ (fuel-syntax--increased-indentation (fuel-syntax--indentation-at op))))))))
+
+(defun factor-mode--indent-definition ()
+ (save-excursion
+ (beginning-of-line)
+ (when (fuel-syntax--at-begin-of-def) 0)))
+
+(defun factor-mode--indent-setter-line ()
+ (when (fuel-syntax--at-setter-line)
+ (save-excursion
+ (let ((indent (and (fuel-syntax--at-constructor-line) (current-indentation))))
+ (while (not (or indent
+ (bobp)
+ (fuel-syntax--at-begin-of-def)
+ (fuel-syntax--at-end-of-def)))
+ (if (fuel-syntax--at-constructor-line)
+ (setq indent (fuel-syntax--increased-indentation))
+ (forward-line -1)))
+ indent))))
+
+(defun factor-mode--indent-continuation ()
+ (save-excursion
+ (forward-line -1)
+ (while (and (not (bobp))
+ (fuel-syntax--looking-at-emptiness))
+ (forward-line -1))
+ (cond ((or (fuel-syntax--at-end-of-def)
+ (fuel-syntax--at-setter-line))
+ (fuel-syntax--decreased-indentation))
+ ((and (fuel-syntax--at-begin-of-def)
+ (not (fuel-syntax--at-using)))
+ (fuel-syntax--increased-indentation))
+ (t (current-indentation)))))
+
+(defun factor-mode--calculate-indentation ()
+ "Calculate Factor indentation for line at point."
+ (or (and (bobp) 0)
+ (factor-mode--indent-definition)
+ (factor-mode--indent-in-brackets)
+ (factor-mode--indent-setter-line)
+ (factor-mode--indent-continuation)
+ 0))
+
+(defun factor-mode--indent-line ()
+ "Indent current line as Factor code"
+ (let ((target (factor-mode--calculate-indentation))
+ (pos (- (point-max) (point))))
+ (if (= target (current-indentation))
+ (if (< (current-column) (current-indentation))
+ (back-to-indentation))
+ (beginning-of-line)
+ (delete-horizontal-space)
+ (indent-to target)
+ (if (> (- (point-max) pos) (point))
+ (goto-char (- (point-max) pos))))))
+
+(defun factor-mode--indentation-setup ()
+ (set (make-local-variable 'indent-line-function) 'factor-mode--indent-line)
+ (setq factor-indent-width (factor-mode--guess-indent-width))
+ (setq indent-tabs-mode nil))
+
+\f
+;;; Buffer cycling:
+
+(defconst factor-mode--cycle-endings
+ '(".factor" "-tests.factor" "-docs.factor"))
+
+(defconst factor-mode--regex-cycle-endings
+ (format "\\(.*?\\)\\(%s\\)$"
+ (regexp-opt factor-mode--cycle-endings)))
+
+(defconst factor-mode--cycle-endings-ring
+ (let ((ring (make-ring (length factor-mode--cycle-endings))))
+ (dolist (e factor-mode--cycle-endings ring)
+ (ring-insert ring e))))
+
+(defun factor-mode--cycle-next (file)
+ (let* ((match (string-match factor-mode--regex-cycle-endings file))
+ (base (and match (match-string-no-properties 1 file)))
+ (ending (and match (match-string-no-properties 2 file)))
+ (idx (and ending (ring-member factor-mode--cycle-endings-ring ending)))
+ (gfl (lambda (i) (concat base (ring-ref factor-mode--cycle-endings-ring i)))))
+ (if (not idx) file
+ (let ((l (length factor-mode--cycle-endings)) (i 1) next)
+ (while (and (not next) (< i l))
+ (when (file-exists-p (funcall gfl (+ idx i)))
+ (setq next (+ idx i)))
+ (setq i (1+ i)))
+ (funcall gfl (or next idx))))))
+
+(defun factor-mode-visit-other-file (&optional file)
+ "Cycle between code, tests and docs factor files."
+ (interactive)
+ (find-file (factor-mode--cycle-next (or file (buffer-file-name)))))
+
+\f
+;;; Keymap:
+
+(defun factor-mode-insert-and-indent (n)
+ (interactive "p")
+ (self-insert-command n)
+ (indent-for-tab-command))
+
+(defvar factor-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [?\]] 'factor-mode-insert-and-indent)
+ (define-key map [?}] 'factor-mode-insert-and-indent)
+ (define-key map "\C-m" 'newline-and-indent)
+ (define-key map "\C-co" 'factor-mode-visit-other-file)
+ (define-key map "\C-c\C-o" 'factor-mode-visit-other-file)
+ map))
+
+(defun factor-mode--keymap-setup ()
+ (use-local-map factor-mode-map))
+
+\f
+;;; Factor mode:
+
+;;;###autoload
+(defun factor-mode ()
+ "A mode for editing programs written in the Factor programming language.
+\\{factor-mode-map}"
+ (interactive)
+ (kill-all-local-variables)
+ (setq major-mode 'factor-mode)
+ (setq mode-name "Factor")
+ (fuel-font-lock--font-lock-setup)
+ (factor-mode--keymap-setup)
+ (factor-mode--indentation-setup)
+ (factor-mode--syntax-setup)
+ (when factor-mode-use-fuel (require 'fuel-mode) (fuel-mode))
+ (run-hooks 'factor-mode-hook))
+
+\f
+(provide 'factor-mode)
+;;; factor-mode.el ends here
--- /dev/null
+;;; fu.el --- Startup file for FUEL
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages
+
+;;; Code:
+
+(add-to-list 'load-path (file-name-directory load-file-name))
+
+(add-to-list 'auto-mode-alist '("\\.factor\\'" . factor-mode))
+(autoload 'factor-mode "factor-mode.el"
+ "Major mode for editing Factor source." t)
+
+(autoload 'run-factor "fuel-listener.el"
+ "Start a Factor listener, or switch to a running one." t)
+
+(autoload 'fuel-autodoc-mode "fuel-help.el"
+ "Minor mode showing in the minibuffer a synopsis of Factor word at point."
+ t)
+
+
+\f
+;;; fu.el ends here
--- /dev/null
+;;; fuel-base.el --- Basic FUEL support code
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages
+
+;;; Commentary:
+
+;; Basic definitions likely to be used by all FUEL modules.
+
+;;; Code:
+
+(defconst fuel-version "1.0")
+
+;;;###autoload
+(defsubst fuel-version ()
+ "Echoes FUEL's version."
+ (interactive)
+ (message "FUEL %s" fuel-version))
+
+\f
+;;; Customization:
+
+;;;###autoload
+(defgroup fuel nil
+ "Factor's Ultimate Emacs Library"
+ :group 'language)
+
+\f
+;;; Emacs compatibility:
+
+(eval-after-load "ring"
+ '(when (not (fboundp 'ring-member))
+ (defun ring-member (ring item)
+ (catch 'found
+ (dotimes (ind (ring-length ring) nil)
+ (when (equal item (ring-ref ring ind))
+ (throw 'found ind)))))))
+
+\f
+;;; Utilities
+
+(defun fuel--shorten-str (str len)
+ (let ((sl (length str)))
+ (if (<= sl len) str
+ (let* ((sep " ... ")
+ (sepl (length sep))
+ (segl (/ (- len sepl) 2)))
+ (format "%s%s%s"
+ (substring str 0 segl)
+ sep
+ (substring str (- sl segl)))))))
+
+(defun fuel--shorten-region (begin end len)
+ (fuel--shorten-str (mapconcat 'identity
+ (split-string (buffer-substring begin end) nil t)
+ " ")
+ len))
+
+(provide 'fuel-base)
+;;; fuel-base.el ends here
--- /dev/null
+;;; fuel-debug.el -- debugging factor code
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages, fuel, factor
+;; Start date: Sun Dec 07, 2008 04:16
+
+;;; Comentary:
+
+;; A mode for displaying the results of run-file and evaluation, with
+;; support for restarts.
+
+;;; Code:
+
+(require 'fuel-base)
+(require 'fuel-eval)
+(require 'fuel-font-lock)
+
+\f
+;;; Customization:
+
+(defgroup fuel-debug nil
+ "Major mode for interaction with the Factor debugger"
+ :group 'fuel)
+
+(defcustom fuel-debug-mode-hook nil
+ "Hook run after `fuel-debug-mode' activates"
+ :group 'fuel-debug
+ :type 'hook)
+
+(defcustom fuel-debug-show-short-help t
+ "Whether to show short help on available keys in debugger"
+ :group 'fuel-debug
+ :type 'boolean)
+
+(fuel-font-lock--define-faces
+ fuel-debug-font-lock font-lock fuel-debug
+ ((error warning "highlighting errors")
+ (line variable-name "line numbers in errors/warnings")
+ (column variable-name "column numbers in errors/warnings")
+ (info comment "information headers")
+ (restart-number warning "restart numbers")
+ (restart-name function-name "restart names")))
+
+\f
+;;; Font lock and other pattern matching:
+
+(defconst fuel-debug--compiler-info-alist
+ '((":warnings" . ?w) (":errors" . ?e) (":linkage" . ?l)))
+
+(defconst fuel-debug--error-file-regex "^P\" \\([^\"]+\\)\"")
+(defconst fuel-debug--error-line-regex "\\([0-9]+\\):")
+(defconst fuel-debug--error-cont-regex "^ +\\(\\^\\)$")
+
+(defconst fuel-debug--error-regex
+ (format "%s\n%s"
+ fuel-debug--error-file-regex
+ fuel-debug--error-line-regex))
+
+(defconst fuel-debug--compiler-info-regex
+ (format "^\\(%s\\) "
+ (regexp-opt (mapcar 'car fuel-debug--compiler-info-alist))))
+
+(defconst fuel-debug--restart-regex "^:\\([0-9]+\\) \\(.+\\)")
+
+(defconst fuel-debug--font-lock-keywords
+ `((,fuel-debug--error-file-regex . 'fuel-debug-font-lock-error)
+ (,fuel-debug--error-line-regex 1 'fuel-debug-font-lock-line)
+ (,fuel-debug--error-cont-regex 1 'fuel-debug-font-lock-column)
+ (,fuel-debug--restart-regex (1 'fuel-debug-font-lock-restart-number)
+ (2 'fuel-debug-font-lock-restart-name))
+ (,fuel-debug--compiler-info-regex 1 'fuel-debug-font-lock-restart-number)
+ ("^\\(Restarts?\\|Loading\\) .+$" . 'fuel-debug-font-lock-info)
+ ("^Error: " . 'fuel-debug-font-lock-error)))
+
+(defun fuel-debug--font-lock-setup ()
+ (set (make-local-variable 'font-lock-defaults)
+ '(fuel-debug--font-lock-keywords t nil nil nil)))
+
+\f
+;;; Debug buffer:
+
+(defvar fuel-debug--buffer nil)
+
+(make-variable-buffer-local
+ (defvar fuel-debug--last-ret nil))
+
+(make-variable-buffer-local
+ (defvar fuel-debug--file nil))
+
+(defun fuel-debug--buffer ()
+ (or (and (buffer-live-p fuel-debug--buffer) fuel-debug--buffer)
+ (with-current-buffer
+ (setq fuel-debug--buffer (get-buffer-create "*fuel dbg*"))
+ (fuel-debug-mode)
+ (current-buffer))))
+
+(defun fuel-debug--display-retort (ret &optional success-msg no-pop file)
+ (let ((err (fuel-eval--retort-error ret))
+ (inhibit-read-only t))
+ (with-current-buffer (fuel-debug--buffer)
+ (erase-buffer)
+ (fuel-debug--display-output ret)
+ (delete-blank-lines)
+ (newline)
+ (when (and (not err) success-msg)
+ (message "%s" success-msg)
+ (insert "\n" success-msg "\n"))
+ (when err
+ (fuel-debug--display-restarts err)
+ (delete-blank-lines)
+ (newline)
+ (let ((hstr (fuel-debug--help-string err file)))
+ (if fuel-debug-show-short-help
+ (insert "-----------\n" hstr "\n")
+ (message "%s" hstr))))
+ (setq fuel-debug--last-ret ret)
+ (setq fuel-debug--file file)
+ (goto-char (point-max))
+ (when (and err (not no-pop)) (pop-to-buffer fuel-debug--buffer))
+ (not err))))
+
+(defun fuel-debug--display-output (ret)
+ (let* ((last (fuel-eval--retort-output fuel-debug--last-ret))
+ (current (fuel-eval--retort-output ret))
+ (llen (length last))
+ (clen (length current))
+ (trail (and last (substring-no-properties last (/ llen 2))))
+ (err (fuel-eval--retort-error ret))
+ (p (point)))
+ (save-excursion (insert current))
+ (when (and (> clen llen) (> llen 0) (search-forward trail nil t))
+ (delete-region p (point)))
+ (goto-char (point-max))
+ (when err
+ (insert (format "\nError: %S\n\n" (fuel-eval--error-name err))))))
+
+(defun fuel-debug--display-restarts (err)
+ (let* ((rs (fuel-eval--error-restarts err))
+ (rsn (length rs)))
+ (when rs
+ (insert "Restarts:\n\n")
+ (dotimes (n rsn)
+ (insert (format ":%s %s\n" (1+ n) (nth n rs))))
+ (newline))))
+
+(defun fuel-debug--help-string (err &optional file)
+ (format "Press %s%s%sq bury buffer"
+ (if (or file (fuel-eval--error-file err)) "g go to file, " "")
+ (let ((rsn (length (fuel-eval--error-restarts err))))
+ (cond ((zerop rsn) "")
+ ((= 1 rsn) "1 invoke restart, ")
+ (t (format "1-%s invoke restarts, " rsn))))
+ (let ((str ""))
+ (dolist (ci fuel-debug--compiler-info-alist str)
+ (save-excursion
+ (goto-char (point-min))
+ (when (search-forward (car ci) nil t)
+ (setq str (format "%c %s, %s" (cdr ci) (car ci) str))))))))
+
+(defun fuel-debug--buffer-file ()
+ (with-current-buffer (fuel-debug--buffer)
+ (or fuel-debug--file
+ (and fuel-debug--last-ret
+ (fuel-eval--error-file
+ (fuel-eval--retort-error fuel-debug--last-ret))))))
+
+(defsubst fuel-debug--buffer-error ()
+ (fuel-eval--retort-error fuel-debug--last-ret))
+
+(defsubst fuel-debug--buffer-restarts ()
+ (fuel-eval--error-restarts (fuel-debug--buffer-error)))
+
+\f
+;;; Buffer navigation:
+
+(defun fuel-debug-goto-error ()
+ (interactive)
+ (let* ((err (or (fuel-debug--buffer-error)
+ (error "No errors reported")))
+ (file (or (fuel-debug--buffer-file)
+ (error "No file associated with error")))
+ (l/c (fuel-eval--error-line/column err))
+ (line (or (car l/c) 1))
+ (col (or (cdr l/c) 0)))
+ (find-file-other-window file)
+ (goto-line line)
+ (forward-char col)))
+
+(defun fuel-debug--read-restart-no ()
+ (let ((rs (fuel-debug--buffer-restarts)))
+ (unless rs (error "No restarts available"))
+ (let* ((rsn (length rs))
+ (prompt (format "Restart number? (1-%s): " rsn))
+ (no 0))
+ (while (or (> (setq no (read-number prompt)) rsn)
+ (< no 1)))
+ no)))
+
+(defun fuel-debug-exec-restart (&optional n confirm)
+ (interactive (list (fuel-debug--read-restart-no)))
+ (let ((n (or n 1))
+ (rs (fuel-debug--buffer-restarts)))
+ (when (zerop (length rs))
+ (error "No restarts available"))
+ (when (or (< n 1) (> n (length rs)))
+ (error "Restart %s not available" n))
+ (when (or (not confirm)
+ (y-or-n-p (format "Invoke restart %s? " n)))
+ (message "Invoking restart %s" n)
+ (let* ((file (fuel-debug--buffer-file))
+ (buffer (if file (find-file-noselect file) (current-buffer))))
+ (with-current-buffer buffer
+ (fuel-debug--display-retort
+ (fuel-eval--eval-string/context (format ":%s" n))
+ (format "Restart %s (%s) successful" n (nth (1- n) rs))))))))
+
+(defun fuel-debug-show--compiler-info (info)
+ (save-excursion
+ (goto-char (point-min))
+ (unless (re-search-forward (format "^%s" info) nil t)
+ (error "%s information not available" info))
+ (message "Retrieving %s info ..." info)
+ (unless (fuel-debug--display-retort
+ (fuel-eval--eval-string info) "" (fuel-debug--buffer-file))
+ (error "Sorry, no %s info available" info))))
+
+\f
+;;; Fuel Debug mode:
+
+(defvar fuel-debug-mode-map
+ (let ((map (make-keymap)))
+ (suppress-keymap map)
+ (define-key map "g" 'fuel-debug-goto-error)
+ (define-key map "\C-c\C-c" 'fuel-debug-goto-error)
+ (define-key map "n" 'next-line)
+ (define-key map "p" 'previous-line)
+ (define-key map "q" 'bury-buffer)
+ (dotimes (n 9)
+ (define-key map (vector (+ ?1 n))
+ `(lambda () (interactive) (fuel-debug-exec-restart ,(1+ n) t))))
+ (dolist (ci fuel-debug--compiler-info-alist)
+ (define-key map (vector (cdr ci))
+ `(lambda () (interactive) (fuel-debug-show--compiler-info ,(car ci)))))
+ map))
+
+(defun fuel-debug-mode ()
+ "A major mode for displaying Factor's compilation results and
+invoking restarts as needed.
+\\{fuel-debug-mode-map}"
+ (interactive)
+ (kill-all-local-variables)
+ (setq major-mode 'factor-mode)
+ (setq mode-name "Fuel Debug")
+ (use-local-map fuel-debug-mode-map)
+ (fuel-debug--font-lock-setup)
+ (setq fuel-debug--file nil)
+ (setq fuel-debug--last-ret nil)
+ (toggle-read-only 1)
+ (run-hooks 'fuel-debug-mode-hook))
+
+\f
+(provide 'fuel-debug)
+;;; fuel-debug.el ends here
--- /dev/null
+;;; fuel-eval.el --- utilities for communication with fuel-listener
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages
+;; Start date: Tue Dec 02, 2008
+
+;;; Commentary:
+
+;; Protocols for handling communications via a comint buffer running a
+;; factor listener.
+
+;;; Code:
+
+(require 'fuel-base)
+(require 'fuel-syntax)
+
+\f
+;;; Syncronous string sending:
+
+(defvar fuel-eval-log-max-length 16000)
+
+(defvar fuel-eval--default-proc-function nil)
+(defsubst fuel-eval--default-proc ()
+ (and fuel-eval--default-proc-function
+ (funcall fuel-eval--default-proc-function)))
+
+(defvar fuel-eval--proc nil)
+(defvar fuel-eval--log t)
+
+(defun fuel-eval--send-string (str)
+ (let ((proc (or fuel-eval--proc (fuel-eval--default-proc))))
+ (when proc
+ (with-current-buffer (get-buffer-create "*factor messages*")
+ (goto-char (point-max))
+ (when (and (> fuel-eval-log-max-length 0)
+ (> (point) fuel-eval-log-max-length))
+ (erase-buffer))
+ (when fuel-eval--log (insert "\n>> " (fuel--shorten-str str 256)))
+ (newline)
+ (let ((beg (point)))
+ (comint-redirect-send-command-to-process str (current-buffer) proc nil t)
+ (with-current-buffer (process-buffer proc)
+ (while (not comint-redirect-completed) (sleep-for 0 1)))
+ (goto-char beg)
+ (current-buffer))))))
+
+\f
+;;; Evaluation protocol
+
+(defsubst fuel-eval--retort-make (err result &optional output)
+ (list err result output))
+
+(defsubst fuel-eval--retort-error (ret) (nth 0 ret))
+(defsubst fuel-eval--retort-result (ret) (nth 1 ret))
+(defsubst fuel-eval--retort-output (ret) (nth 2 ret))
+
+(defsubst fuel-eval--retort-p (ret) (listp ret))
+
+(defsubst fuel-eval--make-parse-error-retort (str)
+ (fuel-eval--retort-make 'parse-retort-error nil str))
+
+(defun fuel-eval--parse-retort (buffer)
+ (save-current-buffer
+ (set-buffer buffer)
+ (condition-case nil
+ (read (current-buffer))
+ (error (fuel-eval--make-parse-error-retort
+ (buffer-substring-no-properties (point) (point-max)))))))
+
+(defsubst fuel-eval--send/retort (str)
+ (fuel-eval--parse-retort (fuel-eval--send-string str)))
+
+(defsubst fuel-eval--eval-begin ()
+ (fuel-eval--send/retort "fuel-begin-eval"))
+
+(defsubst fuel-eval--eval-end ()
+ (fuel-eval--send/retort "fuel-begin-eval"))
+
+(defsubst fuel-eval--factor-array (strs)
+ (format "V{ %S }" (mapconcat 'identity strs " ")))
+
+(defsubst fuel-eval--eval-strings (strs &optional no-restart)
+ (let ((str (format "fuel-eval-%s %s fuel-eval"
+ (if no-restart "non-restartable" "restartable")
+ (fuel-eval--factor-array strs))))
+ (fuel-eval--send/retort str)))
+
+(defsubst fuel-eval--eval-string (str &optional no-restart)
+ (fuel-eval--eval-strings (list str) no-restart))
+
+(defun fuel-eval--eval-strings/context (strs &optional no-restart)
+ (let ((usings (fuel-syntax--usings-update)))
+ (fuel-eval--send/retort
+ (format "fuel-eval-%s %s %S %s fuel-eval-in-context"
+ (if no-restart "non-restartable" "restartable")
+ (fuel-eval--factor-array strs)
+ (or fuel-syntax--current-vocab "f")
+ (if usings (fuel-eval--factor-array usings) "f")))))
+
+(defsubst fuel-eval--eval-string/context (str &optional no-restart)
+ (fuel-eval--eval-strings/context (list str) no-restart))
+
+(defun fuel-eval--eval-region/context (begin end &optional no-restart)
+ (let ((lines (split-string (buffer-substring-no-properties begin end)
+ "[\f\n\r\v]+" t)))
+ (when (> (length lines) 0)
+ (fuel-eval--eval-strings/context lines no-restart))))
+
+\f
+;;; Error parsing
+
+(defsubst fuel-eval--error-name (err) (car err))
+
+(defsubst fuel-eval--error-restarts (err)
+ (cdr (assoc :restarts (fuel-eval--error-name-p err 'condition))))
+
+(defun fuel-eval--error-name-p (err name)
+ (unless (null err)
+ (or (and (eq (fuel-eval--error-name err) name) err)
+ (assoc name err))))
+
+(defsubst fuel-eval--error-file (err)
+ (nth 1 (fuel-eval--error-name-p err 'source-file-error)))
+
+(defsubst fuel-eval--error-lexer-p (err)
+ (or (fuel-eval--error-name-p err 'lexer-error)
+ (fuel-eval--error-name-p (fuel-eval--error-name-p err 'source-file-error)
+ 'lexer-error)))
+
+(defsubst fuel-eval--error-line/column (err)
+ (let ((err (fuel-eval--error-lexer-p err)))
+ (cons (nth 1 err) (nth 2 err))))
+
+(defsubst fuel-eval--error-line-text (err)
+ (nth 3 (fuel-eval--error-lexer-p err)))
+
+\f
+(provide 'fuel-eval)
+;;; fuel-eval.el ends here
--- /dev/null
+;;; fuel-font-lock.el -- font lock for factor code
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages, fuel, factor
+;; Start date: Wed Dec 03, 2008 21:40
+
+;;; Comentary:
+
+;; Font lock setup for highlighting Factor code.
+
+;;; Code:
+
+(require 'fuel-base)
+(require 'fuel-syntax)
+
+(require 'font-lock)
+
+\f
+;;; Faces:
+
+(defmacro fuel-font-lock--make-face (prefix def-prefix group face def doc)
+ (let ((face (intern (format "%s-%s" prefix face)))
+ (def (intern (format "%s-%s-face" def-prefix def))))
+ `(defface ,face (face-default-spec ,def)
+ ,(format "Face for %s." doc)
+ :group ',group
+ :group 'faces)))
+
+(defmacro fuel-font-lock--define-faces (prefix def-prefix group faces)
+ (let ((setup (make-symbol (format "%s--faces-setup" prefix))))
+ `(progn
+ (defmacro ,setup ()
+ (cons 'progn
+ (mapcar (lambda (f) (append '(fuel-font-lock--make-face
+ ,prefix ,def-prefix ,group) f))
+ ',faces)))
+ (,setup))))
+
+\f
+;;; Font lock:
+
+(defconst fuel-font-lock--parsing-lock-keywords
+ (cons '("\\(P\\|SBUF\\)\"" 1 'factor-font-lock-parsing-word)
+ (mapcar (lambda (w) `(,(format "\\(^\\| \\)\\(%s\\)\\($\\| \\)" w)
+ 2 'factor-font-lock-parsing-word))
+ fuel-syntax--parsing-words)))
+
+(defconst fuel-font-lock--font-lock-keywords
+ `(,@fuel-font-lock--parsing-lock-keywords
+ (,fuel-syntax--stack-effect-regex . 'factor-font-lock-stack-effect)
+ (,fuel-syntax--parsing-words-ext-regex . 'factor-font-lock-parsing-word)
+ (,fuel-syntax--declaration-words-regex 1 'factor-font-lock-declaration)
+ (,fuel-syntax--word-definition-regex 2 'factor-font-lock-word)
+ (,fuel-syntax--type-definition-regex 2 'factor-font-lock-type-name)
+ (,fuel-syntax--method-definition-regex (1 'factor-font-lock-type-name)
+ (2 'factor-font-lock-word))
+ (,fuel-syntax--parent-type-regex 1 'factor-font-lock-type)
+ (,fuel-syntax--constructor-regex . 'factor-font-lock-constructor)
+ (,fuel-syntax--setter-regex . 'factor-font-lock-setter-word)
+ (,fuel-syntax--symbol-definition-regex 2 'factor-font-lock-symbol)
+ (,fuel-syntax--use-line-regex 1 'factor-font-lock-vocabulary-name))
+ "Font lock keywords definition for Factor mode.")
+
+(defun fuel-font-lock--font-lock-setup (&optional keywords no-syntax)
+ (set (make-local-variable 'comment-start) "! ")
+ (set (make-local-variable 'parse-sexp-lookup-properties) t)
+ (set (make-local-variable 'font-lock-comment-face) 'factor-font-lock-comment)
+ (set (make-local-variable 'font-lock-string-face) 'factor-font-lock-string)
+ (set (make-local-variable 'font-lock-defaults)
+ `(,(or keywords 'fuel-font-lock--font-lock-keywords)
+ nil nil nil nil
+ ,@(if no-syntax nil
+ (list (cons 'font-lock-syntactic-keywords
+ fuel-syntax--syntactic-keywords))))))
+
+\f
+(provide 'fuel-font-lock)
+;;; fuel-font-lock.el ends here
--- /dev/null
+;;; fuel-help.el -- accessing Factor's help system
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages, fuel, factor
+;; Start date: Wed Dec 03, 2008 21:41
+
+;;; Comentary:
+
+;; Modes and functions interfacing Factor's 'see' and 'help'
+;; utilities, as well as an ElDoc-based autodoc mode.
+
+;;; Code:
+
+(require 'fuel-base)
+(require 'fuel-font-lock)
+(require 'fuel-eval)
+
+\f
+;;; Customization:
+
+(defgroup fuel-help nil
+ "Options controlling FUEL's help system"
+ :group 'fuel)
+
+(defcustom fuel-help-minibuffer-font-lock t
+ "Whether to use font lock for info messages in the minibuffer."
+ :group 'fuel-help
+ :type 'boolean)
+
+(defcustom fuel-help-always-ask t
+ "When enabled, always ask for confirmation in help prompts."
+ :type 'boolean
+ :group 'fuel-help)
+
+(defcustom fuel-help-use-minibuffer t
+ "When enabled, use the minibuffer for short help messages."
+ :type 'boolean
+ :group 'fuel-help)
+
+(defcustom fuel-help-mode-hook nil
+ "Hook run by `factor-help-mode'."
+ :type 'hook
+ :group 'fuel-help)
+
+(defface fuel-help-font-lock-headlines '((t (:bold t :weight bold)))
+ "Face for headlines in help buffers."
+ :group 'fuel-help
+ :group 'faces)
+
+\f
+;;; Autodoc mode:
+
+(defvar fuel-help--font-lock-buffer
+ (let ((buffer (get-buffer-create " *fuel help minibuffer messages*")))
+ (set-buffer buffer)
+ (fuel-font-lock--font-lock-setup)
+ buffer))
+
+(defun fuel-help--font-lock-str (str)
+ (set-buffer fuel-help--font-lock-buffer)
+ (erase-buffer)
+ (insert str)
+ (let ((font-lock-verbose nil)) (font-lock-fontify-buffer))
+ (buffer-string))
+
+(defun fuel-help--word-synopsis (&optional word)
+ (let ((word (or word (fuel-syntax-symbol-at-point)))
+ (fuel-eval--log t))
+ (when word
+ (let ((ret (fuel-eval--eval-string/context
+ (format "\\ %s synopsis fuel-eval-set-result" word)
+ t)))
+ (when (not (fuel-eval--retort-error ret))
+ (if fuel-help-minibuffer-font-lock
+ (fuel-help--font-lock-str (fuel-eval--retort-result ret))
+ (fuel-eval--retort-result ret)))))))
+
+(make-variable-buffer-local
+ (defvar fuel-autodoc-mode-string " A"
+ "Modeline indicator for fuel-autodoc-mode"))
+
+(define-minor-mode fuel-autodoc-mode
+ "Toggle Fuel's Autodoc mode.
+With no argument, this command toggles the mode.
+Non-null prefix argument turns on the mode.
+Null prefix argument turns off the mode.
+
+When Autodoc mode is enabled, a synopsis of the word at point is
+displayed in the minibuffer."
+ :init-value nil
+ :lighter fuel-autodoc-mode-string
+ :group 'fuel
+
+ (set (make-local-variable 'eldoc-documentation-function)
+ (when fuel-autodoc-mode 'fuel-help--word-synopsis))
+ (set (make-local-variable 'eldoc-minor-mode-string) nil)
+ (eldoc-mode fuel-autodoc-mode)
+ (message "Fuel Autodoc %s" (if fuel-autodoc-mode "enabled" "disabled")))
+
+\f
+;;;; Factor help mode:
+
+(defvar fuel-help-mode-map (make-sparse-keymap)
+ "Keymap for Factor help mode.")
+
+(define-key fuel-help-mode-map [(return)] 'fuel-help)
+
+(defconst fuel-help--headlines
+ (regexp-opt '("Class description"
+ "Definition"
+ "Examples"
+ "Generic word contract"
+ "Inputs and outputs"
+ "Methods"
+ "Notes"
+ "Parent topics:"
+ "See also"
+ "Syntax"
+ "Vocabulary"
+ "Warning"
+ "Word description")
+ t))
+
+(defconst fuel-help--headlines-regexp (format "^%s" fuel-help--headlines))
+
+(defconst fuel-help--font-lock-keywords
+ `(,@fuel-font-lock--font-lock-keywords
+ (,fuel-help--headlines-regexp . 'fuel-help-font-lock-headlines)))
+
+(defun fuel-help-mode ()
+ "Major mode for displaying Factor documentation.
+\\{fuel-help-mode-map}"
+ (interactive)
+ (kill-all-local-variables)
+ (use-local-map fuel-help-mode-map)
+ (setq mode-name "Factor Help")
+ (setq major-mode 'fuel-help-mode)
+
+ (fuel-font-lock--font-lock-setup fuel-help--font-lock-keywords t)
+
+ (set (make-local-variable 'view-no-disable-on-exit) t)
+ (view-mode)
+ (setq view-exit-action
+ (lambda (buffer)
+ ;; Use `with-current-buffer' to make sure that `bury-buffer'
+ ;; also removes BUFFER from the selected window.
+ (with-current-buffer buffer
+ (bury-buffer))))
+
+ (setq fuel-autodoc-mode-string "")
+ (fuel-autodoc-mode)
+ (run-mode-hooks 'fuel-help-mode-hook))
+
+(defun fuel-help--help-buffer ()
+ (with-current-buffer (get-buffer-create "*fuel-help*")
+ (fuel-help-mode)
+ (current-buffer)))
+
+(defvar fuel-help--history nil)
+
+(defun fuel-help--show-help (&optional see)
+ (let* ((def (fuel-syntax-symbol-at-point))
+ (prompt (format "See%s help on%s: " (if see " short" "")
+ (if def (format " (%s)" def) "")))
+ (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--history def) def))
+ (cmd (format "\\ %s %s" def (if see "see" "help")))
+ (fuel-eval--log nil)
+ (ret (fuel-eval--eval-string/context cmd t))
+ (out (fuel-eval--retort-output ret)))
+ (if (or (fuel-eval--retort-error ret) (empty-string-p out))
+ (message "No help for '%s'" def)
+ (let ((hb (fuel-help--help-buffer))
+ (inhibit-read-only t)
+ (font-lock-verbose nil))
+ (set-buffer hb)
+ (erase-buffer)
+ (insert out)
+ (set-buffer-modified-p nil)
+ (pop-to-buffer hb)
+ (goto-char (point-min))))))
+
+\f
+;;; Interface: see/help commands
+
+(defun fuel-help-short (&optional arg)
+ "See a help summary of symbol at point.
+By default, the information is shown in the minibuffer. When
+called with a prefix argument, the information is displayed in a
+separate help buffer."
+ (interactive "P")
+ (if (if fuel-help-use-minibuffer (not arg) arg)
+ (fuel-help--word-synopsis)
+ (fuel-help--show-help t)))
+
+(defun fuel-help ()
+ "Show extended help about the symbol at point, using a help
+buffer."
+ (interactive)
+ (fuel-help--show-help))
+
+\f
+(provide 'fuel-help)
+;;; fuel-help.el ends here
--- /dev/null
+;;; fuel-listener.el --- starting the fuel listener
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages
+
+;;; Commentary:
+
+;; Utilities to maintain and switch to a factor listener comint
+;; buffer, with an accompanying major fuel-listener-mode.
+
+;;; Code:
+
+(require 'fuel-eval)
+(require 'fuel-base)
+(require 'comint)
+
+\f
+;;; Customization:
+
+(defgroup fuel-listener nil
+ "Interacting with a Factor listener inside Emacs"
+ :group 'fuel)
+
+(defcustom fuel-listener-factor-binary "~/factor/factor"
+ "Full path to the factor executable to use when starting a listener."
+ :type '(file :must-match t)
+ :group 'fuel-listener)
+
+(defcustom fuel-listener-factor-image "~/factor/factor.image"
+ "Full path to the factor image to use when starting a listener."
+ :type '(file :must-match t)
+ :group 'fuel-listener)
+
+(defcustom fuel-listener-use-other-window t
+ "Use a window other than the current buffer's when switching to
+the factor-listener buffer."
+ :type 'boolean
+ :group 'fuel-listener)
+
+(defcustom fuel-listener-window-allow-split t
+ "Allow window splitting when switching to the fuel listener
+buffer."
+ :type 'boolean
+ :group 'fuel-listener)
+
+\f
+;;; Fuel listener buffer/process:
+
+(defvar fuel-listener-buffer nil
+ "The buffer in which the Factor listener is running.")
+
+(defun fuel-listener--start-process ()
+ (let ((factor (expand-file-name fuel-listener-factor-binary))
+ (image (expand-file-name fuel-listener-factor-image)))
+ (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))
+ (setq fuel-listener-buffer (get-buffer-create "*fuel listener*"))
+ (with-current-buffer fuel-listener-buffer
+ (fuel-listener-mode)
+ (message "Starting FUEL listener ...")
+ (comint-exec fuel-listener-buffer "factor"
+ factor nil `("-run=fuel" ,(format "-i=%s" image)))
+ (fuel-listener--wait-for-prompt 20)
+ (fuel-eval--send-string "USE: fuel")
+ (message "FUEL listener up and running!"))))
+
+(defun fuel-listener--process (&optional start)
+ (or (and (buffer-live-p fuel-listener-buffer)
+ (get-buffer-process fuel-listener-buffer))
+ (if (not start)
+ (error "No running factor listener (try M-x run-factor)")
+ (fuel-listener--start-process)
+ (fuel-listener--process))))
+
+(setq fuel-eval--default-proc-function 'fuel-listener--process)
+
+\f
+;;; 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
+ (while (progn (goto-char comint-last-input-end)
+ (not (or seen
+ (setq seen
+ (re-search-forward comint-prompt-regexp nil t))
+ (not (accept-process-output proc timeout))))))
+ (goto-char (point-max)))
+ (unless seen
+ (pop-to-buffer fuel-listener-buffer)
+ (error "No prompt found!"))))
+
+\f
+;;; Interface: starting fuel listener
+
+(defalias 'switch-to-factor 'run-factor)
+(defalias 'switch-to-fuel-listener 'run-factor)
+;;;###autoload
+(defun run-factor (&optional arg)
+ "Show the fuel-listener buffer, starting the process if needed."
+ (interactive)
+ (let ((buf (process-buffer (fuel-listener--process t)))
+ (pop-up-windows fuel-listener-window-allow-split))
+ (if fuel-listener-use-other-window
+ (pop-to-buffer buf)
+ (switch-to-buffer buf))))
+
+\f
+;;; 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-read-only) t)
+ (setq fuel-listener--compilation-begin nil))
+
+(define-key fuel-listener-mode-map "\C-ch" 'fuel-help)
+(define-key fuel-listener-mode-map "\M-." 'fuel-edit-word-at-point)
+(define-key fuel-listener-mode-map "\C-ck" 'fuel-run-file)
+
+\f
+(provide 'fuel-listener)
+;;; fuel-listener.el ends here
--- /dev/null
+;;; fuel-mode.el -- Minor mode enabling FUEL niceties
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages, fuel, factor
+;; Start date: Sat Dec 06, 2008 00:52
+
+;;; Comentary:
+
+;; Enhancements to vanilla factor-mode (notably, listener interaction)
+;; enabled by means of a minor mode.
+
+;;; Code:
+
+(require 'factor-mode)
+(require 'fuel-base)
+(require 'fuel-syntax)
+(require 'fuel-font-lock)
+(require 'fuel-debug)
+(require 'fuel-help)
+(require 'fuel-eval)
+(require 'fuel-listener)
+
+\f
+;;; Customization:
+
+(defgroup fuel-mode nil
+ "Mode enabling FUEL's ultimate abilities."
+ :group 'fuel)
+
+(defcustom fuel-mode-autodoc-p t
+ "Whether `fuel-autodoc-mode' gets enable by default in fuel buffers."
+ :group 'fuel-mode
+ :type 'boolean)
+
+\f
+;;; User commands
+
+(defun fuel-run-file (&optional arg)
+ "Sends the current file to Factor for compilation.
+With prefix argument, ask for the file to run."
+ (interactive "P")
+ (let* ((file (or (and arg (read-file-name "File: " nil (buffer-file-name) t))
+ (buffer-file-name)))
+ (file (expand-file-name file))
+ (buffer (find-file-noselect file))
+ (cmd (format "%S fuel-run-file" file)))
+ (when buffer
+ (with-current-buffer buffer
+ (message "Compiling %s ..." file)
+ (let ((r (fuel-debug--display-retort (fuel-eval--eval-string/context cmd)
+ (format "%s successfully compiled" file)
+ nil
+ file)))
+ (if r (message "Compiling %s ... OK!" file) (message "")))))))
+
+(defun fuel-eval-region (begin end &optional arg)
+ "Sends region to Fuel's listener for evaluation.
+Unless called with a prefix, switchs to the compilation results
+buffer in case of errors."
+ (interactive "r\nP")
+ (fuel-debug--display-retort
+ (fuel-eval--eval-region/context begin end)
+ (format "%s%s"
+ (if fuel-syntax--current-vocab
+ (format "IN: %s " fuel-syntax--current-vocab)
+ "")
+ (fuel--shorten-region begin end 70))
+ arg
+ (buffer-file-name)))
+
+(defun fuel-eval-extended-region (begin end &optional arg)
+ "Sends region extended outwards to nearest definitions,
+to Fuel's listener for evaluation.
+Unless called with a prefix, switchs to the compilation results
+buffer in case of errors."
+ (interactive "r\nP")
+ (fuel-eval-region (save-excursion (goto-char begin) (mark-defun) (point))
+ (save-excursion (goto-char end) (mark-defun) (mark))
+ arg))
+
+(defun fuel-eval-definition (&optional arg)
+ "Sends definition around point to Fuel's listener for evaluation.
+Unless called with a prefix, switchs to the compilation results
+buffer in case of errors."
+ (interactive "P")
+ (save-excursion
+ (mark-defun)
+ (let* ((begin (point))
+ (end (mark)))
+ (unless (< begin end) (error "No evaluable definition around point"))
+ (fuel-eval-region begin end arg))))
+
+(defun fuel-edit-word-at-point (&optional arg)
+ "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* ((ret (fuel-eval--eval-string/context
+ (format "\\ %s fuel-get-edit-location" word)))
+ (err (fuel-eval--retort-error ret))
+ (loc (fuel-eval--retort-result ret)))
+ (when (or err (not loc) (not (listp loc)) (not (stringp (car loc))))
+ (error "Couldn't find edit location for '%s'" word))
+ (unless (file-readable-p (car loc))
+ (error "Couldn't open '%s' for read" (car loc)))
+ (find-file-other-window (car loc))
+ (goto-line (if (numberp (cadr loc)) (cadr loc) 1)))))
+
+\f
+;;; Minor mode definition:
+
+(make-variable-buffer-local
+ (defvar fuel-mode-string " F"
+ "Modeline indicator for fuel-mode"))
+
+(defvar fuel-mode-map (make-sparse-keymap)
+ "Key map for fuel-mode")
+
+(define-minor-mode fuel-mode
+ "Toggle Fuel's mode.
+With no argument, this command toggles the mode.
+Non-null prefix argument turns on the mode.
+Null prefix argument turns off the mode.
+
+When Fuel mode is enabled, a host of nice utilities for
+interacting with a factor listener is at your disposal.
+\\{fuel-mode-map}"
+ :init-value nil
+ :lighter fuel-mode-string
+ :group 'fuel
+ :keymap fuel-mode-map
+
+ (setq fuel-autodoc-mode-string "/A")
+ (when fuel-mode-autodoc-p (fuel-autodoc-mode fuel-mode)))
+
+\f
+;;; Keys:
+
+(defun fuel-mode--key-1 (k c)
+ (define-key fuel-mode-map (vector '(control ?c) k) c)
+ (define-key fuel-mode-map (vector '(control ?c) `(control ,k)) c))
+
+(defun fuel-mode--key (p k c)
+ (define-key fuel-mode-map (vector '(control ?c) `(control ,p) k) c)
+ (define-key fuel-mode-map (vector '(control ?c) `(control ,p) `(control ,k)) c))
+
+(fuel-mode--key-1 ?z 'run-factor)
+
+(fuel-mode--key-1 ?k 'fuel-run-file)
+(fuel-mode--key ?e ?k 'fuel-run-file)
+
+(define-key fuel-mode-map "\C-\M-x" 'fuel-eval-definition)
+(fuel-mode--key ?e ?x 'fuel-eval-definition)
+
+(fuel-mode--key-1 ?r 'fuel-eval-region)
+(fuel-mode--key ?e ?r 'fuel-eval-region)
+
+(define-key fuel-mode-map "\C-\M-r" 'fuel-eval-extended-region)
+(fuel-mode--key ?e ?e 'fuel-eval-extended-region)
+
+(define-key fuel-mode-map "\M-." 'fuel-edit-word-at-point)
+
+(fuel-mode--key ?d ?a 'fuel-autodoc-mode)
+(fuel-mode--key ?d ?d 'fuel-help)
+(fuel-mode--key ?d ?s 'fuel-help-short)
+
+\f
+(provide 'fuel-mode)
+;;; fuel-mode.el ends here
--- /dev/null
+;;; fuel-syntax.el --- auxiliar definitions for factor code navigation.
+
+;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
+;; See http://factorcode.org/license.txt for BSD license.
+
+;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
+;; Keywords: languages
+
+;;; Commentary:
+
+;; Auxiliar constants and functions to parse factor code.
+
+;;; Code:
+
+(require 'thingatpt)
+
+\f
+;;; Thing-at-point support for factor symbols:
+
+(defun fuel-syntax--beginning-of-symbol ()
+ "Move point to the beginning of the current symbol."
+ (while (eq (char-before) ?:) (backward-char))
+ (skip-syntax-backward "w_"))
+
+(defun fuel-syntax--end-of-symbol ()
+ "Move point to the end of the current symbol."
+ (skip-syntax-forward "w_")
+ (while (looking-at ":") (forward-char)))
+
+(put 'factor-symbol 'end-op 'fuel-syntax--end-of-symbol)
+(put 'factor-symbol 'beginning-op 'fuel-syntax--beginning-of-symbol)
+
+(defsubst fuel-syntax-symbol-at-point ()
+ (let ((s (substring-no-properties (thing-at-point 'factor-symbol))))
+ (and (> (length s) 0) s)))
+
+\f
+;;; Regexps galore:
+
+(defconst fuel-syntax--parsing-words
+ '("{" "}" "^:" "^::" ";" "<<" "<PRIVATE" ">>"
+ "BIN:" "BV{" "B{" "C:" "C-STRUCT:" "C-UNION:" "CHAR:" "CS{" "C{"
+ "DEFER:" "ERROR:" "EXCLUDE:" "FORGET:"
+ "GENERIC#" "GENERIC:" "HEX:" "HOOK:" "H{"
+ "IN:" "INSTANCE:" "INTERSECTION:"
+ "M:" "MACRO:" "MACRO::" "MAIN:" "MATH:" "METHOD:" "MIXIN:"
+ "OCT:" "POSTPONE:" "PREDICATE:" "PRIMITIVE:" "PRIVATE>" "PROVIDE:"
+ "REQUIRE:" "REQUIRES:" "SINGLETON:" "SLOT:" "SYMBOL:" "SYMBOLS:"
+ "TUPLE:" "T{" "t\\??" "TYPEDEF:"
+ "UNION:" "USE:" "USING:" "V{" "VARS:" "W{"))
+
+(defconst fuel-syntax--parsing-words-ext-regex
+ (regexp-opt '("B" "call-next-method" "delimiter" "f" "initial:" "read-only")
+ 'words))
+
+(defconst fuel-syntax--declaration-words
+ '("flushable" "foldable" "inline" "parsing" "recursive"))
+
+(defconst fuel-syntax--declaration-words-regex
+ (regexp-opt fuel-syntax--declaration-words 'words))
+
+(defsubst fuel-syntax--second-word-regex (prefixes)
+ (format "^%s +\\([^ \r\n]+\\)" (regexp-opt prefixes t)))
+
+(defconst fuel-syntax--method-definition-regex
+ "^M: +\\([^ ]+\\) +\\([^ ]+\\)")
+
+(defconst fuel-syntax--word-definition-regex
+ (fuel-syntax--second-word-regex '(":" "::" "GENERIC:")))
+
+(defconst fuel-syntax--type-definition-regex
+ (fuel-syntax--second-word-regex '("TUPLE:" "SINGLETON:")))
+
+(defconst fuel-syntax--parent-type-regex "^TUPLE: +[^ ]+ +< +\\([^ ]+\\)")
+
+(defconst fuel-syntax--constructor-regex "<[^ >]+>")
+
+(defconst fuel-syntax--setter-regex "\\W>>[^ ]+\\b")
+
+(defconst fuel-syntax--symbol-definition-regex
+ (fuel-syntax--second-word-regex '("SYMBOL:" "VAR:")))
+
+(defconst fuel-syntax--stack-effect-regex " ( .* )")
+
+(defconst fuel-syntax--using-lines-regex "^USING: +\\([^;]+\\);")
+
+(defconst fuel-syntax--use-line-regex "^USE: +\\(.*\\)$")
+
+(defconst fuel-syntax--current-vocab-regex "^IN: +\\([^ \r\n\f]+\\)")
+
+(defconst fuel-syntax--sub-vocab-regex "^<\\([^ \n]+\\) *$")
+
+(defconst fuel-syntax--definition-starters-regex
+ (regexp-opt '("VARS" "TUPLE" "MACRO" "MACRO:" "M" ":" "")))
+
+(defconst fuel-syntax--definition-start-regex
+ (format "^\\(%s:\\) " fuel-syntax--definition-starters-regex))
+
+(defconst fuel-syntax--definition-end-regex
+ (format "\\(\\(^\\| +\\);\\( +%s\\)*\\($\\| +\\)\\)"
+ fuel-syntax--declaration-words-regex))
+
+(defconst fuel-syntax--single-liner-regex
+ (format "^%s" (regexp-opt '("DEFER:" "GENERIC:" "IN:"
+ "PRIVATE>" "<PRIVATE"
+ "SINGLETON:" "SYMBOL:" "USE:" "VAR:"))))
+
+(defconst fuel-syntax--begin-of-def-regex
+ (format "^USING: \\|\\(%s\\)\\|\\(%s .*\\)"
+ fuel-syntax--definition-start-regex
+ fuel-syntax--single-liner-regex))
+
+(defconst fuel-syntax--end-of-def-line-regex
+ (format "^.*%s" fuel-syntax--definition-end-regex))
+
+(defconst fuel-syntax--end-of-def-regex
+ (format "\\(%s\\)\\|\\(%s .*\\)"
+ fuel-syntax--end-of-def-line-regex
+ fuel-syntax--single-liner-regex))
+\f
+;;; Factor syntax table
+
+(defvar fuel-syntax--syntax-table
+ (let ((i 0)
+ (table (make-syntax-table)))
+ ;; Default is atom-constituent
+ (while (< i 256)
+ (modify-syntax-entry i "_ " table)
+ (setq i (1+ i)))
+
+ ;; Word components.
+ (setq i ?0)
+ (while (<= i ?9)
+ (modify-syntax-entry i "w " table)
+ (setq i (1+ i)))
+ (setq i ?A)
+ (while (<= i ?Z)
+ (modify-syntax-entry i "w " table)
+ (setq i (1+ i)))
+ (setq i ?a)
+ (while (<= i ?z)
+ (modify-syntax-entry i "w " table)
+ (setq i (1+ i)))
+
+ ;; Whitespace
+ (modify-syntax-entry ?\t " " table)
+ (modify-syntax-entry ?\f " " table)
+ (modify-syntax-entry ?\r " " table)
+ (modify-syntax-entry ? " " table)
+
+ ;; (end of) Comments
+ (modify-syntax-entry ?\n ">" table)
+
+ ;; Parenthesis
+ (modify-syntax-entry ?\[ "(] " table)
+ (modify-syntax-entry ?\] ")[ " table)
+ (modify-syntax-entry ?{ "(} " table)
+ (modify-syntax-entry ?} "){ " table)
+
+ (modify-syntax-entry ?\( "()" table)
+ (modify-syntax-entry ?\) ")(" table)
+
+ ;; Strings
+ (modify-syntax-entry ?\" "\"" table)
+ (modify-syntax-entry ?\\ "/" table)
+ table)
+ "Syntax table used while in Factor mode.")
+
+(defconst fuel-syntax--syntactic-keywords
+ `(("\\(#!\\)" (1 "<"))
+ (" \\(!\\)" (1 "<"))
+ ("^\\(!\\)" (1 "<"))
+ ("\\(!(\\) .* \\()\\)" (1 "<") (2 ">"))
+ ("\\([[({]\\)\\([^ \"\n]\\)" (1 "_") (2 "_"))
+ ("\\([^ \"\n]\\)\\([])}]\\)" (1 "_") (2 "_"))))
+
+\f
+;;; Source code analysis:
+
+(defsubst fuel-syntax--brackets-depth ()
+ (nth 0 (syntax-ppss)))
+
+(defsubst fuel-syntax--brackets-start ()
+ (nth 1 (syntax-ppss)))
+
+(defun fuel-syntax--brackets-end ()
+ (save-excursion
+ (goto-char (fuel-syntax--brackets-start))
+ (condition-case nil
+ (progn (forward-sexp)
+ (1- (point)))
+ (error -1))))
+
+(defsubst fuel-syntax--indentation-at (pos)
+ (save-excursion (goto-char pos) (current-indentation)))
+
+(defsubst fuel-syntax--increased-indentation (&optional i)
+ (+ (or i (current-indentation)) factor-indent-width))
+(defsubst fuel-syntax--decreased-indentation (&optional i)
+ (- (or i (current-indentation)) factor-indent-width))
+
+(defsubst fuel-syntax--at-begin-of-def ()
+ (looking-at fuel-syntax--begin-of-def-regex))
+
+(defsubst fuel-syntax--at-end-of-def ()
+ (looking-at fuel-syntax--end-of-def-regex))
+
+(defsubst fuel-syntax--looking-at-emptiness ()
+ (looking-at "^[ \t]*$"))
+
+(defun fuel-syntax--at-setter-line ()
+ (save-excursion
+ (beginning-of-line)
+ (if (not (fuel-syntax--looking-at-emptiness))
+ (re-search-forward fuel-syntax--setter-regex (line-end-position) t)
+ (forward-line -1)
+ (or (fuel-syntax--at-constructor-line)
+ (fuel-syntax--at-setter-line)))))
+
+(defun fuel-syntax--at-constructor-line ()
+ (save-excursion
+ (beginning-of-line)
+ (re-search-forward fuel-syntax--constructor-regex (line-end-position) t)))
+
+(defsubst fuel-syntax--at-using ()
+ (looking-at fuel-syntax--using-lines-regex))
+
+(defsubst fuel-syntax--beginning-of-defun (&optional times)
+ (re-search-backward fuel-syntax--begin-of-def-regex nil t times))
+
+(defsubst fuel-syntax--end-of-defun ()
+ (re-search-forward fuel-syntax--end-of-def-regex nil t))
+
+\f
+;;; USING/IN:
+
+(make-variable-buffer-local
+ (defvar fuel-syntax--current-vocab nil))
+
+(make-variable-buffer-local
+ (defvar fuel-syntax--usings nil))
+
+(defun fuel-syntax--current-vocab ()
+ (let ((ip
+ (save-excursion
+ (when (re-search-backward fuel-syntax--current-vocab-regex nil t)
+ (setq fuel-syntax--current-vocab (match-string-no-properties 1))
+ (point)))))
+ (when ip
+ (let ((pp (save-excursion
+ (when (re-search-backward fuel-syntax--sub-vocab-regex ip t)
+ (point)))))
+ (when (and pp (> pp ip))
+ (let ((sub (match-string-no-properties 1)))
+ (unless (save-excursion (search-backward (format "%s>" sub) pp t))
+ (setq fuel-syntax--current-vocab
+ (format "%s.%s" fuel-syntax--current-vocab (downcase sub)))))))))
+ fuel-syntax--current-vocab)
+
+(defun fuel-syntax--usings-update ()
+ (save-excursion
+ (setq fuel-syntax--usings (list (fuel-syntax--current-vocab)))
+ (while (re-search-backward fuel-syntax--using-lines-regex nil t)
+ (dolist (u (split-string (match-string-no-properties 1) nil t))
+ (push u fuel-syntax--usings)))
+ fuel-syntax--usings))
+
+(defsubst fuel-syntax--usings-update-hook ()
+ (fuel-syntax--usings-update)
+ nil)
+
+(defun fuel-syntax--enable-usings ()
+ (add-hook 'before-save-hook 'fuel-syntax--usings-update-hook nil t)
+ (fuel-syntax--usings-update))
+
+(defsubst fuel-syntax--usings ()
+ (or fuel-syntax--usings (fuel-syntax--usings-update)))
+
+\f
+(provide 'fuel-syntax)
+;;; fuel-syntax.el ends here
+++ /dev/null
-
-USING: kernel words accessors
- classes
- classes.builtin
- classes.tuple
- classes.predicate
- vocabs
- arrays
- sequences sorting
- io help.markup
- effects
- generic
- prettyprint
- prettyprint.sections
- prettyprint.backend
- combinators.cleave
- obj.print ;
-
-IN: vocab-browser
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: word-effect-as-string ( word -- string )
- stack-effect dup
- [ effect>string ]
- [ drop "" ]
- if ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: print-vocabulary-summary ( vocabulary -- )
-
- dup vocab words [ builtin-class? ] filter natural-sort
- dup empty?
- [ drop ]
- [
- "Builtin Classes" $heading nl
- print-seq
- ]
- if
-
- dup vocab words [ tuple-class? ] filter natural-sort
- dup empty?
- [ drop ]
- [
- "Tuple Classes" $heading nl
- [
- { [ ] [ superclass ] [ "slots" word-prop [ name>> ] map " " join ] }
- 1arr
- ]
- map
- { "CLASS" "PARENT" "SLOTS" } prefix
- print-table
- ]
- if
-
- dup vocab words [ predicate-class? ] filter natural-sort
- dup empty?
- [ drop ]
- [
- "Predicate Classes" $heading nl
- ! [ pprint-class ] each
- [ { [ ] [ superclass ] } 1arr ] map
- { "CLASS" "SUPERCLASS" } prefix
- print-table
- ]
- if
-
- dup vocab words [ class? not ] filter [ symbol? ] filter natural-sort
- dup empty?
- [ drop ]
- [
- "Symbols" $heading nl
- print-seq
- ]
- if
-
- dup vocab words [ generic? ] filter natural-sort
- dup empty?
- [ drop ]
- [
- "Generic words" $heading nl
- [ [ ] [ stack-effect effect>string ] bi 2array ] map
- print-table
- ]
- if
-
- "Words" $heading nl
- dup vocab words
- [ predicate-class? not ] filter
- [ builtin-class? not ] filter
- [ tuple-class? not ] filter
- [ generic? not ] filter
- [ symbol? not ] filter
- [ word? ] filter
- natural-sort
- [ [ ] [ word-effect-as-string ] bi 2array ] map
- print-table
-
- drop ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-USING: vocabs.loader tools.vocabs.browser ;
-
-: $vocab-summary ( seq -- )
- first
- dup vocab
- [
- dup print-vocabulary-summary
- dup describe-help
- ! dup describe-uses
- ! dup describe-usage
- ]
- when
- dup find-vocab-root
- [
- dup describe-summary
- dup describe-tags
- dup describe-authors
- ! dup describe-files
- ]
- when
- ! dup describe-children
- drop ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-USING: assocs ui.tools.browser ui.operations io.styles ;
-
-! IN: tools.vocabs.browser
-
-! : $describe-vocab ( element -- ) $vocab-summary ;
-
-USING: tools.vocabs ;
-
-: print-vocabs ( -- )
- vocabs
- [ { [ vocab ] [ vocab-summary ] } 1arr ]
- map
- print-table ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-! : $all-vocabs ( seq -- ) drop print-vocabs ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-USING: help.syntax help.topics ;
-
-! ARTICLE: "vocab-index" "Vocabulary Index" { $all-vocabs } ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-M: vocab-spec article-content ( vocab-spec -- content )
- { $vocab-summary } swap name>> suffix ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: loaded-and-unloaded-vocabs ( -- seq )
- "" all-child-vocabs values concat [ name>> ] map ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-! ARTICLE: "loaded-vocabs-index" "Loaded Vocabularies" { $loaded-vocabs } ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-USING: debugger ;
-
-TUPLE: load-this-vocab name ;
-
-! : do-load-vocab ( ltv -- )
-! dup name>> require
-! name>> vocab com-follow ;
-
-: do-load-vocab ( ltv -- )
- [
- dup name>> require
- name>> vocab com-follow
- ]
- curry
- try ;
-
-[ load-this-vocab? ] \ do-load-vocab { { +primary+ t } } define-operation
-
-M: load-this-vocab pprint* ( obj -- )
- [ name>> "*" append ] [ ] bi write-object ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: vocab-or-loader ( name -- obj )
- dup vocab
- [ vocab ]
- [ load-this-vocab boa ]
- if ;
-
-: vocab-summary-text ( vocab-name -- text )
- dup vocab-summary-path vocab-file-contents
- dup empty?
- [ drop "" ]
- [ first ]
- if ;
-
-! : vocab-table-entry ( vocab-name -- seq )
-! { [ vocab-or-loader ] [ vocab-summary ] } 1arr ;
-
-: vocab-table-entry ( vocab-name -- seq )
- { [ vocab-or-loader ] [ vocab-summary-text ] } 1arr ;
-
-: print-these-vocabs ( seq -- ) [ vocab-table-entry ] map print-table ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-! : vocab-list ( -- seq ) "" all-child-vocabs values concat [ name>> ] map ;
-
-: all-vocab-names ( -- seq )
- all-vocabs values concat [ name>> ] map natural-sort ;
-
-: loaded-vocab-names ( -- seq ) all-vocab-names [ vocab ] filter ;
-
-: unloaded-vocab-names ( -- seq ) all-vocab-names [ vocab not ] filter ;
-
-: root->names ( root -- seq ) all-vocabs at [ name>> ] map natural-sort ;
-
-: vocab-names-core ( -- seq ) "resource:core" root->names ;
-: vocab-names-basis ( -- seq ) "resource:basis" root->names ;
-: vocab-names-extra ( -- seq ) "resource:extra" root->names ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-: $all-vocabs ( seq -- ) drop all-vocab-names print-these-vocabs ;
-: $loaded-vocabs ( seq -- ) drop loaded-vocab-names print-these-vocabs ;
-: $unloaded-vocabs ( seq -- ) drop unloaded-vocab-names print-these-vocabs ;
-
-: $vocabs-core ( seq -- ) drop vocab-names-core print-these-vocabs ;
-: $vocabs-basis ( seq -- ) drop vocab-names-basis print-these-vocabs ;
-: $vocabs-extra ( seq -- ) drop vocab-names-extra print-these-vocabs ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-! { "" }
-
-! all-child-vocabs values concat [ name>> ] map
-
-! : vocab-tree ( vocab -- seq )
-! dup
-! all-child-vocabs values concat [ name>> ] map prune
-! [ vocab-tree ]
-! map
-! concat
-! swap prefix
-! [ vocab-source-path ] filter ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-M: vocab-author pprint* ( vocab-author -- ) [ name>> ] [ ] bi write-object ;
-
-: $vocab-authors ( seq -- )
- drop all-authors [ vocab-author boa ] map print-seq ;
-
-ARTICLE: "vocab-authors" "Vocabulary Authors" { $vocab-authors } ;
-
-: vocabs-by-author ( author -- vocab-names )
- authored values concat [ name>> ] map ;
-
-: $vocabs-by-author ( seq -- )
- first name>> vocabs-by-author print-these-vocabs ;
-
-M: vocab-author article-content ( vocab-author -- content )
- { $vocabs-by-author } swap suffix ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-M: vocab-tag pprint* ( vocab-tag -- ) [ name>> ] [ ] bi write-object ;
-
-: print-vocab-tags ( -- ) all-tags [ vocab-tag boa ] map print-seq ;
-
-: $vocab-tags ( seq -- ) drop print-vocab-tags ;
-
-ARTICLE: "vocab-tags" "Vocabulary Tags" { $vocab-tags } ;
-
-: $vocabs-with-tag ( seq -- )
- first tagged values concat [ name>> ] map print-these-vocabs ;
-
-M: vocab-tag article-content ( vocab-tag -- content )
- name>> { $vocabs-with-tag } swap suffix ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-ARTICLE: "vocab-index-all" "All Vocabularies" { $all-vocabs } ;
-ARTICLE: "vocab-index-loaded" "Loaded Vocabularies" { $loaded-vocabs } ;
-ARTICLE: "vocab-index-unloaded" "Unloaded Vocabularies" { $loaded-vocabs } ;
-
-ARTICLE: "vocab-index-core" "Core Vocabularies" { $vocabs-core } ;
-ARTICLE: "vocab-index-basis" "Basis Vocabularies" { $vocabs-basis } ;
-ARTICLE: "vocab-index-extra" "Extra Vocabularies" { $vocabs-extra } ;
-
-ARTICLE: "vocab-indices" "Vocabulary Indices"
- { $subsection "vocab-index-core" }
- { $subsection "vocab-index-basis" }
- { $subsection "vocab-index-extra" }
- { $subsection "vocab-index-all" }
- { $subsection "vocab-index-loaded" }
- { $subsection "vocab-index-unloaded" }
- { $subsection "vocab-authors" }
- { $subsection "vocab-tags" } ;
-
-! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
+++ /dev/null
-This directory contains Factor code that is not part of the core
-library, but is useful enough to ship with the Factor distribution.
-
-Modules can be loaded from the listener:
-
- "libs/modulename" require
-
-Available libraries:
-
-- alarms -- call a quotation at a calendar date (Doug Coleman)
-- alien -- Alien utility words (Eduardo Cavazos)
-- base64 -- base64 encoding/decoding (Doug Coleman)
-- basic-authentication -- basic authentication implementation for HTTP server (Chris Double)
-- cairo -- cairo bindings (Sampo Vuori)
-- calendar -- timestamp/calendar with timezones (Doug Coleman)
-- canvas -- Gadget which renders an OpenGL display list (Slava Pestov)
-- cocoa-callbacks -- Allows you to use Factor quotations as actions (Slava Pestov)
-- concurrency -- Erlang/Termite-style distibuted concurrency (Chris Double)
-- coroutines -- coroutines (Chris Double)
-- cryptlib -- cryptlib binding (Elie Chaftari)
-- crypto -- Various cryptographic algorithms (Doug Coleman)
-- csv -- Comma-separated values parser (Daniel Ehrenberg)
-- dlists -- double-linked-lists (Mackenzie Straight)
-- editpadpro -- EditPadPro integration for Windows (Ryan Murphy)
-- emacs -- emacs integration (Eduardo Cavazos)
-- farkup -- Wiki-style markup (Matthew Willis)
-- file-appender -- append to existing files (Doug Coleman)
-- fjsc -- Factor to Javascript compiler (Chris Double)
-- furnace -- Web framework (Slava Pestov)
-- gap-buffer -- Efficient text editor buffer (Alex Chapman)
-- graphics -- Graphics library in Factor (Doug Coleman)
-- hardware-info -- Information about your computer (Doug Coleman)
-- handler -- Gesture handler mixin (Eduardo Cavazos)
-- heap -- Binary min heap implementation (Ryan Murphy)
-- hexdump -- Hexdump routine (Doug Coleman)
-- http -- Code shared by HTTP server and client (Slava Pestov)
-- http-client -- HTTP client (Slava Pestov)
-- id3 -- ID3 parser (Adam Wendt)
-- io -- mmap, filesystem utils (Doug Coleman)
-- jedit -- jEdit editor integration (Slava Pestov)
-- jni -- Java Native Interface Wrapper (Chris Double)
-- json -- JSON reader and writer (Chris Double)
-- koszul -- Lie algebra cohomology and central representation (Slava Pestov)
-- lazy-lists -- Lazy evaluation lists (Chris Double, Matthew Willis)
-- locals -- Crappy local variables (Slava Pestov)
-- mad -- Wrapper for libmad MP3 decoder (Adam Wendt)
-- match -- pattern matching (Chris Double)
-- math -- extended math library (Doug Coleman, Slava Pestov)
-- matrices -- Matrix math (Slava Pestov)
-- memoize -- memoization (caching word results) (Slava Pestov)
-- mmap -- memory mapped files (Doug Coleman)
-- mysql -- MySQL binding (Berlin Brown)
-- null-stream -- Something akin to /dev/null (Slava Pestov)
-- odbc -- Wrapper for ODBC library (Chris Double)
-- ogg -- Wrapper for libogg library (Chris Double)
-- openal -- Wrapper for OpenAL and alut sound libraries (Chris Double)
-- oracle -- Oracle binding (Elie Chaftari)
-- parser-combinators -- Haskell-style parser combinators (Chris Double)
-- porter-stemmer -- Porter stemming algorithm (Slava Pestov)
-- postgresql -- PostgreSQL binding (Doug Coleman)
-- process -- Run external programs (Slava Pestov, Doug Coleman)
-- qualified -- Qualified names for words in other vocabularies (Daniel Ehrenberg)
-- rewrite-closures -- Turn quotations into closures (Eduardo Cavazos)
-- scite -- SciTE editor integration (Clemens F. Hofreither)
-- sequences -- Non-core sequence words (Eduardo Cavazos)
-- serialize -- Binary object serialization (Chris Double)
-- server -- The with-server combinator formely found in the core (Slava Pestov)
-- slate -- Framework for graphical demos (Eduardo Cavazos)
-- shuffle -- Shuffle words not in the core library (Chris Double)
-- smtp -- SMTP client library (Elie Chaftari)
-- splay-trees -- Splay trees (Mackenzie Straight)
-- sqlite -- SQLite binding (Chris Double)
-- state-machine -- Finite state machine abstraction (Daniel Ehrenberg)
-- state-parser -- State-based parsing mechanism (Daniel Ehrenberg)
-- textmate -- TextMate integration (Benjamin Pollack)
-- theora -- Wrapper for libtheora library (Chris Double)
-- trees -- Binary search and AVL (balanced) trees (Alex Chapman)
-- usb -- Wrapper for libusb (Chris Double)
-- unicode -- Partial Unicode support beyond the core (Daniel Ehrenberg)
-- units -- Unit conversion (Doug Coleman)
-- vars -- Alternative syntax for variables (Eduardo Cavazos)
-- vim -- VIM integration (Alex Chapman)
-- visitor -- Double dispatch through the visitor pattern (Daniel Ehrenberg)
-- vorbis -- Wrapper for Ogg Vorbis library (Chris Double)
-- x11 -- X Window System client library (Eduardo Cavazos)
-- xml -- XML parser (Daniel Ehrenberg)
-- xml-rpc -- XML-RPC client and server (Daniel Ehrenberg)
-- yahoo -- Yahoo! automated search (Daniel Ehrenberg)
+++ /dev/null
-This directory contains Factor code that is not part of the core
-library, but is useful enough to ship with the Factor distribution.
-
-Modules can be loaded from the listener:
-
- "apps/modulename" require
-
-Available applications:
-
-- article-manager -- Web-based content management system (Chris Double)
-- automata -- Graphics demo for the UI (Eduardo Cavazos)
-- benchmarks -- Various performance benchmarks (Slava Pestov)
-- boids -- Graphics demo for the UI (Eduardo Cavazos)
-- factory -- X11 window manager (Eduardo Cavazos)
-- furnace-fjsc -- Web frontend for libs/fjsc (Chris Double)
-- furnace-onigiri -- Weblog engine (Matthew Willis)
-- furnace-pastebin -- demo app for Furnace (Slava Pestov)
-- help-lint -- online documentation typo checker (Slava Pestov)
-- icfp-2006 -- implements the icfp 2006 vm, boundvariable.org (Gavin Harrison)
-- http-server -- HTTP server (Slava Pestov, Chris Double)
-- lindenmayer -- L-systems tool (Eduardo Cavazos)
-- lisppaste -- Lisppaste XML-RPC demo (Slava Pestov)
-- ogg-player -- Ogg Vorbis (audio) and Theora (video) player (Chris Double)
-- print-dataflow -- Code to print compiler dataflow IR to the console, or show it in the UI (Slava Pestov)
-- random-tester -- Random compiler tester (Doug Coleman)
-- rss -- An RSS1, RSS2 and Atom parser and aggregator (Chris Double, Daniel Ehrenberg)
-- space-invaders -- Intel 8080-based Space Invaders arcade machine emulator (Chris Double)
-- tetris -- Tetris game (Alex Chapman)
-- turing -- Turing machine demo (Slava Pestov)
-- wee-url -- Web app to make short URLs from long ones (Doug Coleman)
--- /dev/null
+Eduardo Cavazos
--- /dev/null
+USING: tools.deploy.config ;
+V{
+ { deploy-ui? t }
+ { deploy-io 1 }
+ { deploy-reflection 1 }
+ { deploy-compiler? t }
+ { deploy-math? t }
+ { deploy-word-props? f }
+ { deploy-c-types? f }
+ { "stop-after-last-window?" t }
+ { deploy-name "Golden Section" }
+}
--- /dev/null
+
+USING: kernel namespaces math math.constants math.functions math.order
+ arrays sequences
+ opengl opengl.gl opengl.glu ui ui.render ui.gadgets ui.gadgets.theme
+ ui.gadgets.cartesian colors accessors combinators.cleave
+ processing.shapes ;
+
+IN: golden-section
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! omega(i) = 2*pi*i*(phi-1)
+
+! x(i) = 0.5*i*cos(omega(i))
+! y(i) = 0.5*i*sin(omega(i))
+
+! radius(i) = 10*sin((pi*i)/720)
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: omega ( i -- omega ) phi 1- * 2 * pi * ;
+
+: x ( i -- x ) [ omega cos ] [ 0.5 * ] bi * ;
+: y ( i -- y ) [ omega sin ] [ 0.5 * ] bi * ;
+
+: center ( i -- point ) { x y } 1arr ;
+
+: radius ( i -- radius ) pi * 720 / sin 10 * ;
+
+: color ( i -- i ) dup 360.0 / dup 0.25 1 rgba boa >fill-color ;
+
+: line-width ( i -- i ) dup radius 0.5 * 1 max glLineWidth ;
+
+: draw ( i -- ) [ center ] [ radius 1.5 * 2 * ] bi circle ;
+
+: dot ( i -- ) color line-width draw ;
+
+: golden-section ( -- ) 720 [ dot ] each ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: <golden-section> ( -- gadget )
+ <cartesian>
+ { 600 600 } >>pdim
+ { -400 400 } x-range
+ { -400 400 } y-range
+ [ golden-section ] >>action ;
+
+: golden-section-window ( -- )
+ [ <golden-section> "Golden Section" open-window ] with-ui ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+MAIN: golden-section-window
--- /dev/null
+Golden section demo
+++ /dev/null
-USING: kernel ;
-
-REQUIRES: libs/calendar libs/shuffle ;
-
-PROVIDE: libs/io
-{ +files+ {
- "io.factor"
- "mmap.factor"
- "shell.factor"
- { "os-unix.factor" [ unix? ] }
- { "os-unix-shell.factor" [ unix? ] }
- { "mmap-os-unix.factor" [ unix? ] }
-
- { "os-winnt.factor" [ winnt? ] }
- { "os-winnt-shell.factor" [ winnt? ] }
- { "mmap-os-winnt.factor" [ winnt? ] }
-
- { "os-wince.factor" [ wince? ] }
-} }
-{ +tests+ {
- "test/io.factor"
- "test/mmap.factor"
-} } ;
-
+++ /dev/null
-USING: arrays kernel libs-io sequences prettyprint unix-internals
-calendar namespaces math ;
-USE: io
-IN: shell
-
-TUPLE: unix-shell ;
-
-T{ unix-shell } \ shell set-global
-
-TUPLE: file name mode nlink uid gid size mtime symbol ;
-
-M: unix-shell directory* ( path -- seq )
- dup (directory) [ tuck >r "/" r> 3append stat* 2array ] map-with ;
-
-M: unix-shell make-file ( path -- file )
- first2
- [ stat-mode ] keep
- [ stat-nlink ] keep
- [ stat-uid ] keep
- [ stat-gid ] keep
- [ stat-size ] keep
- [ stat-mtime timespec>timestamp >local-time ] keep
- stat-mode mode>symbol <file> ;
-
-M: unix-shell file. ( file -- )
- [ [ file-mode >oct write ] keep ] with-cell
- [ bl ] with-cell
- [ [ file-nlink unparse write ] keep ] with-cell
- [ bl ] with-cell
- [ [ file-uid unparse write ] keep ] with-cell
- [ bl ] with-cell
- [ [ file-gid unparse write ] keep ] with-cell
- [ bl ] with-cell
- [ [ file-size unparse write ] keep ] with-cell
- [ bl ] with-cell
- [ [ file-mtime file-time-string write ] keep ] with-cell
- [ bl ] with-cell
- [ file-name write ] with-cell ;
-
-USE: unix-internals
-M: unix-shell touch-file ( path -- )
- dup open-append dup -1 = [
- drop now dup set-file-times
- ] [
- nip [ now dup set-file-times* ] keep close
- ] if ;
+++ /dev/null
-! Copyright (C) 2007 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: alien arrays calendar errors io io-internals kernel
-math nonblocking-io sequences unix-internals unix-io ;
-IN: libs-io
-
-: O_APPEND HEX: 100 ; inline
-: O_EXCL HEX: 800 ; inline
-: SEEK_SET 0 ; inline
-: SEEK_CUR 1 ; inline
-: SEEK_END 2 ; inline
-: EEXIST 17 ; inline
-
-: mode>symbol ( mode -- ch )
- S_IFMT bitand
- {
- { [ dup S_IFDIR = ] [ drop "/" ] }
- { [ dup S_IFIFO = ] [ drop "|" ] }
- { [ dup S_IXUSR = ] [ drop "*" ] }
- { [ dup S_IFLNK = ] [ drop "@" ] }
- { [ dup S_IFWHT = ] [ drop "%" ] }
- { [ dup S_IFSOCK = ] [ drop "=" ] }
- { [ t ] [ drop "" ] }
- } cond ;
+++ /dev/null
-USING: alien calendar io io-internals kernel libs-io math
-namespaces prettyprint sequences windows-api ;
-IN: shell
-
-TUPLE: winnt-shell ;
-
-T{ winnt-shell } \ shell set-global
-
-TUPLE: file name size mtime attributes ;
-
-: ((directory*)) ( handle -- )
- "WIN32_FIND_DATA" <c-object> [ FindNextFile ] 2keep
- rot zero? [ 2drop ] [ , ((directory*)) ] if ;
-
-: (directory*) ( path -- )
- "WIN32_FIND_DATA" <c-object> [
- FindFirstFile dup INVALID_HANDLE_VALUE = [
- win32-error
- ] when
- ] keep ,
- [ ((directory*)) ] keep FindClose win32-error=0/f ;
-
-: append-star ( path -- path )
- dup peek CHAR: \\ = "*" "\\*" ? append ;
-
-M: winnt-shell directory* ( path -- seq )
- normalize-pathname append-star [ (directory*) ] { } make ;
-
-: WIN32_FIND_DATA>file-size ( WIN32_FILE_ATTRIBUTE_DATA -- n )
- [ WIN32_FIND_DATA-nFileSizeLow ] keep
- WIN32_FIND_DATA-nFileSizeHigh 32 shift + ;
-
-M: winnt-shell make-file ( WIN32_FIND_DATA -- file )
- [ WIN32_FIND_DATA-cFileName alien>u16-string ] keep
- [ WIN32_FIND_DATA>file-size ] keep
- [
- WIN32_FIND_DATA-ftCreationTime
- FILETIME>timestamp >local-time
- ] keep
- WIN32_FIND_DATA-dwFileAttributes <file> ;
-
-M: winnt-shell file. ( file -- )
- [ [ file-attributes >oct write ] keep ] with-cell
- [ bl ] with-cell
- [ [ file-size unparse write ] keep ] with-cell
- [ bl ] with-cell
- [ [ file-mtime file-time-string write ] keep ] with-cell
- [ bl ] with-cell
- [ file-name write ] with-cell ;
-
-M: winnt-shell touch-file ( path -- )
- #! Set the file write time to 'now'
- normalize-pathname
- dup maybe-create-file [ drop ] [ now set-file-write-time ] if ;
-
+++ /dev/null
-USING: alien calendar errors generic io io-internals kernel
-math namespaces nonblocking-io parser quotations sequences
-shuffle windows-api words ;
-IN: libs-io
-
-: stat* ( path -- WIN32_FIND_DATA )
- "WIN32_FIND_DATA" <c-object>
- [
- FindFirstFile
- [ INVALID_HANDLE_VALUE = [ win32-error ] when ] keep
- FindClose win32-error=0/f
- ] keep ;
-
-: set-file-time ( path timestamp/f timestamp/f timestamp/f -- )
- #! timestamp order: creation access write
- >r >r >r open-existing dup r> r> r>
- [ timestamp>FILETIME ] 3 napply
- SetFileTime win32-error=0/f
- close-handle ;
-
-: set-file-times ( path timestamp/f timestamp/f -- )
- f -rot set-file-time ;
-
-: set-file-create-time ( path timestamp -- )
- f f set-file-time ;
-
-: set-file-access-time ( path timestamp -- )
- >r f r> f set-file-time ;
-
-: set-file-write-time ( path timestamp -- )
- >r f f r> set-file-time ;
-
-: maybe-make-filetime ( ? -- FILETIME/f )
- [ "FILETIME" <c-object> ] [ f ] if ;
-
-: file-time ( path ? ? ? -- FILETIME/f FILETIME/f FILETIME/f )
- >r >r >r open-existing dup r> r> r>
- [ maybe-make-filetime ] 3 napply
- [ GetFileTime win32-error=0/f close-handle ] 3keep ;
-
-: file-times ( path -- FILETIME FILETIME FILETIME )
- t t t file-time [ FILETIME>timestamp ] 3 napply ;
-
-: file-create-time ( path -- FILETIME )
- t f f file-time 2drop FILETIME>timestamp ;
-
-: file-access-time ( path -- FILETIME )
- f t f file-time drop nip FILETIME>timestamp ;
-
-: file-write-time ( path -- FILETIME )
- f f t file-time 2nip FILETIME>timestamp ;
-
-: attrib ( path -- n )
- [ stat* WIN32_FIND_DATA-dwFileAttributes ] catch
- [ drop 0 ] when ;
-
-: (read-only?) ( mode -- ? )
- FILE_ATTRIBUTE_READONLY bit-set? ;
-
-: read-only? ( path -- ? )
- attrib (read-only?) ;
-
-: (hidden?) ( mode -- ? )
- FILE_ATTRIBUTE_HIDDEN bit-set? ;
-
-: hidden? ( path -- ? )
- attrib (hidden?) ;
-
-: (system?) ( mode -- ? )
- FILE_ATTRIBUTE_SYSTEM bit-set? ;
-
-: system? ( path -- ? )
- attrib (system?) ;
-
-: (directory?) ( mode -- ? )
- FILE_ATTRIBUTE_DIRECTORY bit-set? ;
-
-: directory? ( path -- ? )
- attrib (directory?) ;
-
-: (archive?) ( mode -- ? )
- FILE_ATTRIBUTE_ARCHIVE bit-set? ;
-
-: archive? ( path -- ? )
- attrib (archive?) ;
-
-! FILE_ATTRIBUTE_DEVICE
-! FILE_ATTRIBUTE_NORMAL
-! FILE_ATTRIBUTE_TEMPORARY
-! FILE_ATTRIBUTE_SPARSE_FILE
-! FILE_ATTRIBUTE_REPARSE_POINT
-! FILE_ATTRIBUTE_COMPRESSED
-! FILE_ATTRIBUTE_OFFLINE
-! FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
-! FILE_ATTRIBUTE_ENCRYPTED
-
+++ /dev/null
-USING: calendar io io-internals kernel math namespaces
-nonblocking-io prettyprint quotations sequences ;
-IN: shell
-
-SYMBOL: shell
-HOOK: directory* shell ( path -- seq )
-HOOK: make-file shell ( bytes -- file )
-HOOK: file. shell ( file -- )
-HOOK: touch-file shell ( path -- )
-
-: (ls) ( path -- )
- >r H{ } r> directory*
- [
- [ [ make-file file. ] with-row ] each
- ] curry tabular-output ;
-
-: ls ( -- )
- cwd (ls) ;
-
-: pwd ( -- )
- cwd pprint nl ;
-
-: (slurp) ( quot -- )
- >r default-buffer-size read r> over [
- dup slip (slurp)
- ] [
- 2drop
- ] if ;
-
-: slurp ( stream quot -- )
- [ (slurp) ] curry with-stream ;
-
-: cat ( path -- )
- <file-reader> stdio get
- duplex-stream-out <duplex-stream>
- [ write ] slurp ;
-
-: copy-file ( path path -- )
- >r <file-reader> r>
- <file-writer> <duplex-stream> [ write ] slurp ;
+++ /dev/null
-USING: calendar errors io kernel libs-io math namespaces sequences\r
-shell test ;\r
-IN: temporary\r
-\r
-SYMBOL: file "file-appender-test.txt" \ file set\r
-[ \ file get delete-file ] catch drop\r
-[ f ] [ \ file get exists? ] unit-test\r
-\ file get <file-appender> [ "asdf" write ] with-stream\r
-[ t ] [ \ file get exists? ] unit-test\r
-[ 4 ] [ \ file get file-length ] unit-test\r
-\ file get <file-appender> [ "jkl;" write ] with-stream\r
-[ t ] [ \ file get exists? ] unit-test\r
-[ 8 ] [ \ file get file-length ] unit-test\r
-[ "asdfjkl;" ] [ \ file get <file-reader> contents ] unit-test\r
-\ file get delete-file\r
-[ f ] [ \ file get exists? ] unit-test\r
-\r
-SYMBOL: directory "test-directory" \ directory set\r
-\ directory get create-directory\r
-[ t ] [ \ directory get directory? ] unit-test\r
-\ directory get delete-directory\r
-[ f ] [ \ directory get directory? ] unit-test\r
-\r
-SYMBOL: time "time-test.txt" \ time set\r
-[ \ time get delete-file ] catch drop\r
-\ time get touch-file\r
-[ 0 ] [ \ time get file-length ] unit-test\r
-[ t ] [ \ time get exists? ] unit-test\r
-\ time get 0 unix-time>timestamp dup set-file-times\r
-[ t ] [ \ time get file-write-time 0 unix-time>timestamp = ] unit-test\r
-[ t ] [ \ time get file-access-time 0 unix-time>timestamp = ] unit-test\r
-\ time get touch-file\r
-[ t ] [ now \ time get file-write-time timestamp- 10 < ] unit-test\r
-\ time get delete-file\r
-\r
-SYMBOL: longname "" 255 CHAR: a pad-left \ longname set\r
-\ longname get touch-file\r
-[ t ] [ \ longname get exists? ] unit-test\r
-[ 0 ] [ \ longname get file-length ] unit-test\r
-\ longname get delete-file\r
-[ f ] [ \ longname get exists? ] unit-test\r
-\r
+++ /dev/null
-USING: alien errors io kernel libs-io mmap namespaces test ;\r
-\r
-IN: temporary\r
-SYMBOL: mmap "mmap-test.txt" \ mmap set\r
-\r
-[ \ mmap get delete-file ] catch drop\r
-\ mmap get [\r
- "Four" write\r
-] with-file-writer\r
-\r
-\ mmap get [\r
- >r CHAR: R r> mmap-address 3 set-alien-unsigned-1\r
-] with-mmap\r
-\r
-\ mmap get [\r
- mmap-address 3 alien-unsigned-1 CHAR: R = [\r
- "mmap test failed" throw\r
- ] unless\r
-] with-mmap\r
-\r
-[ \ mmap get delete-file ] catch drop\r
--- /dev/null
+Alex Chapman
--- /dev/null
+USING: tools.deploy.config ;
+V{
+ { deploy-ui? t }
+ { deploy-io 1 }
+ { deploy-reflection 1 }
+ { deploy-compiler? t }
+ { deploy-math? t }
+ { deploy-word-props? f }
+ { deploy-c-types? f }
+ { "stop-after-last-window?" t }
+ { deploy-name "Jamshred" }
+}
--- /dev/null
+Alex Chapman
--- /dev/null
+! Copyright (C) 2007, 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel opengl arrays sequences jamshred.log jamshred.player jamshred.sound jamshred.tunnel math math.constants math.vectors ;
+IN: jamshred.game
+
+TUPLE: jamshred sounds tunnel players running quit ;
+
+: <jamshred> ( -- jamshred )
+ <sounds> <random-tunnel> "Player 1" pick <player>
+ 2dup swap play-in-tunnel 1array f f jamshred boa ;
+
+: jamshred-player ( jamshred -- player )
+ ! TODO: support more than one player
+ players>> first ;
+
+: jamshred-update ( jamshred -- )
+ dup running>> [
+ jamshred-player update-player
+ ] [ drop ] if ;
+
+: toggle-running ( jamshred -- )
+ dup running>> [
+ f >>running drop
+ ] [
+ [ jamshred-player moved ]
+ [ t >>running drop ] bi
+ ] if ;
+
+: mouse-moved ( x-radians y-radians jamshred -- )
+ jamshred-player -rot turn-player ;
+
+: units-per-full-roll ( -- n ) 50 ;
+
+: jamshred-roll ( jamshred n -- )
+ [ jamshred-player ] dip 2 pi * * units-per-full-roll / roll-player ;
+
+: mouse-scroll-x ( jamshred x -- ) jamshred-roll ;
+
+: mouse-scroll-y ( jamshred y -- )
+ neg swap jamshred-player change-player-speed ;
--- /dev/null
+Alex Chapman
--- /dev/null
+! Copyright (C) 2007, 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types jamshred.game jamshred.oint
+jamshred.player jamshred.tunnel kernel math math.constants
+math.functions math.vectors opengl opengl.gl opengl.glu
+opengl.demo-support sequences specialized-arrays.float ;
+IN: jamshred.gl
+
+: min-vertices 6 ; inline
+: max-vertices 32 ; inline
+
+: n-vertices ( -- n ) 32 ; inline
+
+! render enough of the tunnel that it looks continuous
+: n-segments-ahead ( -- n ) 60 ; inline
+: n-segments-behind ( -- n ) 40 ; inline
+
+: wall-drawing-offset ( -- n )
+ #! so that we can't see through the wall, we draw it a bit further away
+ 0.15 ;
+
+: wall-drawing-radius ( segment -- r )
+ radius>> wall-drawing-offset + ;
+
+: wall-up ( segment -- v )
+ [ wall-drawing-radius ] [ up>> ] bi n*v ;
+
+: wall-left ( segment -- v )
+ [ wall-drawing-radius ] [ left>> ] bi n*v ;
+
+: segment-vertex ( theta segment -- vertex )
+ [
+ [ wall-up swap sin v*n ] [ wall-left swap cos v*n ] 2bi v+
+ ] [
+ location>> v+
+ ] bi ;
+
+: segment-vertex-normal ( vertex segment -- normal )
+ location>> swap v- normalize ;
+
+: segment-vertex-and-normal ( segment theta -- vertex normal )
+ swap [ segment-vertex ] keep dupd segment-vertex-normal ;
+
+: equally-spaced-radians ( n -- seq )
+ #! return a sequence of n numbers between 0 and 2pi
+ dup [ / pi 2 * * ] curry map ;
+
+: draw-segment-vertex ( segment theta -- )
+ over color>> gl-color segment-vertex-and-normal
+ gl-normal gl-vertex ;
+
+: draw-vertex-pair ( theta next-segment segment -- )
+ rot tuck draw-segment-vertex draw-segment-vertex ;
+
+: draw-segment ( next-segment segment -- )
+ GL_QUAD_STRIP [
+ [ draw-vertex-pair ] 2curry
+ n-vertices equally-spaced-radians F{ 0.0 } append swap each
+ ] do-state ;
+
+: draw-segments ( segments -- )
+ 1 over length pick subseq swap [ draw-segment ] 2each ;
+
+: segments-to-render ( player -- segments )
+ dup nearest-segment>> number>> dup n-segments-behind -
+ swap n-segments-ahead + rot tunnel>> sub-tunnel ;
+
+: draw-tunnel ( player -- )
+ segments-to-render draw-segments ;
+
+: init-graphics ( width height -- )
+ GL_DEPTH_TEST glEnable
+ GL_SCISSOR_TEST glDisable
+ 1.0 glClearDepth
+ 0.0 0.0 0.0 0.0 glClearColor
+ GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear
+ GL_PROJECTION glMatrixMode glLoadIdentity
+ dup 0 = [ 2drop ] [ / >float 45.0 swap 0.1 100.0 gluPerspective ] if
+ GL_MODELVIEW glMatrixMode glLoadIdentity
+ GL_LEQUAL glDepthFunc
+ GL_LIGHTING glEnable
+ GL_LIGHT0 glEnable
+ GL_FOG glEnable
+ GL_FOG_DENSITY 0.09 glFogf
+ GL_FRONT GL_AMBIENT_AND_DIFFUSE glColorMaterial
+ GL_COLOR_MATERIAL glEnable
+ GL_LIGHT0 GL_POSITION float-array{ 0.0 0.0 0.0 1.0 } underlying>> glLightfv
+ GL_LIGHT0 GL_AMBIENT float-array{ 0.2 0.2 0.2 1.0 } underlying>> glLightfv
+ GL_LIGHT0 GL_DIFFUSE float-array{ 1.0 1.0 1.0 1.0 } underlying>> glLightfv
+ GL_LIGHT0 GL_SPECULAR float-array{ 1.0 1.0 1.0 1.0 } underlying>> glLightfv ;
+
+: player-view ( player -- )
+ [ location>> ]
+ [ [ location>> ] [ forward>> ] bi v+ ]
+ [ up>> ] tri gl-look-at ;
+
+: draw-jamshred ( jamshred width height -- )
+ init-graphics jamshred-player [ player-view ] [ draw-tunnel ] bi ;
+
--- /dev/null
+! Copyright (C) 2007, 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays calendar jamshred.game jamshred.gl jamshred.player jamshred.log kernel math math.constants math.geometry.rect math.vectors namespaces sequences threads ui ui.backend ui.gadgets ui.gadgets.worlds ui.gestures ui.render ;
+IN: jamshred
+
+TUPLE: jamshred-gadget < gadget { jamshred jamshred } last-hand-loc ;
+
+: <jamshred-gadget> ( jamshred -- gadget )
+ jamshred-gadget new-gadget swap >>jamshred ;
+
+: default-width ( -- x ) 800 ;
+: default-height ( -- y ) 600 ;
+
+M: jamshred-gadget pref-dim*
+ drop default-width default-height 2array ;
+
+M: jamshred-gadget draw-gadget* ( gadget -- )
+ [ jamshred>> ] [ rect-dim first2 draw-jamshred ] bi ;
+
+: jamshred-loop ( gadget -- )
+ dup jamshred>> quit>> [
+ drop
+ ] [
+ [ jamshred>> jamshred-update ]
+ [ relayout-1 ]
+ [ 10 milliseconds sleep yield jamshred-loop ] tri
+ ] if ;
+
+: fullscreen ( gadget -- )
+ find-world t swap set-fullscreen* ;
+
+: no-fullscreen ( gadget -- )
+ find-world f swap set-fullscreen* ;
+
+: toggle-fullscreen ( world -- )
+ [ fullscreen? not ] keep set-fullscreen* ;
+
+M: jamshred-gadget graft* ( gadget -- )
+ [ jamshred-loop ] curry in-thread ;
+
+M: jamshred-gadget ungraft* ( gadget -- )
+ jamshred>> t swap (>>quit) ;
+
+: jamshred-restart ( jamshred-gadget -- )
+ <jamshred> >>jamshred drop ;
+
+: pix>radians ( n m -- theta )
+ / pi 4 * * ; ! 2 / / pi 2 * * ;
+
+: x>radians ( x gadget -- theta )
+ #! translate motion of x pixels to an angle
+ rect-dim first pix>radians neg ;
+
+: y>radians ( y gadget -- theta )
+ #! translate motion of y pixels to an angle
+ rect-dim second pix>radians ;
+
+: (handle-mouse-motion) ( jamshred-gadget mouse-motion -- )
+ over jamshred>> >r
+ [ first swap x>radians ] 2keep second swap y>radians
+ r> mouse-moved ;
+
+: handle-mouse-motion ( jamshred-gadget -- )
+ hand-loc get [
+ over last-hand-loc>> [
+ v- (handle-mouse-motion)
+ ] [ 2drop ] if*
+ ] 2keep >>last-hand-loc drop ;
+
+: handle-mouse-scroll ( jamshred-gadget -- )
+ jamshred>> scroll-direction get
+ [ first mouse-scroll-x ]
+ [ second mouse-scroll-y ] 2bi ;
+
+: quit ( gadget -- )
+ [ no-fullscreen ] [ close-window ] bi ;
+
+jamshred-gadget H{
+ { T{ key-down f f "r" } [ jamshred-restart ] }
+ { T{ key-down f f " " } [ jamshred>> toggle-running ] }
+ { T{ key-down f f "f" } [ find-world toggle-fullscreen ] }
+ { T{ key-down f f "UP" } [ jamshred>> jamshred-player 1 swap change-player-speed ] }
+ { T{ key-down f f "DOWN" } [ jamshred>> jamshred-player -1 swap change-player-speed ] }
+ { T{ key-down f f "LEFT" } [ jamshred>> 1 jamshred-roll ] }
+ { T{ key-down f f "RIGHT" } [ jamshred>> -1 jamshred-roll ] }
+ { T{ key-down f f "q" } [ quit ] }
+ { T{ motion } [ handle-mouse-motion ] }
+ { T{ mouse-scroll } [ handle-mouse-scroll ] }
+} set-gestures
+
+: jamshred-window ( -- gadget )
+ [ <jamshred> <jamshred-gadget> dup "Jamshred" open-window ] with-ui ;
+
+MAIN: jamshred-window
--- /dev/null
+USING: kernel logging ;
+IN: jamshred.log
+
+LOG: (jamshred-log) DEBUG
+
+: with-jamshred-log ( quot -- )
+ "jamshred" swap with-logging ;
+
+: jamshred-log ( message -- )
+ [ (jamshred-log) ] with-jamshred-log ; ! ugly...
--- /dev/null
+Alex Chapman
--- /dev/null
+USING: jamshred.oint tools.test ;
+IN: jamshred.oint-tests
+
+[ { 0 -1 -1 } ] [ { 0 1 -1 } { 0 -1 0 } reflect ] unit-test
+[ { 0 1 0 } ] [ { 1 1 0 } { 1 0 0 } proj-perp ] unit-test
+[ { 1 0 0 } ] [ { 1 1 0 } { 0 1 0 } proj-perp ] unit-test
+[ { 1/2 -1/2 0 } ] [ { 1 0 0 } { 1 1 0 } proj-perp ] unit-test
+[ { -1/2 1/2 0 } ] [ { 0 1 0 } { 1 1 0 } proj-perp ] unit-test
--- /dev/null
+! Copyright (C) 2007, 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays float-arrays kernel locals math math.constants math.functions math.matrices math.vectors math.quaternions random sequences ;
+IN: jamshred.oint
+
+! An oint is a point with three linearly independent unit vectors
+! given relative to that point. In jamshred a player's location and
+! direction are given by the player's oint. Similarly, a tunnel
+! segment's location and orientation are given by an oint.
+
+TUPLE: oint location forward up left ;
+C: <oint> oint
+
+: rotation-quaternion ( theta axis -- quaternion )
+ swap 2 / dup cos swap sin rot n*v first3 rect> >r rect> r> 2array ;
+
+: rotate-vector ( q qrecip v -- v )
+ v>q swap q* q* q>v ;
+
+: rotate-oint ( oint theta axis -- )
+ rotation-quaternion dup qrecip pick
+ [ forward>> rotate-vector >>forward ]
+ [ up>> rotate-vector >>up ]
+ [ left>> rotate-vector >>left ] 3tri drop ;
+
+: left-pivot ( oint theta -- )
+ over left>> rotate-oint ;
+
+: up-pivot ( oint theta -- )
+ over up>> rotate-oint ;
+
+: forward-pivot ( oint theta -- )
+ over forward>> rotate-oint ;
+
+: random-float+- ( n -- m )
+ #! find a random float between -n/2 and n/2
+ dup 10000 * >fixnum random 10000 / swap 2 / - ;
+
+: random-turn ( oint theta -- )
+ 2 / 2dup random-float+- left-pivot random-float+- up-pivot ;
+
+: location+ ( v oint -- )
+ [ location>> v+ ] [ (>>location) ] bi ;
+
+: go-forward ( distance oint -- )
+ [ forward>> n*v ] [ location+ ] bi ;
+
+: distance-vector ( oint oint -- vector )
+ [ location>> ] bi@ swap v- ;
+
+: distance ( oint oint -- distance )
+ distance-vector norm ;
+
+: scalar-projection ( v1 v2 -- n )
+ #! the scalar projection of v1 onto v2
+ tuck v. swap norm / ;
+
+: proj-perp ( u v -- w )
+ dupd proj v- ;
+
+: perpendicular-distance ( oint oint -- distance )
+ tuck distance-vector swap 2dup left>> scalar-projection abs
+ -rot up>> scalar-projection abs + ;
+
+:: reflect ( v n -- v' )
+ #! bounce v on a surface with normal n
+ v v n v. n n v. / 2 * n n*v v- ;
+
+: half-way ( p1 p2 -- p3 )
+ over v- 2 v/n v+ ;
+
+: half-way-between-oints ( o1 o2 -- p )
+ [ location>> ] bi@ half-way ;
--- /dev/null
+Alex Chapman
--- /dev/null
+! Copyright (C) 2007, 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors colors combinators float-arrays jamshred.log jamshred.oint jamshred.sound jamshred.tunnel kernel locals math math.constants math.order math.ranges math.vectors math.matrices sequences shuffle strings system ;
+IN: jamshred.player
+
+TUPLE: player < oint
+ { name string }
+ { sounds sounds }
+ tunnel
+ nearest-segment
+ { last-move integer }
+ { speed float } ;
+
+! speeds are in GL units / second
+: default-speed ( -- speed ) 1.0 ;
+: max-speed ( -- speed ) 30.0 ;
+
+: <player> ( name sounds -- player )
+ [ F{ 0 0 5 } F{ 0 0 -1 } F{ 0 1 0 } F{ -1 0 0 } ] 2dip
+ f f 0 default-speed player boa ;
+
+: turn-player ( player x-radians y-radians -- )
+ >r over r> left-pivot up-pivot ;
+
+: roll-player ( player z-radians -- )
+ forward-pivot ;
+
+: to-tunnel-start ( player -- )
+ [ tunnel>> first dup location>> ]
+ [ tuck (>>location) (>>nearest-segment) ] bi ;
+
+: play-in-tunnel ( player segments -- )
+ >>tunnel to-tunnel-start ;
+
+: update-nearest-segment ( player -- )
+ [ tunnel>> ] [ dup nearest-segment>> nearest-segment ]
+ [ (>>nearest-segment) ] tri ;
+
+: update-time ( player -- seconds-passed )
+ millis swap [ last-move>> - 1000 / ] [ (>>last-move) ] 2bi ;
+
+: moved ( player -- ) millis swap (>>last-move) ;
+
+: speed-range ( -- range )
+ max-speed [0,b] ;
+
+: change-player-speed ( inc player -- )
+ [ + speed-range clamp-to-range ] change-speed drop ;
+
+: multiply-player-speed ( n player -- )
+ [ * speed-range clamp-to-range ] change-speed drop ;
+
+: distance-to-move ( seconds-passed player -- distance )
+ speed>> * ;
+
+: bounce ( d-left player -- d-left' player )
+ {
+ [ dup nearest-segment>> bounce-off-wall ]
+ [ sounds>> bang ]
+ [ 3/4 swap multiply-player-speed ]
+ [ ]
+ } cleave ;
+
+:: (distance) ( heading player -- current next location heading )
+ player nearest-segment>>
+ player [ tunnel>> ] [ nearest-segment>> ] bi heading heading-segment
+ player location>> heading ;
+
+: distance-to-heading-segment ( heading player -- distance )
+ (distance) distance-to-next-segment ;
+
+: distance-to-heading-segment-area ( heading player -- distance )
+ (distance) distance-to-next-segment-area ;
+
+: distance-to-collision ( player -- distance )
+ dup nearest-segment>> (distance-to-collision) ;
+
+: almost-to-collision ( player -- distance )
+ distance-to-collision 0.1 - dup 0 < [ drop 0 ] when ;
+
+: from ( player -- radius distance-from-centre )
+ [ nearest-segment>> dup radius>> swap ] [ location>> ] bi
+ distance-from-centre ;
+
+: distance-from-wall ( player -- distance ) from - ;
+: fraction-from-centre ( player -- fraction ) from swap / ;
+: fraction-from-wall ( player -- fraction )
+ fraction-from-centre 1 swap - ;
+
+: update-nearest-segment2 ( heading player -- )
+ 2dup distance-to-heading-segment-area 0 <= [
+ [ tunnel>> ] [ nearest-segment>> rot heading-segment ]
+ [ (>>nearest-segment) ] tri
+ ] [
+ 2drop
+ ] if ;
+
+:: move-player-on-heading ( d-left player distance heading -- d-left' player )
+ [let* | d-to-move [ d-left distance min ]
+ move-v [ d-to-move heading n*v ] |
+ move-v player location+
+ heading player update-nearest-segment2
+ d-left d-to-move - player ] ;
+
+: distance-to-move-freely ( player -- distance )
+ [ almost-to-collision ]
+ [ [ forward>> ] keep distance-to-heading-segment-area ] bi min ;
+
+: ?move-player-freely ( d-left player -- d-left' player )
+ over 0 > [
+ ! must make sure we are moving a significant distance, otherwise
+ ! we can recurse endlessly due to floating-point imprecision.
+ ! (at least I /think/ that's what causes it...)
+ dup distance-to-move-freely dup 0.1 > [
+ over forward>> move-player-on-heading ?move-player-freely
+ ] [ drop ] if
+ ] when ;
+
+: drag-heading ( player -- heading )
+ [ forward>> ] [ nearest-segment>> forward>> proj ] bi ;
+
+: drag-player ( d-left player -- d-left' player )
+ dup [ [ drag-heading ] keep distance-to-heading-segment-area ]
+ [ drag-heading move-player-on-heading ] bi ;
+
+: (move-player) ( d-left player -- d-left' player )
+ ?move-player-freely over 0 > [
+ ! bounce
+ drag-player
+ (move-player)
+ ] when ;
+
+: move-player ( player -- )
+ [ update-time ] [ distance-to-move ] [ (move-player) 2drop ] tri ;
+
+: update-player ( player -- )
+ [ move-player ] [ nearest-segment>> white swap (>>color) ] bi ;
--- /dev/null
+! Copyright (C) 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors io.files kernel openal sequences ;
+IN: jamshred.sound
+
+TUPLE: sounds bang ;
+
+: assign-sound ( source wav-path -- )
+ resource-path create-buffer-from-wav AL_BUFFER swap set-source-param ;
+
+: <sounds> ( -- sounds )
+ init-openal 1 gen-sources first sounds boa
+ dup bang>> "extra/jamshred/sound/bang.wav" assign-sound ;
+
+: bang ( sounds -- ) bang>> source-play check-error ;
--- /dev/null
+A simple 3d tunnel racing game
--- /dev/null
+applications
+games
--- /dev/null
+Alex Chapman
--- /dev/null
+! Copyright (C) 2007, 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays float-arrays jamshred.oint jamshred.tunnel kernel math.vectors sequences tools.test ;
+IN: jamshred.tunnel.tests
+
+[ 0 ] [ T{ segment f { 0 0 0 } f f f 0 }
+ T{ segment f { 1 1 1 } f f f 1 }
+ T{ oint f { 0 0 0.25 } }
+ nearer-segment number>> ] unit-test
+
+[ 0 ] [ T{ oint f { 0 0 0 } } <straight-tunnel> find-nearest-segment number>> ] unit-test
+[ 1 ] [ T{ oint f { 0 0 -1 } } <straight-tunnel> find-nearest-segment number>> ] unit-test
+[ 2 ] [ T{ oint f { 0 0.1 -2.1 } } <straight-tunnel> find-nearest-segment number>> ] unit-test
+
+[ 3 ] [ <straight-tunnel> T{ oint f { 0 0 -3.25 } } 0 nearest-segment-forward number>> ] unit-test
+
+[ F{ 0 0 0 } ] [ <straight-tunnel> T{ oint f { 0 0 -0.25 } } over first nearest-segment location>> ] unit-test
+
+: test-segment-oint ( -- oint )
+ { 0 0 0 } { 0 0 -1 } { 0 1 0 } { -1 0 0 } <oint> ;
+
+[ { -1 0 0 } ] [ test-segment-oint { 1 0 0 } vector-to-centre ] unit-test
+[ { 1 0 0 } ] [ test-segment-oint { -1 0 0 } vector-to-centre ] unit-test
+[ { 0 -1 0 } ] [ test-segment-oint { 0 1 0 } vector-to-centre ] unit-test
+[ { 0 1 0 } ] [ test-segment-oint { 0 -1 0 } vector-to-centre ] unit-test
+[ { -1 0 0 } ] [ test-segment-oint { 1 0 -1 } vector-to-centre ] unit-test
+[ { 1 0 0 } ] [ test-segment-oint { -1 0 -1 } vector-to-centre ] unit-test
+[ { 0 -1 0 } ] [ test-segment-oint { 0 1 -1 } vector-to-centre ] unit-test
+[ { 0 1 0 } ] [ test-segment-oint { 0 -1 -1 } vector-to-centre ] unit-test
+
+: simplest-straight-ahead ( -- oint segment )
+ { 0 0 0 } { 0 0 -1 } { 0 1 0 } { -1 0 0 } <oint>
+ initial-segment ;
+
+[ { 0.0 0.0 0.0 } ] [ simplest-straight-ahead sideways-heading ] unit-test
+[ { 0.0 0.0 0.0 } ] [ simplest-straight-ahead sideways-relative-location ] unit-test
+
+: simple-collision-up ( -- oint segment )
+ { 0 0 0 } { 0 1 0 } { 0 0 1 } { -1 0 0 } <oint>
+ initial-segment ;
+
+[ { 0.0 1.0 0.0 } ] [ simple-collision-up sideways-heading ] unit-test
+[ { 0.0 0.0 0.0 } ] [ simple-collision-up sideways-relative-location ] unit-test
+[ { 0.0 1.0 0.0 } ]
+[ simple-collision-up collision-vector 0 0 0 3array v+ ] unit-test
--- /dev/null
+! Copyright (C) 2007, 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays colors combinators float-arrays kernel
+locals math math.constants math.matrices math.order math.ranges
+math.vectors math.quadratic random sequences vectors jamshred.oint ;
+IN: jamshred.tunnel
+
+: n-segments ( -- n ) 5000 ; inline
+
+TUPLE: segment < oint number color radius ;
+C: <segment> segment
+
+: segment-number++ ( segment -- )
+ [ number>> 1+ ] keep (>>number) ;
+
+: random-color ( -- color )
+ { 100 100 100 } [ random 100 / >float ] map first3 1.0 <rgba> ;
+
+: tunnel-segment-distance ( -- n ) 0.4 ;
+: random-rotation-angle ( -- theta ) pi 20 / ;
+
+: random-segment ( previous-segment -- segment )
+ clone dup random-rotation-angle random-turn
+ tunnel-segment-distance over go-forward
+ random-color >>color dup segment-number++ ;
+
+: (random-segments) ( segments n -- segments )
+ dup 0 > [
+ >r dup peek random-segment over push r> 1- (random-segments)
+ ] [ drop ] if ;
+
+: default-segment-radius ( -- r ) 1 ;
+
+: initial-segment ( -- segment )
+ F{ 0 0 0 } F{ 0 0 -1 } F{ 0 1 0 } F{ -1 0 0 }
+ 0 random-color default-segment-radius <segment> ;
+
+: random-segments ( n -- segments )
+ initial-segment 1vector swap (random-segments) ;
+
+: simple-segment ( n -- segment )
+ [ F{ 0 0 -1 } n*v F{ 0 0 -1 } F{ 0 1 0 } F{ -1 0 0 } ] keep
+ random-color default-segment-radius <segment> ;
+
+: simple-segments ( n -- segments )
+ [ simple-segment ] map ;
+
+: <random-tunnel> ( -- segments )
+ n-segments random-segments ;
+
+: <straight-tunnel> ( -- segments )
+ n-segments simple-segments ;
+
+: sub-tunnel ( from to segments -- segments )
+ #! return segments between from and to, after clamping from and to to
+ #! valid values
+ [ sequence-index-range [ clamp-to-range ] curry bi@ ] keep <slice> ;
+
+: nearer-segment ( segment segment oint -- segment )
+ #! return whichever of the two segments is nearer to the oint
+ >r 2dup r> tuck distance >r distance r> < -rot ? ;
+
+: (find-nearest-segment) ( nearest next oint -- nearest ? )
+ #! find the nearest of 'next' and 'nearest' to 'oint', and return
+ #! t if the nearest hasn't changed
+ pick >r nearer-segment dup r> = ;
+
+: find-nearest-segment ( oint segments -- segment )
+ dup first swap rest-slice rot [ (find-nearest-segment) ] curry
+ find 2drop ;
+
+: nearest-segment-forward ( segments oint start -- segment )
+ rot dup length swap <slice> find-nearest-segment ;
+
+: nearest-segment-backward ( segments oint start -- segment )
+ swapd 1+ 0 spin <slice> <reversed> find-nearest-segment ;
+
+: nearest-segment ( segments oint start-segment -- segment )
+ #! find the segment nearest to 'oint', and return it.
+ #! start looking at segment 'start-segment'
+ number>> over >r
+ [ nearest-segment-forward ] 3keep
+ nearest-segment-backward r> nearer-segment ;
+
+: get-segment ( segments n -- segment )
+ over sequence-index-range clamp-to-range swap nth ;
+
+: next-segment ( segments current-segment -- segment )
+ number>> 1+ get-segment ;
+
+: previous-segment ( segments current-segment -- segment )
+ number>> 1- get-segment ;
+
+: heading-segment ( segments current-segment heading -- segment )
+ #! the next segment on the given heading
+ over forward>> v. 0 <=> {
+ { +gt+ [ next-segment ] }
+ { +lt+ [ previous-segment ] }
+ { +eq+ [ nip ] } ! current segment
+ } case ;
+
+:: distance-to-next-segment ( current next location heading -- distance )
+ [let | cf [ current forward>> ] |
+ cf next location>> v. cf location v. - cf heading v. / ] ;
+
+:: distance-to-next-segment-area ( current next location heading -- distance )
+ [let | cf [ current forward>> ]
+ h [ next current half-way-between-oints ] |
+ cf h v. cf location v. - cf heading v. / ] ;
+
+: vector-to-centre ( seg loc -- v )
+ over location>> swap v- swap forward>> proj-perp ;
+
+: distance-from-centre ( seg loc -- distance )
+ vector-to-centre norm ;
+
+: wall-normal ( seg oint -- n )
+ location>> vector-to-centre normalize ;
+
+: distant ( -- n ) 1000 ;
+
+: max-real ( a b -- c )
+ #! sometimes collision-coefficient yields complex roots, so we ignore these (hack)
+ dup real? [
+ over real? [ max ] [ nip ] if
+ ] [
+ drop dup real? [ drop distant ] unless
+ ] if ;
+
+:: collision-coefficient ( v w r -- c )
+ v norm 0 = [
+ distant
+ ] [
+ [let* | a [ v dup v. ]
+ b [ v w v. 2 * ]
+ c [ w dup v. r sq - ] |
+ c b a quadratic max-real ]
+ ] if ;
+
+: sideways-heading ( oint segment -- v )
+ [ forward>> ] bi@ proj-perp ;
+
+: sideways-relative-location ( oint segment -- loc )
+ [ [ location>> ] bi@ v- ] keep forward>> proj-perp ;
+
+: (distance-to-collision) ( oint segment -- distance )
+ [ sideways-heading ] [ sideways-relative-location ]
+ [ nip radius>> ] 2tri collision-coefficient ;
+
+: collision-vector ( oint segment -- v )
+ dupd (distance-to-collision) swap forward>> n*v ;
+
+: bounce-forward ( segment oint -- )
+ [ wall-normal ] [ forward>> swap reflect ] [ (>>forward) ] tri ;
+
+: bounce-left ( segment oint -- )
+ #! must be done after forward
+ [ forward>> vneg ] dip [ left>> swap reflect ]
+ [ forward>> proj-perp normalize ] [ (>>left) ] tri ;
+
+: bounce-up ( segment oint -- )
+ #! must be done after forward and left!
+ nip [ forward>> ] [ left>> cross ] [ (>>up) ] tri ;
+
+: bounce-off-wall ( oint segment -- )
+ swap [ bounce-forward ] [ bounce-left ] [ bounce-up ] 2tri ;
+
+++ /dev/null
-Doug Coleman
+++ /dev/null
-USING: io lint kernel math tools.test ;
-IN: lint.tests
-
-! Don't write code like this
-: lint1
- [ "hi" print ] [ ] if ; ! when
-
-[ { [ [ ] if ] } ] [ \ lint1 lint ] unit-test
-
-: lint2
- 1 + ; ! 1+
-[ { [ 1 + ] } ] [ \ lint2 lint ] unit-test
-
-: lint3
- dup -rot ; ! tuck
-
-[ { [ dup -rot ] } ] [ \ lint3 lint ] unit-test
-
+++ /dev/null
-! Copyright (C) 2007 Doug Coleman.
-! See http://factorcode.org/license.txt for BSD license.
-USING: accessors alien alien.accessors arrays assocs
-combinators.lib io kernel macros math namespaces prettyprint
-quotations sequences vectors vocabs words html.elements sets
-slots.private combinators.short-circuit math.order hashtables
-sequences.deep ;
-IN: lint
-
-SYMBOL: def-hash
-SYMBOL: def-hash-keys
-
-: set-hash-vector ( val key hash -- )
- 2dup at -rot [ ?push ] 2dip set-at ;
-
-: add-word-def ( word quot -- )
- dup callable? [
- def-hash get-global set-hash-vector
- ] [
- 2drop
- ] if ;
-
-: more-defs ( -- )
- {
- { [ swap >r swap r> ] -rot }
- { [ swap swapd ] -rot }
- { [ >r swap r> swap ] rot }
- { [ swapd swap ] rot }
- { [ dup swap ] over }
- { [ dup -rot ] tuck }
- { [ >r swap r> ] swapd }
- { [ nip nip ] 2nip }
- { [ drop drop ] 2drop }
- { [ drop drop drop ] 3drop }
- { [ 0 = ] zero? }
- { [ pop drop ] pop* }
- { [ [ ] if ] when }
- { [ f = not ] >boolean }
- } [ first2 swap add-word-def ] each ;
-
-: accessor-words ( -- seq )
-{
- alien-signed-1 alien-signed-2 alien-signed-4 alien-signed-8
- alien-unsigned-1 alien-unsigned-2 alien-unsigned-4 alien-unsigned-8
- <displaced-alien> alien-unsigned-cell set-alien-signed-cell
- set-alien-unsigned-1 set-alien-signed-1 set-alien-unsigned-2
- set-alien-signed-2 set-alien-unsigned-4 set-alien-signed-4
- set-alien-unsigned-8 set-alien-signed-8
- alien-cell alien-signed-cell set-alien-cell set-alien-unsigned-cell
- set-alien-float alien-float
-} ;
-
-: trivial-defs
- {
- [ get ] [ t ] [ { } ] [ . ] [ drop f ]
- [ drop ] [ f ] [ first ] [ second ] [ third ] [ fourth ]
- [ ">" write-html ] [ "/>" write-html ]
- } ;
-
-H{ } clone def-hash set-global
-all-words [ dup def>> add-word-def ] each
-more-defs
-
-! Remove empty word defs
-def-hash get-global [
- drop empty? not
-] assoc-filter
-
-! Remove constants [ 1 ]
-[
- drop { [ length 1 = ] [ first number? ] } 1&& not
-] assoc-filter
-
-! Remove set-alien-cell, etc.
-[
- drop [ accessor-words diff ] keep [ length ] bi@ =
-] assoc-filter
-
-! Remove trivial defs
-[
- drop trivial-defs member? not
-] assoc-filter
-
-[
- drop {
- [ [ wrapper? ] deep-contains? ]
- [ [ hashtable? ] deep-contains? ]
- } 1|| not
-] assoc-filter
-
-! Remove n m shift defs
-[
- drop dup length 3 = [
- dup first2 [ number? ] both?
- swap third \ shift = and not
- ] [ drop t ] if
-] assoc-filter
-
-! Remove [ n slot ]
-[
- drop dup length 2 = [
- first2 \ slot = swap number? and not
- ] [ drop t ] if
-] assoc-filter def-hash set-global
-
-: find-duplicates ( -- seq )
- def-hash get-global [
- nip length 1 >
- ] assoc-filter ;
-
-def-hash get-global keys def-hash-keys set-global
-
-GENERIC: lint ( obj -- seq )
-
-M: object lint ( obj -- seq )
- drop f ;
-
-: subseq/member? ( subseq/member seq -- ? )
- { [ start ] [ member? ] } 2|| ;
-
-M: callable lint ( quot -- seq )
- def-hash-keys get [
- swap subseq/member?
- ] with filter ;
-
-M: word lint ( word -- seq )
- def>> dup callable? [ lint ] [ drop f ] if ;
-
-: word-path. ( word -- )
- [ vocabulary>> ":" ] keep unparse 3append write nl ;
-
-: (lint.) ( pair -- )
- first2 >r word-path. r> [
- bl bl bl bl
- dup .
- "-----------------------------------" print
- def-hash get at [ bl bl bl bl word-path. ] each
- nl
- ] each nl nl ;
-
-: lint. ( alist -- )
- [ (lint.) ] each ;
-
-
-GENERIC: run-lint ( obj -- obj )
-
-: (trim-self) ( val key -- obj ? )
- def-hash get-global at* [
- dupd remove empty? not
- ] [
- drop f
- ] if ;
-
-: trim-self ( seq -- newseq )
- [ [ (trim-self) ] filter ] assoc-map ;
-
-: filter-symbols ( alist -- alist )
- [
- nip first dup def-hash get at
- [ first ] bi@ literalize = not
- ] assoc-filter ;
-
-M: sequence run-lint ( seq -- seq )
- [
- global [ dup . flush ] bind
- dup lint
- ] { } map>assoc
- trim-self
- [ second empty? not ] filter
- filter-symbols ;
-
-M: word run-lint ( word -- seq )
- 1array run-lint ;
-
-: lint-all ( -- seq )
- all-words run-lint dup lint. ;
-
-: lint-vocab ( vocab -- seq )
- words run-lint dup lint. ;
-
-: lint-word ( word -- seq )
- 1array run-lint dup lint. ;
+++ /dev/null
-Finds potential mistakes in code
--- /dev/null
+James Cash
--- /dev/null
+IN: lisp
+USING: help.markup help.syntax ;
+HELP: <LISP
+{ $description "parsing word which converts the lisp code between <LISP and LISP> into factor quotations and calls it" }
+{ $see-also lisp-string>factor } ;
+
+HELP: lisp-string>factor
+{ $values { "str" "a string of lisp code" } { "quot" "the quotation the lisp compiles into" } }
+{ $description "Turns a string of lisp into a factor quotation" } ;
+
+ARTICLE: "lisp" "Lisp in Factor"
+"This is a simple implementation of a Lisp dialect, which somewhat resembles Scheme." $nl
+"It works in two main stages: "
+{ $list
+ { "Parse (via " { $vocab-link "lisp.parser" } " the Lisp code into a "
+ { $snippet "s-exp" } " tuple." }
+ { "Transform the " { $snippet "s-exp" } " into a Factor quotation, via " { $link convert-form } }
+}
+
+{ $subsection "lisp.parser" } ;
+
+ABOUT: "lisp"
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2008 James Cash
+! See http://factorcode.org/license.txt for BSD license.
+USING: lisp lisp.parser tools.test sequences math kernel parser arrays lists
+quotations ;
+
+IN: lisp.test
+
+[
+ define-lisp-builtins
+
+ { 5 } [
+ "(+ 2 3)" lisp-eval
+ ] unit-test
+
+ { 8.3 } [
+ "(- 10.4 2.1)" lisp-eval
+ ] unit-test
+
+ { 3 } [
+ "((lambda (x y) (+ x y)) 1 2)" lisp-eval
+ ] unit-test
+
+ { 42 } [
+ "((lambda (x y z) (+ x (- y z))) 40 3 1)" lisp-eval
+ ] unit-test
+
+ { "b" } [
+ "(cond (#f \"a\") (#t \"b\"))" lisp-eval
+ ] unit-test
+
+ { "b" } [
+ "(cond ((< 1 2) \"b\") (#t \"a\"))" lisp-eval
+ ] unit-test
+
+ { +nil+ } [
+ "(list)" lisp-eval
+ ] unit-test
+
+ { { 1 2 3 4 5 } } [
+ "(list 1 2 3 4 5)" lisp-eval list>seq
+ ] unit-test
+
+ { { 1 2 { 3 { 4 } 5 } } } [
+ "(list 1 2 (list 3 (list 4) 5))" lisp-eval cons>seq
+ ] unit-test
+
+ { 5 } [
+ "(begin (+ 1 4))" lisp-eval
+ ] unit-test
+
+ { 5 } [
+ "(begin (+ 5 6) (+ 1 4))" lisp-eval
+ ] unit-test
+
+ { t } [
+ T{ lisp-symbol f "if" } lisp-macro?
+ ] unit-test
+
+ { 1 } [
+ "(if #t 1 2)" lisp-eval
+ ] unit-test
+
+ { 3 } [
+ "((lambda (x) (if x (+ 1 2) (- 3 5))) #t)" lisp-eval
+ ] unit-test
+
+ { { 5 4 3 } } [
+ "((lambda (x &rest xs) (cons x xs)) 5 4 3)" lisp-eval cons>seq
+ ] unit-test
+
+ { { 5 } } [
+ "((lambda (x &rest xs) (cons x xs)) 5)" lisp-eval cons>seq
+ ] unit-test
+
+ { { 1 2 3 4 } } [
+ "((lambda (&rest xs) xs) 1 2 3 4)" lisp-eval cons>seq
+ ] unit-test
+
+ { 10 } [
+ <LISP (begin (+ 1 2) (+ 9 1)) LISP>
+ ] unit-test
+
+ { 4 } [
+ <LISP ((lambda (x y) (if x (+ 1 y) (+ 2 y))) #t 3) LISP>
+ ] unit-test
+
+ { { 3 3 4 } } [
+ <LISP (defun foo (x y &rest z)
+ (cons (+ x y) z))
+ (foo 1 2 3 4)
+ LISP> cons>seq
+ ] unit-test
+
+] with-interactive-vocabs
--- /dev/null
+! Copyright (C) 2008 James Cash
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel peg sequences arrays strings
+namespaces combinators math locals locals.private locals.backend accessors
+vectors syntax lisp.parser assocs parser words
+quotations fry lists summary combinators.short-circuit continuations multiline ;
+IN: lisp
+
+DEFER: convert-form
+DEFER: funcall
+DEFER: lookup-var
+DEFER: lookup-macro
+DEFER: lisp-macro?
+DEFER: lisp-var?
+DEFER: define-lisp-macro
+
+! Functions to convert s-exps to quotations
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+: convert-body ( cons -- quot )
+ [ ] [ convert-form compose ] foldl ; inline
+
+: convert-cond ( cons -- quot )
+ cdr [ 2car [ convert-form ] bi@ 2array ]
+ { } lmap-as '[ _ cond ] ;
+
+: convert-general-form ( cons -- quot )
+ uncons [ convert-body ] [ convert-form ] bi* '[ _ @ funcall ] ;
+
+! words for convert-lambda
+<PRIVATE
+: localize-body ( assoc body -- newbody )
+ {
+ { [ dup list? ] [ [ lisp-symbol? ] rot '[ [ name>> _ at ] [ ] bi or ] traverse ] }
+ { [ dup lisp-symbol? ] [ name>> swap at ] }
+ [ nip ]
+ } cond ;
+
+: localize-lambda ( body vars -- newvars newbody )
+ swap [ make-locals dup push-locals ] dip
+ dupd [ localize-body convert-form ] with lmap>array
+ >quotation swap pop-locals ;
+
+: split-lambda ( cons -- body-cons vars-seq )
+ cdr uncons [ name>> ] lmap>array ; inline
+
+: rest-lambda ( body vars -- quot )
+ "&rest" swap [ remove ] [ index ] 2bi
+ [ localize-lambda <lambda> lambda-rewrite call ] dip
+ swap '[ _ cut '[ @ _ seq>list ] call _ call call ] 1quotation ;
+
+: normal-lambda ( body vars -- quot )
+ localize-lambda <lambda> lambda-rewrite '[ @ compose call call ] 1quotation ;
+PRIVATE>
+
+: convert-lambda ( cons -- quot )
+ split-lambda "&rest" over member? [ rest-lambda ] [ normal-lambda ] if ;
+
+: convert-quoted ( cons -- quot )
+ cadr 1quotation ;
+
+: convert-defmacro ( cons -- quot )
+ cdr [ convert-lambda ] [ car name>> ] bi define-lisp-macro [ ] ;
+
+: macro-expand ( cons -- quot )
+ uncons [ list>seq >quotation ] [ lookup-macro ] bi* call call ;
+
+: expand-macros ( cons -- cons )
+ dup list? [ [ expand-macros ] lmap dup car lisp-macro? [ macro-expand expand-macros ] when ] when ;
+
+: convert-begin ( cons -- quot )
+ cdr [ convert-form ] [ ] lmap-as [ 1 tail* ] [ but-last ] bi
+ [ '[ { } _ with-datastack drop ] ] map prepend '[ _ [ call ] each ] ;
+
+: form-dispatch ( cons lisp-symbol -- quot )
+ name>>
+ { { "lambda" [ convert-lambda ] }
+ { "defmacro" [ convert-defmacro ] }
+ { "quote" [ convert-quoted ] }
+ { "cond" [ convert-cond ] }
+ { "begin" [ convert-begin ] }
+ [ drop convert-general-form ]
+ } case ;
+
+: convert-list-form ( cons -- quot )
+ dup car
+ {
+ { [ dup lisp-symbol? ] [ form-dispatch ] }
+ [ drop convert-general-form ]
+ } cond ;
+
+: convert-form ( lisp-form -- quot )
+ {
+ { [ dup cons? ] [ convert-list-form ] }
+ { [ dup lisp-var? ] [ lookup-var 1quotation ] }
+ { [ dup lisp-symbol? ] [ '[ _ lookup-var ] ] }
+ [ 1quotation ]
+ } cond ;
+
+: lisp-string>factor ( str -- quot )
+ lisp-expr expand-macros convert-form ;
+
+: lisp-eval ( str -- * )
+ lisp-string>factor call ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+SYMBOL: lisp-env
+SYMBOL: macro-env
+
+ERROR: no-such-var variable-name ;
+M: no-such-var summary drop "No such variable" ;
+
+: init-env ( -- )
+ H{ } clone lisp-env set
+ H{ } clone macro-env set ;
+
+: lisp-define ( quot name -- )
+ lisp-env get set-at ;
+
+: define-lisp-var ( lisp-symbol body -- )
+ swap name>> lisp-define ;
+
+: lisp-get ( name -- word )
+ lisp-env get at ;
+
+: lookup-var ( lisp-symbol -- quot )
+ [ name>> ] [ lisp-var? ] bi [ lisp-get ] [ no-such-var ] if ;
+
+: lisp-var? ( lisp-symbol -- ? )
+ dup lisp-symbol? [ name>> lisp-env get key? ] [ drop f ] if ;
+
+: funcall ( quot sym -- * )
+ [ 1array [ call ] with-datastack >quotation ] dip curry call ; inline
+
+: define-primitive ( name vocab word -- )
+ swap lookup 1quotation '[ _ compose call ] swap lisp-define ;
+
+: lookup-macro ( lisp-symbol -- lambda )
+ name>> macro-env get at ;
+
+: define-lisp-macro ( quot name -- )
+ macro-env get set-at ;
+
+: lisp-macro? ( car -- ? )
+ dup lisp-symbol? [ name>> macro-env get key? ] [ drop f ] if ;
+
+: define-lisp-builtins ( -- )
+ init-env
+
+ f "#f" lisp-define
+ t "#t" lisp-define
+
+ "+" "math" "+" define-primitive
+ "-" "math" "-" define-primitive
+ "<" "math" "<" define-primitive
+ ">" "math" ">" define-primitive
+
+ "cons" "lists" "cons" define-primitive
+ "car" "lists" "car" define-primitive
+ "cdr" "lists" "cdr" define-primitive
+ "append" "lists" "lappend" define-primitive
+ "nil" "lists" "nil" define-primitive
+ "nil?" "lists" "nil?" define-primitive
+
+ "set" "lisp" "define-lisp-var" define-primitive
+
+ "(set 'list (lambda (&rest xs) xs))" lisp-eval
+ "(defmacro setq (var val) (list 'set (list 'quote var) val))" lisp-eval
+
+ <" (defmacro defun (name vars &rest body)
+ (list 'setq name (cons 'lambda (cons vars body)))) "> lisp-eval
+
+ "(defmacro if (pred tr fl) (list 'cond (list pred tr) (list (quote #t) fl)))" lisp-eval
+ ;
+
+: <LISP
+ "LISP>" parse-multiline-string "(begin " prepend ")" append define-lisp-builtins
+ lisp-string>factor parsed \ call parsed ; parsing
\ No newline at end of file
--- /dev/null
+James Cash
--- /dev/null
+IN: lisp.parser
+USING: help.markup help.syntax ;
+
+ARTICLE: "lisp.parser" "Parsing strings of Lisp"
+"This vocab uses " { $vocab-link "peg.ebnf" } " to turn strings of Lisp into " { $snippet "s-exp" } "s, which are then used by"
+{ $vocab-link "lisp" } " to produce Factor quotations." ;
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2008 James Cash
+! See http://factorcode.org/license.txt for BSD license.
+USING: lisp.parser tools.test peg peg.ebnf lists ;
+
+IN: lisp.parser.tests
+
+{ 1234 } [
+ "1234" "atom" \ lisp-expr rule parse
+] unit-test
+
+{ -42 } [
+ "-42" "atom" \ lisp-expr rule parse
+] unit-test
+
+{ 37/52 } [
+ "37/52" "atom" \ lisp-expr rule parse
+] unit-test
+
+{ 123.98 } [
+ "123.98" "atom" \ lisp-expr rule parse
+] unit-test
+
+{ "" } [
+ "\"\"" "atom" \ lisp-expr rule parse
+] unit-test
+
+{ "aoeu" } [
+ "\"aoeu\"" "atom" \ lisp-expr rule parse
+] unit-test
+
+{ "aoeu\"de" } [
+ "\"aoeu\\\"de\"" "atom" \ lisp-expr rule parse
+] unit-test
+
+{ T{ lisp-symbol f "foobar" } } [
+ "foobar" "atom" \ lisp-expr rule parse
+] unit-test
+
+{ T{ lisp-symbol f "+" } } [
+ "+" "atom" \ lisp-expr rule parse
+] unit-test
+
+{ +nil+ } [
+ "()" lisp-expr
+] unit-test
+
+{ T{
+ cons
+ f
+ T{ lisp-symbol f "foo" }
+ T{
+ cons
+ f
+ 1
+ T{ cons f 2 T{ cons f "aoeu" +nil+ } }
+ } } } [
+ "(foo 1 2 \"aoeu\")" lisp-expr
+] unit-test
+
+{ T{ cons f
+ 1
+ T{ cons f
+ T{ cons f 3 T{ cons f 4 +nil+ } }
+ T{ cons f 2 +nil+ } }
+ }
+} [
+ "(1 (3 4) 2)" lisp-expr
+] unit-test
+
+{ { T{ lisp-symbol { name "quote" } } { 1 2 3 } } } [
+ "'(1 2 3)" lisp-expr cons>seq
+] unit-test
+
+{ { T{ lisp-symbol f "quote" } T{ lisp-symbol f "foo" } } } [
+ "'foo" lisp-expr cons>seq
+] unit-test
+
+{ { 1 2 { T{ lisp-symbol { name "quote" } } { 3 4 } } 5 } } [
+ "(1 2 '(3 4) 5)" lisp-expr cons>seq
+] unit-test
\ No newline at end of file
--- /dev/null
+! Copyright (C) 2008 James Cash
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel peg peg.ebnf math.parser sequences arrays strings
+math fry accessors lists combinators.short-circuit ;
+
+IN: lisp.parser
+
+TUPLE: lisp-symbol name ;
+C: <lisp-symbol> lisp-symbol
+
+EBNF: lisp-expr
+_ = (" " | "\t" | "\n")*
+LPAREN = "("
+RPAREN = ")"
+dquote = '"'
+squote = "'"
+digit = [0-9]
+integer = ("-")? (digit)+ => [[ first2 append string>number ]]
+float = integer "." (digit)* => [[ first3 >string [ number>string ] 2dip 3append string>number ]]
+rational = integer "/" (digit)+ => [[ first3 nip string>number / ]]
+number = float
+ | rational
+ | integer
+id-specials = "!" | "$" | "%" | "&" | "*" | "/" | ":"
+ | "<" | "#" | " =" | ">" | "?" | "^" | "_"
+ | "~" | "+" | "-" | "." | "@"
+letters = [a-zA-Z] => [[ 1array >string ]]
+initials = letters | id-specials
+numbers = [0-9] => [[ 1array >string ]]
+subsequents = initials | numbers
+identifier = initials (subsequents)* => [[ first2 concat append <lisp-symbol> ]]
+escaped = "\" . => [[ second ]]
+string = dquote ( escaped | !(dquote) . )* dquote => [[ second >string ]]
+atom = number
+ | identifier
+ | string
+s-expression = LPAREN (list-item)* RPAREN => [[ second seq>cons ]]
+list-item = _ ( atom | s-expression | quoted ) _ => [[ second ]]
+quoted = squote list-item => [[ second nil cons "quote" <lisp-symbol> swap cons ]]
+expr = list-item
+;EBNF
\ No newline at end of file
--- /dev/null
+EBNF grammar for parsing Lisp
--- /dev/null
+lisp
+parsing
--- /dev/null
+A Lisp interpreter/compiler in Factor
--- /dev/null
+lisp
+languages
--- /dev/null
+Reginald Ford
+Eduardo Cavazos
\ No newline at end of file
--- /dev/null
+USING: help.markup help.syntax math math.functions ;
+IN: math.derivatives
+
+HELP: derivative ( x function -- m )
+{ $values { "x" "a position on the function" } { "function" "a differentiable function" } { "m" number } }
+{ $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 math.derivatives prettyprint ;"
+ "4 [ sq ] derivative >integer ."
+ "8"
+ }
+ { $notes
+ "For applied scientists, you may play with the settings "
+ "in the source file to achieve arbitrary accuracy. "
+ }
+} ;
+
+HELP: (derivative)
+{ $values
+ { "x" "a position on the function" }
+ { "func" "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."
+ }
+ { "ans" number }
+ { "error" number }
+}
+{ $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 math.derivatives prettyprint ;"
+ "4 [ sq ] derivative >integer ."
+ "8"
+ }
+ { $notes
+ "For applied scientists, you may play with the settings "
+ "in the source file to achieve arbitrary accuracy. "
+ }
+} ;
+
+HELP: derivative-func
+{ $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: kernel math.derivatives math.functions math.trig prettyprint ;"
+ "60 deg>rad [ sin ] derivative-func call 0.5 .001 ~ ."
+ "t"
+ }
+ { $notes
+ "Without a heavy algebraic system, derivatives must be "
+ "approximated. With the current settings, there is a fair trade of "
+ "speed and accuracy; the first 12 digits "
+ "will always be correct with " { $link sin } " and " { $link cos }
+ ". The following code performs a minumum and maximum error test."
+ { $code
+ "USING: kernel math math.functions math.trig sequences sequences.lib ;"
+ "360"
+ "["
+ " deg>rad"
+ " [ [ sin ] derivative-func call ]"
+ " ! Note: the derivative of sin is cos"
+ " [ cos ]"
+ " bi - abs"
+ "] map minmax"
+ }
+ }
+} ;
+
+ARTICLE: "derivatives" "The Derivative Toolkit"
+"A toolkit for computing the derivative of functions."
+{ $subsection derivative }
+{ $subsection derivative-func }
+{ $subsection (derivative) } ;
+
+ABOUT: "derivatives"
--- /dev/null
+USING: math math.derivatives tools.test ;
+IN: math.derivatives.test
+
+[ 8 ] [ 4 [ sq ] derivative >integer ] unit-test
+
--- /dev/null
+! Copyright (c) 2008 Reginald Keith Ford II, Eduardo Cavazos.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel continuations combinators sequences math math.order math.ranges
+ accessors float-arrays ;
+IN: math.derivatives
+
+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 ; inline
+: con ( -- val ) 1.6 ; inline
+: con2 ( -- val ) con con * ; inline
+: big ( -- val ) largest-float ; inline
+: safe ( -- val ) 2.0 ; inline
+
+! 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 ;
--- /dev/null
+Reginald Ford
\ No newline at end of file
--- /dev/null
+! Copyright (c) 2008 Reginald Keith Ford II.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel math math.derivatives ;
+IN: math.newtons-method
+
+! Newton's method of approximating roots
+
+<PRIVATE
+
+: newton-step ( x function -- x2 )
+ dupd [ call ] [ derivative ] 2bi / - ; inline
+
+: newton-precision ( -- n ) 13 ; inline
+
+PRIVATE>
+
+: newtons-method ( guess function -- x )
+ newton-precision [ [ newton-step ] keep ] times drop ;
--- /dev/null
+Alex Chapman
--- /dev/null
+! Copyright (C) 2007 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax ;
+IN: morse
+
+HELP: ch>morse
+{ $values
+ { "ch" "A character that has a morse code translation" } { "str" "A string consisting of zero or more dots and dashes" } }
+{ $description "If the given character has a morse code translation, then return that translation, otherwise return an empty string." } ;
+
+HELP: morse>ch
+{ $values
+ { "str" "A string of dots and dashes that represents a single character in morse code" } { "ch" "The translated character" } }
+{ $description "If the given string represents a morse code character, then return that character, otherwise return f" } ;
+
+HELP: >morse
+{ $values
+ { "str" "A string of ASCII characters which can be translated into morse code" } { "str" "A string in morse code" } }
+{ $description "Translates ASCII text into morse code, represented by a series of dots, dashes, and slashes." }
+{ $see-also morse> ch>morse } ;
+
+HELP: morse>
+{ $values { "str" "A string of morse code, in which the character '.' represents dots, '-' dashes, ' ' spaces between letters, and ' / ' spaces between words." } { "str" "The ASCII translation of the given string" } }
+{ $description "Translates morse code into ASCII text" }
+{ $see-also >morse morse>ch } ;
+
+HELP: play-as-morse*
+{ $values { "str" "A string of ascii characters which can be translated into morse code" } { "unit-length" "The length of a dot" } }
+{ $description "Plays a string as morse code" } ;
+
+HELP: play-as-morse
+{ $values { "str" "A string of ascii characters which can be translated into morse code" } }
+{ $description "Plays a string as morse code" } ;
--- /dev/null
+! Copyright (C) 2007 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays morse strings tools.test ;
+
+[ "" ] [ CHAR: \\ ch>morse ] unit-test
+[ "..." ] [ CHAR: s ch>morse ] unit-test
+[ CHAR: s ] [ "..." morse>ch ] unit-test
+[ f ] [ "..--..--.." morse>ch ] unit-test
+[ "-- --- .-. ... . / -.-. --- -.. ." ] [ "morse code" >morse ] unit-test
+[ "morse code" ] [ "-- --- .-. ... . / -.-. --- -.. ." morse> ] unit-test
+[ "hello, world!" ] [ "Hello, World!" >morse morse> ] unit-test
+! [ ] [ "sos" 0.075 play-as-morse* ] unit-test
+! [ ] [ "Factor rocks!" play-as-morse ] unit-test
--- /dev/null
+! Copyright (C) 2007, 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors assocs combinators hashtables kernel lists math
+namespaces make openal parser-combinators promises sequences
+strings symbols synth synth.buffers unicode.case ;
+IN: morse
+
+<PRIVATE
+: morse-codes ( -- array )
+ {
+ { CHAR: a ".-" }
+ { CHAR: b "-..." }
+ { CHAR: c "-.-." }
+ { CHAR: d "-.." }
+ { CHAR: e "." }
+ { CHAR: f "..-." }
+ { CHAR: g "--." }
+ { CHAR: h "...." }
+ { CHAR: i ".." }
+ { CHAR: j ".---" }
+ { CHAR: k "-.-" }
+ { CHAR: l ".-.." }
+ { CHAR: m "--" }
+ { CHAR: n "-." }
+ { CHAR: o "---" }
+ { CHAR: p ".--." }
+ { CHAR: q "--.-" }
+ { CHAR: r ".-." }
+ { CHAR: s "..." }
+ { CHAR: t "-" }
+ { CHAR: u "..-" }
+ { CHAR: v "...-" }
+ { CHAR: w ".--" }
+ { CHAR: x "-..-" }
+ { CHAR: y "-.--" }
+ { CHAR: z "--.." }
+ { CHAR: 1 ".----" }
+ { CHAR: 2 "..---" }
+ { CHAR: 3 "...--" }
+ { CHAR: 4 "....-" }
+ { CHAR: 5 "....." }
+ { CHAR: 6 "-...." }
+ { CHAR: 7 "--..." }
+ { CHAR: 8 "---.." }
+ { CHAR: 9 "----." }
+ { CHAR: 0 "-----" }
+ { CHAR: . ".-.-.-" }
+ { CHAR: , "--..--" }
+ { CHAR: ? "..--.." }
+ { CHAR: ' ".----." }
+ { CHAR: ! "-.-.--" }
+ { CHAR: / "-..-." }
+ { CHAR: ( "-.--." }
+ { CHAR: ) "-.--.-" }
+ { CHAR: & ".-..." }
+ { CHAR: : "---..." }
+ { CHAR: ; "-.-.-." }
+ { CHAR: = "-...- " }
+ { CHAR: + ".-.-." }
+ { CHAR: - "-....-" }
+ { CHAR: _ "..--.-" }
+ { CHAR: " ".-..-." }
+ { CHAR: $ "...-..-" }
+ { CHAR: @ ".--.-." }
+ { CHAR: \s "/" }
+ } ;
+
+: ch>morse-assoc ( -- assoc )
+ morse-codes >hashtable ;
+
+: morse>ch-assoc ( -- assoc )
+ morse-codes [ reverse ] map >hashtable ;
+
+PRIVATE>
+
+: ch>morse ( ch -- str )
+ ch>lower ch>morse-assoc at* swap "" ? ;
+
+: morse>ch ( str -- ch )
+ morse>ch-assoc at* swap f ? ;
+
+: >morse ( str -- str )
+ [
+ [ CHAR: \s , ] [ ch>morse % ] interleave
+ ] "" make ;
+
+<PRIVATE
+
+: dot-char ( -- ch ) CHAR: . ;
+: dash-char ( -- ch ) CHAR: - ;
+: char-gap-char ( -- ch ) CHAR: \s ;
+: word-gap-char ( -- ch ) CHAR: / ;
+
+: =parser ( obj -- parser )
+ [ = ] curry satisfy ;
+
+LAZY: 'dot' ( -- parser )
+ dot-char =parser ;
+
+LAZY: 'dash' ( -- parser )
+ dash-char =parser ;
+
+LAZY: 'char-gap' ( -- parser )
+ char-gap-char =parser ;
+
+LAZY: 'word-gap' ( -- parser )
+ word-gap-char =parser ;
+
+LAZY: 'morse-char' ( -- parser )
+ 'dot' 'dash' <|> <+> ;
+
+LAZY: 'morse-word' ( -- parser )
+ 'morse-char' 'char-gap' list-of ;
+
+LAZY: 'morse-words' ( -- parser )
+ 'morse-word' 'word-gap' list-of ;
+
+PRIVATE>
+
+: morse> ( str -- str )
+ 'morse-words' parse car parsed>> [
+ [
+ >string morse>ch
+ ] map >string
+ ] map [ [ CHAR: \s , ] [ % ] interleave ] "" make ;
+
+<PRIVATE
+SYMBOLS: source dot-buffer dash-buffer intra-char-gap-buffer letter-gap-buffer ;
+
+: queue ( symbol -- )
+ get source get swap queue-buffer ;
+
+: dot ( -- ) dot-buffer queue ;
+: dash ( -- ) dash-buffer queue ;
+: intra-char-gap ( -- ) intra-char-gap-buffer queue ;
+: letter-gap ( -- ) letter-gap-buffer queue ;
+
+: beep-freq 880 ;
+
+: <morse-buffer> ( -- buffer )
+ half-sample-freq <8bit-mono-buffer> ;
+
+: sine-buffer ( seconds -- id )
+ beep-freq swap <morse-buffer> >sine-wave-buffer
+ send-buffer id>> ;
+
+: silent-buffer ( seconds -- id )
+ <morse-buffer> >silent-buffer send-buffer id>> ;
+
+: make-buffers ( unit-length -- )
+ {
+ [ sine-buffer dot-buffer set ]
+ [ 3 * sine-buffer dash-buffer set ]
+ [ silent-buffer intra-char-gap-buffer set ]
+ [ 3 * silent-buffer letter-gap-buffer set ]
+ } cleave ;
+
+: playing-morse ( quot unit-length -- )
+ [
+ init-openal 1 gen-sources first source set make-buffers
+ call
+ source get source-play
+ ] with-scope ;
+
+: play-char ( ch -- )
+ [ intra-char-gap ] [
+ {
+ { dot-char [ dot ] }
+ { dash-char [ dash ] }
+ { word-gap-char [ intra-char-gap ] }
+ } case
+ ] interleave ;
+
+PRIVATE>
+
+: play-as-morse* ( str unit-length -- )
+ [
+ [ letter-gap ] [ ch>morse play-char ] interleave
+ ] swap playing-morse ;
+
+: play-as-morse ( str -- )
+ 0.05 play-as-morse* ;
--- /dev/null
+Converts between text and morse code, and plays morse code.
--- /dev/null
+USING: arrays kernel math opengl opengl.gl opengl.glu
+opengl.demo-support ui ui.gadgets ui.render ;
+IN: nehe.2
+
+TUPLE: nehe2-gadget < gadget ;
+
+: width 256 ;
+: height 256 ;
+
+: <nehe2-gadget> ( -- gadget )
+ nehe2-gadget new-gadget ;
+
+M: nehe2-gadget pref-dim* ( gadget -- dim )
+ drop width height 2array ;
+
+M: nehe2-gadget draw-gadget* ( gadget -- )
+ drop
+ GL_PROJECTION glMatrixMode
+ glLoadIdentity
+ 45.0 width height / >float 0.1 100.0 gluPerspective
+ GL_MODELVIEW glMatrixMode
+ glLoadIdentity
+ GL_SMOOTH glShadeModel
+ 0.0 0.0 0.0 0.0 glClearColor
+ 1.0 glClearDepth
+ GL_DEPTH_TEST glEnable
+ GL_LEQUAL glDepthFunc
+ GL_PERSPECTIVE_CORRECTION_HINT GL_NICEST glHint
+ GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear
+ glLoadIdentity
+ -1.5 0.0 -6.0 glTranslatef
+ GL_TRIANGLES [
+ 0.0 1.0 0.0 glVertex3f
+ -1.0 -1.0 0.0 glVertex3f
+ 1.0 -1.0 0.0 glVertex3f
+ ] do-state
+ 3.0 0.0 0.0 glTranslatef
+ GL_QUADS [
+ -1.0 1.0 0.0 glVertex3f
+ 1.0 1.0 0.0 glVertex3f
+ 1.0 -1.0 0.0 glVertex3f
+ -1.0 -1.0 0.0 glVertex3f
+ ] do-state ;
+
+: run2 ( -- )
+ <nehe2-gadget> "NeHe Tutorial 2" open-window ;
--- /dev/null
+Chris Double
--- /dev/null
+USING: arrays kernel math opengl opengl.gl opengl.glu
+opengl.demo-support ui ui.gadgets ui.render ;
+IN: nehe.3
+
+TUPLE: nehe3-gadget < gadget ;
+
+: width 256 ;
+: height 256 ;
+
+: <nehe3-gadget> ( -- gadget )
+ nehe3-gadget new-gadget ;
+
+M: nehe3-gadget pref-dim* ( gadget -- dim )
+ drop width height 2array ;
+
+M: nehe3-gadget draw-gadget* ( gadget -- )
+ drop
+ GL_PROJECTION glMatrixMode
+ glLoadIdentity
+ 45.0 width height / >float 0.1 100.0 gluPerspective
+ GL_MODELVIEW glMatrixMode
+ glLoadIdentity
+ GL_SMOOTH glShadeModel
+ 0.0 0.0 0.0 0.0 glClearColor
+ 1.0 glClearDepth
+ GL_DEPTH_TEST glEnable
+ GL_LEQUAL glDepthFunc
+ GL_PERSPECTIVE_CORRECTION_HINT GL_NICEST glHint
+ GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear
+ glLoadIdentity
+ -1.5 0.0 -6.0 glTranslatef
+ GL_TRIANGLES [
+ 1.0 0.0 0.0 glColor3f
+ 0.0 1.0 0.0 glVertex3f
+ 0.0 1.0 0.0 glColor3f
+ -1.0 -1.0 0.0 glVertex3f
+ 0.0 0.0 1.0 glColor3f
+ 1.0 -1.0 0.0 glVertex3f
+ ] do-state
+ 3.0 0.0 0.0 glTranslatef
+ 0.5 0.5 1.0 glColor3f
+ GL_QUADS [
+ -1.0 1.0 0.0 glVertex3f
+ 1.0 1.0 0.0 glVertex3f
+ 1.0 -1.0 0.0 glVertex3f
+ -1.0 -1.0 0.0 glVertex3f
+ ] do-state ;
+
+: run3 ( -- )
+ <nehe3-gadget> "NeHe Tutorial 3" open-window ;
--- /dev/null
+Chris Double
--- /dev/null
+USING: arrays kernel math opengl opengl.gl opengl.glu
+opengl.demo-support ui ui.gadgets ui.render threads accessors
+calendar ;
+IN: nehe.4
+
+TUPLE: nehe4-gadget < gadget rtri rquad thread quit? ;
+
+: width 256 ;
+: height 256 ;
+: redraw-interval ( -- dt ) 10 milliseconds ;
+
+: <nehe4-gadget> ( -- gadget )
+ nehe4-gadget new-gadget
+ 0.0 >>rtri
+ 0.0 >>rquad ;
+
+M: nehe4-gadget pref-dim* ( gadget -- dim )
+ drop width height 2array ;
+
+M: nehe4-gadget draw-gadget* ( gadget -- )
+ GL_PROJECTION glMatrixMode
+ glLoadIdentity
+ 45.0 width height / >float 0.1 100.0 gluPerspective
+ GL_MODELVIEW glMatrixMode
+ glLoadIdentity
+ GL_SMOOTH glShadeModel
+ 0.0 0.0 0.0 0.0 glClearColor
+ 1.0 glClearDepth
+ GL_DEPTH_TEST glEnable
+ GL_LEQUAL glDepthFunc
+ GL_PERSPECTIVE_CORRECTION_HINT GL_NICEST glHint
+ GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear
+ glLoadIdentity
+ -1.5 0.0 -6.0 glTranslatef
+ dup rtri>> 0.0 1.0 0.0 glRotatef
+
+ GL_TRIANGLES [
+ 1.0 0.0 0.0 glColor3f
+ 0.0 1.0 0.0 glVertex3f
+ 0.0 1.0 0.0 glColor3f
+ -1.0 -1.0 0.0 glVertex3f
+ 0.0 0.0 1.0 glColor3f
+ 1.0 -1.0 0.0 glVertex3f
+ ] do-state
+
+ glLoadIdentity
+
+ 1.5 0.0 -6.0 glTranslatef
+ dup rquad>> 1.0 0.0 0.0 glRotatef
+ 0.5 0.5 1.0 glColor3f
+ GL_QUADS [
+ -1.0 1.0 0.0 glVertex3f
+ 1.0 1.0 0.0 glVertex3f
+ 1.0 -1.0 0.0 glVertex3f
+ -1.0 -1.0 0.0 glVertex3f
+ ] do-state
+ [ 0.2 + ] change-rtri
+ [ 0.15 - ] change-rquad drop ;
+
+: nehe4-update-thread ( gadget -- )
+ dup quit?>> [ drop ] [
+ redraw-interval sleep
+ dup relayout-1
+ nehe4-update-thread
+ ] if ;
+
+M: nehe4-gadget graft* ( gadget -- )
+ f >>quit?
+ [ nehe4-update-thread ] curry in-thread ;
+
+M: nehe4-gadget ungraft* ( gadget -- )
+ t >>quit? drop ;
+
+: run4 ( -- )
+ <nehe4-gadget> "NeHe Tutorial 4" open-window ;
--- /dev/null
+Chris Double
--- /dev/null
+USING: arrays kernel math opengl opengl.gl opengl.glu\r
+opengl.demo-support ui ui.gadgets ui.render threads accessors\r
+calendar ;\r
+IN: nehe.5\r
+\r
+TUPLE: nehe5-gadget < gadget rtri rquad thread quit? ;\r
+: width 256 ;\r
+: height 256 ;\r
+: redraw-interval ( -- dt ) 10 milliseconds ;\r
+\r
+: <nehe5-gadget> ( -- gadget )\r
+ nehe5-gadget new-gadget\r
+ 0.0 >>rtri\r
+ 0.0 >>rquad ;\r
+\r
+M: nehe5-gadget pref-dim* ( gadget -- dim )\r
+ drop width height 2array ;\r
+\r
+M: nehe5-gadget draw-gadget* ( gadget -- )\r
+ GL_PROJECTION glMatrixMode\r
+ glLoadIdentity\r
+ 45.0 width height / >float 0.1 100.0 gluPerspective\r
+ GL_MODELVIEW glMatrixMode\r
+ glLoadIdentity\r
+ GL_SMOOTH glShadeModel\r
+ 0.0 0.0 0.0 0.0 glClearColor\r
+ 1.0 glClearDepth\r
+ GL_DEPTH_TEST glEnable\r
+ GL_LEQUAL glDepthFunc\r
+ GL_PERSPECTIVE_CORRECTION_HINT GL_NICEST glHint\r
+ GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear\r
+ glLoadIdentity\r
+ -1.5 0.0 -6.0 glTranslatef\r
+ dup rtri>> 0.0 1.0 0.0 glRotatef\r
+\r
+ GL_TRIANGLES [\r
+ 1.0 0.0 0.0 glColor3f\r
+ 0.0 1.0 0.0 glVertex3f\r
+ 0.0 1.0 0.0 glColor3f\r
+ -1.0 -1.0 1.0 glVertex3f\r
+ 0.0 0.0 1.0 glColor3f\r
+ 1.0 -1.0 1.0 glVertex3f\r
+\r
+ 1.0 0.0 0.0 glColor3f\r
+ 0.0 1.0 0.0 glVertex3f\r
+ 0.0 0.0 1.0 glColor3f\r
+ 1.0 -1.0 1.0 glVertex3f\r
+ 0.0 1.0 0.0 glColor3f\r
+ 1.0 -1.0 -1.0 glVertex3f\r
+\r
+ 1.0 0.0 0.0 glColor3f\r
+ 0.0 1.0 0.0 glVertex3f\r
+ 0.0 1.0 0.0 glColor3f\r
+ 1.0 -1.0 -1.0 glVertex3f\r
+ 0.0 0.0 1.0 glColor3f\r
+ -1.0 -1.0 -1.0 glVertex3f\r
+\r
+ 1.0 0.0 0.0 glColor3f\r
+ 0.0 1.0 0.0 glVertex3f\r
+ 0.0 0.0 1.0 glColor3f\r
+ -1.0 -1.0 -1.0 glVertex3f\r
+ 0.0 1.0 0.0 glColor3f\r
+ -1.0 -1.0 1.0 glVertex3f\r
+ ] do-state\r
+\r
+ glLoadIdentity\r
+\r
+ 1.5 0.0 -7.0 glTranslatef\r
+ dup rquad>> 1.0 0.0 0.0 glRotatef\r
+ GL_QUADS [\r
+ 0.0 1.0 0.0 glColor3f\r
+ 1.0 1.0 -1.0 glVertex3f\r
+ -1.0 1.0 -1.0 glVertex3f\r
+ -1.0 1.0 1.0 glVertex3f\r
+ 1.0 1.0 1.0 glVertex3f\r
+\r
+ 1.0 0.5 0.0 glColor3f\r
+ 1.0 -1.0 1.0 glVertex3f\r
+ -1.0 -1.0 1.0 glVertex3f\r
+ -1.0 -1.0 -1.0 glVertex3f\r
+ 1.0 -1.0 -1.0 glVertex3f\r
+\r
+ 1.0 0.0 0.0 glColor3f\r
+ 1.0 1.0 1.0 glVertex3f\r
+ -1.0 1.0 1.0 glVertex3f\r
+ -1.0 -1.0 1.0 glVertex3f\r
+ 1.0 -1.0 1.0 glVertex3f\r
+\r
+ 1.0 1.0 0.0 glColor3f\r
+ 1.0 -1.0 -1.0 glVertex3f\r
+ -1.0 -1.0 -1.0 glVertex3f\r
+ -1.0 1.0 -1.0 glVertex3f\r
+ 1.0 1.0 -1.0 glVertex3f\r
+\r
+ 0.0 0.0 1.0 glColor3f\r
+ -1.0 1.0 1.0 glVertex3f\r
+ -1.0 1.0 -1.0 glVertex3f\r
+ -1.0 -1.0 -1.0 glVertex3f\r
+ -1.0 -1.0 1.0 glVertex3f\r
+\r
+ 1.0 0.0 1.0 glColor3f\r
+ 1.0 1.0 -1.0 glVertex3f\r
+ 1.0 1.0 1.0 glVertex3f\r
+ 1.0 -1.0 1.0 glVertex3f\r
+ 1.0 -1.0 -1.0 glVertex3f\r
+ ] do-state \r
+ [ 0.2 + ] change-rtri\r
+ [ 0.15 - ] change-rquad drop ;\r
+\r
+: nehe5-update-thread ( gadget -- ) \r
+ dup quit?>> [\r
+ drop\r
+ ] [\r
+ redraw-interval sleep \r
+ dup relayout-1 \r
+ nehe5-update-thread \r
+ ] if ;\r
+\r
+M: nehe5-gadget graft* ( gadget -- )\r
+ f >>quit?\r
+ [ nehe5-update-thread ] curry in-thread ;\r
+\r
+M: nehe5-gadget ungraft* ( gadget -- )\r
+ t >>quit? drop ;\r
+\r
+\r
+: run5 ( -- )\r
+ <nehe5-gadget> "NeHe Tutorial 5" open-window ;\r
--- /dev/null
+Chris Double
--- /dev/null
+Chris Double
--- /dev/null
+USING: tools.deploy.config ;
+V{
+ { deploy-ui? t }
+ { deploy-io 1 }
+ { deploy-reflection 1 }
+ { deploy-compiler? t }
+ { deploy-math? t }
+ { deploy-word-props? f }
+ { deploy-c-types? f }
+ { "stop-after-last-window?" t }
+ { deploy-name "NeHe OpenGL demos" }
+}
--- /dev/null
+USING: ui.gadgets.buttons ui.gadgets.packs ui.gadgets ui
+nehe.2 nehe.3 nehe.4 nehe.5 kernel ;
+IN: nehe
+
+: nehe-window ( -- )
+ [
+ <filled-pile>
+ "Nehe 2" [ drop run2 ] <bevel-button> add-gadget
+ "Nehe 3" [ drop run3 ] <bevel-button> add-gadget
+ "Nehe 4" [ drop run4 ] <bevel-button> add-gadget
+ "Nehe 5" [ drop run5 ] <bevel-button> add-gadget
+ "Nehe examples" open-window
+ ] with-ui ;
+
+MAIN: nehe-window
--- /dev/null
+NeHe OpenGL tutorials ported to Factor
--- /dev/null
+Chris Double
--- /dev/null
+Chris Double
--- /dev/null
+USING: namespaces system ;
+IN: openal.backend
+
+HOOK: load-wav-file os ( filename -- format data size frequency )
--- /dev/null
+Chris Double
--- /dev/null
+! Copyright (C) 2007 Chris Double.\r
+! See http://factorcode.org/license.txt for BSD license.\r
+!\r
+IN: openal.example\r
+USING: openal kernel alien threads sequences calendar ;\r
+\r
+: play-hello ( -- )\r
+ init-openal\r
+ 1 gen-sources\r
+ first dup AL_BUFFER alutCreateBufferHelloWorld set-source-param\r
+ source-play\r
+ 1000 milliseconds sleep ;\r
+ \r
+: (play-file) ( source -- )\r
+ 100 milliseconds sleep\r
+ dup source-playing? [ (play-file) ] [ drop ] if ;\r
+\r
+: play-file ( filename -- )\r
+ init-openal\r
+ create-buffer-from-file \r
+ 1 gen-sources\r
+ first dup >r AL_BUFFER rot set-source-param r>\r
+ dup source-play\r
+ check-error\r
+ (play-file) ;\r
+\r
+: play-wav ( filename -- )\r
+ init-openal\r
+ create-buffer-from-wav \r
+ 1 gen-sources\r
+ first dup >r AL_BUFFER rot set-source-param r>\r
+ dup source-play\r
+ check-error\r
+ (play-file) ;
\ No newline at end of file
--- /dev/null
+Chris Double
--- /dev/null
+! Copyright (C) 2007 Chris Double.
+! See http://factorcode.org/license.txt for BSD license.
+USING: alien.c-types kernel alien alien.syntax shuffle
+combinators.lib openal.backend namespaces system ;
+IN: openal.macosx
+
+LIBRARY: alut
+
+FUNCTION: void alutLoadWAVFile ( ALbyte* fileName, ALenum* format, void** data, ALsizei* size, ALsizei* frequency ) ;
+
+M: macosx load-wav-file ( path -- format data size frequency )
+ 0 <int> f <void*> 0 <int> 0 <int>
+ [ alutLoadWAVFile ] 4keep
+ >r >r >r *int r> *void* r> *int r> *int ;
--- /dev/null
+unportable
--- /dev/null
+! Copyright (C) 2007 Chris Double.
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel arrays alien system combinators alien.syntax namespaces
+ alien.c-types sequences vocabs.loader shuffle combinators.lib
+ openal.backend specialized-arrays.uint ;
+IN: openal
+
+<< "alut" {
+ { [ os windows? ] [ "alut.dll" ] }
+ { [ os macosx? ] [
+ "/System/Library/Frameworks/OpenAL.framework/OpenAL"
+ ] }
+ { [ os unix? ] [ "libalut.so" ] }
+ } cond "cdecl" add-library >>
+
+<< "openal" {
+ { [ os windows? ] [ "OpenAL32.dll" ] }
+ { [ os macosx? ] [
+ "/System/Library/Frameworks/OpenAL.framework/OpenAL"
+ ] }
+ { [ os unix? ] [ "libopenal.so" ] }
+ } cond "cdecl" add-library >>
+
+LIBRARY: openal
+
+TYPEDEF: char ALboolean
+TYPEDEF: char ALchar
+TYPEDEF: char ALbyte
+TYPEDEF: uchar ALubyte
+TYPEDEF: short ALshort
+TYPEDEF: ushort ALushort
+TYPEDEF: int ALint
+TYPEDEF: uint ALuint
+TYPEDEF: int ALsizei
+TYPEDEF: int ALenum
+TYPEDEF: float ALfloat
+TYPEDEF: double ALdouble
+
+: AL_INVALID ( -- number ) -1 ; inline
+: AL_NONE ( -- number ) 0 ; inline
+: AL_FALSE ( -- number ) 0 ; inline
+: AL_TRUE ( -- number ) 1 ; inline
+: AL_SOURCE_RELATIVE ( -- number ) HEX: 202 ; inline
+: AL_CONE_INNER_ANGLE ( -- nmber ) HEX: 1001 ; inline
+: AL_CONE_OUTER_ANGLE ( -- number ) HEX: 1002 ; inline
+: AL_PITCH ( -- number ) HEX: 1003 ; inline
+: AL_POSITION ( -- number ) HEX: 1004 ; inline
+: AL_DIRECTION ( -- number ) HEX: 1005 ; inline
+: AL_VELOCITY ( -- number ) HEX: 1006 ; inline
+: AL_LOOPING ( -- number ) HEX: 1007 ; inline
+: AL_BUFFER ( -- number ) HEX: 1009 ; inline
+: AL_GAIN ( -- number ) HEX: 100A ; inline
+: AL_MIN_GAIN ( -- number ) HEX: 100D ; inline
+: AL_MAX_GAIN ( -- number ) HEX: 100E ; inline
+: AL_ORIENTATION ( -- number ) HEX: 100F ; inline
+: AL_CHANNEL_MASK ( -- number ) HEX: 3000 ; inline
+: AL_SOURCE_STATE ( -- number ) HEX: 1010 ; inline
+: AL_INITIAL ( -- number ) HEX: 1011 ; inline
+: AL_PLAYING ( -- number ) HEX: 1012 ; inline
+: AL_PAUSED ( -- number ) HEX: 1013 ; inline
+: AL_STOPPED ( -- number ) HEX: 1014 ; inline
+: AL_BUFFERS_QUEUED ( -- number ) HEX: 1015 ; inline
+: AL_BUFFERS_PROCESSED ( -- number ) HEX: 1016 ; inline
+: AL_SEC_OFFSET ( -- number ) HEX: 1024 ; inline
+: AL_SAMPLE_OFFSET ( -- number ) HEX: 1025 ; inline
+: AL_BYTE_OFFSET ( -- number ) HEX: 1026 ; inline
+: AL_SOURCE_TYPE ( -- number ) HEX: 1027 ; inline
+: AL_STATIC ( -- number ) HEX: 1028 ; inline
+: AL_STREAMING ( -- number ) HEX: 1029 ; inline
+: AL_UNDETERMINED ( -- number ) HEX: 1030 ; inline
+: AL_FORMAT_MONO8 ( -- number ) HEX: 1100 ; inline
+: AL_FORMAT_MONO16 ( -- number ) HEX: 1101 ; inline
+: AL_FORMAT_STEREO8 ( -- number ) HEX: 1102 ; inline
+: AL_FORMAT_STEREO16 ( -- number ) HEX: 1103 ; inline
+: AL_REFERENCE_DISTANCE ( -- number ) HEX: 1020 ; inline
+: AL_ROLLOFF_FACTOR ( -- number ) HEX: 1021 ; inline
+: AL_CONE_OUTER_GAIN ( -- number ) HEX: 1022 ; inline
+: AL_MAX_DISTANCE ( -- number ) HEX: 1023 ; inline
+: AL_FREQUENCY ( -- number ) HEX: 2001 ; inline
+: AL_BITS ( -- number ) HEX: 2002 ; inline
+: AL_CHANNELS ( -- number ) HEX: 2003 ; inline
+: AL_SIZE ( -- number ) HEX: 2004 ; inline
+: AL_UNUSED ( -- number ) HEX: 2010 ; inline
+: AL_PENDING ( -- number ) HEX: 2011 ; inline
+: AL_PROCESSED ( -- number ) HEX: 2012 ; inline
+: AL_NO_ERROR ( -- number ) AL_FALSE ; inline
+: AL_INVALID_NAME ( -- number ) HEX: A001 ; inline
+: AL_ILLEGAL_ENUM ( -- number ) HEX: A002 ; inline
+: AL_INVALID_ENUM ( -- number ) HEX: A002 ; inline
+: AL_INVALID_VALUE ( -- number ) HEX: A003 ; inline
+: AL_ILLEGAL_COMMAND ( -- number ) HEX: A004 ; inline
+: AL_INVALID_OPERATION ( -- number ) HEX: A004 ; inline
+: AL_OUT_OF_MEMORY ( -- number ) HEX: A005 ; inline
+: AL_VENDOR ( -- number ) HEX: B001 ; inline
+: AL_VERSION ( -- number ) HEX: B002 ; inline
+: AL_RENDERER ( -- number ) HEX: B003 ; inline
+: AL_EXTENSIONS ( -- number ) HEX: B004 ; inline
+: AL_DOPPLER_FACTOR ( -- number ) HEX: C000 ; inline
+: AL_DOPPLER_VELOCITY ( -- number ) HEX: C001 ; inline
+: AL_SPEED_OF_SOUND ( -- number ) HEX: C003 ; inline
+: AL_DISTANCE_MODEL ( -- number ) HEX: D000 ; inline
+: AL_INVERSE_DISTANCE ( -- number ) HEX: D001 ; inline
+: AL_INVERSE_DISTANCE_CLAMPED ( -- number ) HEX: D002 ; inline
+: AL_LINEAR_DISTANCE ( -- number ) HEX: D003 ; inline
+: AL_LINEAR_DISTANCE_CLAMPED ( -- number ) HEX: D004 ; inline
+: AL_EXPONENT_DISTANCE ( -- number ) HEX: D005 ; inline
+: AL_EXPONENT_DISTANCE_CLAMPED ( -- number ) HEX: D006 ; inline
+
+FUNCTION: void alEnable ( ALenum capability ) ;
+FUNCTION: void alDisable ( ALenum capability ) ;
+FUNCTION: ALboolean alIsEnabled ( ALenum capability ) ;
+FUNCTION: ALchar* alGetString ( ALenum param ) ;
+FUNCTION: void alGetBooleanv ( ALenum param, ALboolean* data ) ;
+FUNCTION: void alGetIntegerv ( ALenum param, ALint* data ) ;
+FUNCTION: void alGetFloatv ( ALenum param, ALfloat* data ) ;
+FUNCTION: void alGetDoublev ( ALenum param, ALdouble* data ) ;
+FUNCTION: ALboolean alGetBoolean ( ALenum param ) ;
+FUNCTION: ALint alGetInteger ( ALenum param ) ;
+FUNCTION: ALfloat alGetFloat ( ALenum param ) ;
+FUNCTION: ALdouble alGetDouble ( ALenum param ) ;
+FUNCTION: ALenum alGetError ( ) ;
+FUNCTION: ALboolean alIsExtensionPresent ( ALchar* extname ) ;
+FUNCTION: void* alGetProcAddress ( ALchar* fname ) ;
+FUNCTION: ALenum alGetEnumValue ( ALchar* ename ) ;
+FUNCTION: void alListenerf ( ALenum param, ALfloat value ) ;
+FUNCTION: void alListener3f ( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ) ;
+FUNCTION: void alListenerfv ( ALenum param, ALfloat* values ) ;
+FUNCTION: void alListeneri ( ALenum param, ALint value ) ;
+FUNCTION: void alListener3i ( ALenum param, ALint value1, ALint value2, ALint value3 ) ;
+FUNCTION: void alListeneriv ( ALenum param, ALint* values ) ;
+FUNCTION: void alGetListenerf ( ALenum param, ALfloat* value ) ;
+FUNCTION: void alGetListener3f ( ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3 ) ;
+FUNCTION: void alGetListenerfv ( ALenum param, ALfloat* values ) ;
+FUNCTION: void alGetListeneri ( ALenum param, ALint* value ) ;
+FUNCTION: void alGetListener3i ( ALenum param, ALint* value1, ALint* value2, ALint* value3 ) ;
+FUNCTION: void alGetListeneriv ( ALenum param, ALint* values ) ;
+FUNCTION: void alGenSources ( ALsizei n, ALuint* sources ) ;
+FUNCTION: void alDeleteSources ( ALsizei n, ALuint* sources ) ;
+FUNCTION: ALboolean alIsSource ( ALuint sid ) ;
+FUNCTION: void alSourcef ( ALuint sid, ALenum param, ALfloat value ) ;
+FUNCTION: void alSource3f ( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ) ;
+FUNCTION: void alSourcefv ( ALuint sid, ALenum param, ALfloat* values ) ;
+FUNCTION: void alSourcei ( ALuint sid, ALenum param, ALint value ) ;
+FUNCTION: void alSource3i ( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ) ;
+FUNCTION: void alSourceiv ( ALuint sid, ALenum param, ALint* values ) ;
+FUNCTION: void alGetSourcef ( ALuint sid, ALenum param, ALfloat* value ) ;
+FUNCTION: void alGetSource3f ( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3) ;
+FUNCTION: void alGetSourcefv ( ALuint sid, ALenum param, ALfloat* values ) ;
+FUNCTION: void alGetSourcei ( ALuint sid, ALenum param, ALint* value ) ;
+FUNCTION: void alGetSource3i ( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3) ;
+FUNCTION: void alGetSourceiv ( ALuint sid, ALenum param, ALint* values ) ;
+FUNCTION: void alSourcePlayv ( ALsizei ns, ALuint* sids ) ;
+FUNCTION: void alSourceStopv ( ALsizei ns, ALuint* sids ) ;
+FUNCTION: void alSourceRewindv ( ALsizei ns, ALuint* sids ) ;
+FUNCTION: void alSourcePausev ( ALsizei ns, ALuint* sids ) ;
+FUNCTION: void alSourcePlay ( ALuint sid ) ;
+FUNCTION: void alSourceStop ( ALuint sid ) ;
+FUNCTION: void alSourceRewind ( ALuint sid ) ;
+FUNCTION: void alSourcePause ( ALuint sid ) ;
+FUNCTION: void alSourceQueueBuffers ( ALuint sid, ALsizei numEntries, ALuint* bids ) ;
+FUNCTION: void alSourceUnqueueBuffers ( ALuint sid, ALsizei numEntries, ALuint* bids ) ;
+FUNCTION: void alGenBuffers ( ALsizei n, ALuint* buffers ) ;
+FUNCTION: void alDeleteBuffers ( ALsizei n, ALuint* buffers ) ;
+FUNCTION: ALboolean alIsBuffer ( ALuint bid ) ;
+FUNCTION: void alBufferData ( ALuint bid, ALenum format, void* data, ALsizei size, ALsizei freq ) ;
+FUNCTION: void alBufferf ( ALuint bid, ALenum param, ALfloat value ) ;
+FUNCTION: void alBuffer3f ( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ) ;
+FUNCTION: void alBufferfv ( ALuint bid, ALenum param, ALfloat* values ) ;
+FUNCTION: void alBufferi ( ALuint bid, ALenum param, ALint value ) ;
+FUNCTION: void alBuffer3i ( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ) ;
+FUNCTION: void alBufferiv ( ALuint bid, ALenum param, ALint* values ) ;
+FUNCTION: void alGetBufferf ( ALuint bid, ALenum param, ALfloat* value ) ;
+FUNCTION: void alGetBuffer3f ( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3) ;
+FUNCTION: void alGetBufferfv ( ALuint bid, ALenum param, ALfloat* values ) ;
+FUNCTION: void alGetBufferi ( ALuint bid, ALenum param, ALint* value ) ;
+FUNCTION: void alGetBuffer3i ( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3) ;
+FUNCTION: void alGetBufferiv ( ALuint bid, ALenum param, ALint* values ) ;
+FUNCTION: void alDopplerFactor ( ALfloat value ) ;
+FUNCTION: void alDopplerVelocity ( ALfloat value ) ;
+FUNCTION: void alSpeedOfSound ( ALfloat value ) ;
+FUNCTION: void alDistanceModel ( ALenum distanceModel ) ;
+
+LIBRARY: alut
+
+: ALUT_API_MAJOR_VERSION ( -- number ) 1 ; inline
+: ALUT_API_MINOR_VERSION ( -- number ) 1 ; inline
+: ALUT_ERROR_NO_ERROR ( -- number ) 0 ; inline
+: ALUT_ERROR_OUT_OF_MEMORY ( -- number ) HEX: 200 ; inline
+: ALUT_ERROR_INVALID_ENUM ( -- number ) HEX: 201 ; inline
+: ALUT_ERROR_INVALID_VALUE ( -- number ) HEX: 202 ; inline
+: ALUT_ERROR_INVALID_OPERATION ( -- number ) HEX: 203 ; inline
+: ALUT_ERROR_NO_CURRENT_CONTEXT ( -- number ) HEX: 204 ; inline
+: ALUT_ERROR_AL_ERROR_ON_ENTRY ( -- number ) HEX: 205 ; inline
+: ALUT_ERROR_ALC_ERROR_ON_ENTRY ( -- number ) HEX: 206 ; inline
+: ALUT_ERROR_OPEN_DEVICE ( -- number ) HEX: 207 ; inline
+: ALUT_ERROR_CLOSE_DEVICE ( -- number ) HEX: 208 ; inline
+: ALUT_ERROR_CREATE_CONTEXT ( -- number ) HEX: 209 ; inline
+: ALUT_ERROR_MAKE_CONTEXT_CURRENT ( -- number ) HEX: 20A ; inline
+: ALUT_ERROR_DESTRY_CONTEXT ( -- number ) HEX: 20B ; inline
+: ALUT_ERROR_GEN_BUFFERS ( -- number ) HEX: 20C ; inline
+: ALUT_ERROR_BUFFER_DATA ( -- number ) HEX: 20D ; inline
+: ALUT_ERROR_IO_ERROR ( -- number ) HEX: 20E ; inline
+: ALUT_ERROR_UNSUPPORTED_FILE_TYPE ( -- number ) HEX: 20F ; inline
+: ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE ( -- number ) HEX: 210 ; inline
+: ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA ( -- number ) HEX: 211 ; inline
+: ALUT_WAVEFORM_SINE ( -- number ) HEX: 100 ; inline
+: ALUT_WAVEFORM_SQUARE ( -- number ) HEX: 101 ; inline
+: ALUT_WAVEFORM_SAWTOOTH ( -- number ) HEX: 102 ; inline
+: ALUT_WAVEFORM_WHITENOISE ( -- number ) HEX: 103 ; inline
+: ALUT_WAVEFORM_IMPULSE ( -- number ) HEX: 104 ; inline
+: ALUT_LOADER_BUFFER ( -- number ) HEX: 300 ; inline
+: ALUT_LOADER_MEMORY ( -- number ) HEX: 301 ; inline
+
+FUNCTION: ALboolean alutInit ( int* argcp, char** argv ) ;
+FUNCTION: ALboolean alutInitWithoutContext ( int* argcp, char** argv ) ;
+FUNCTION: ALboolean alutExit ( ) ;
+FUNCTION: ALenum alutGetError ( ) ;
+FUNCTION: char* alutGetErrorString ( ALenum error ) ;
+FUNCTION: ALuint alutCreateBufferFromFile ( char* fileName ) ;
+FUNCTION: ALuint alutCreateBufferFromFileImage ( void* data, ALsizei length ) ;
+FUNCTION: ALuint alutCreateBufferHelloWorld ( ) ;
+FUNCTION: ALuint alutCreateBufferWaveform ( ALenum waveshape, ALfloat frequency, ALfloat phase, ALfloat duration ) ;
+FUNCTION: void* alutLoadMemoryFromFile ( char* fileName, ALenum* format, ALsizei* size, ALfloat* frequency ) ;
+FUNCTION: void* alutLoadMemoryFromFileImage ( void* data, ALsizei length, ALenum* format, ALsizei* size, ALfloat* frequency ) ;
+FUNCTION: void* alutLoadMemoryHelloWorld ( ALenum* format, ALsizei* size, ALfloat* frequency ) ;
+FUNCTION: void* alutLoadMemoryWaveform ( ALenum waveshape, ALfloat frequency, ALfloat phase, ALfloat duration, ALenum* format, ALsizei* size, ALfloat* freq ) ;
+FUNCTION: char* alutGetMIMETypes ( ALenum loader ) ;
+FUNCTION: ALint alutGetMajorVersion ( ) ;
+FUNCTION: ALint alutGetMinorVersion ( ) ;
+FUNCTION: ALboolean alutSleep ( ALfloat duration ) ;
+
+FUNCTION: void alutUnloadWAV ( ALenum format, void* data, ALsizei size, ALsizei frequency ) ;
+
+SYMBOL: init
+
+: init-openal ( -- )
+ init get-global expired? [
+ f f alutInit 0 = [ "Could not initialize OpenAL" throw ] when
+ 1337 <alien> init set-global
+ ] when ;
+
+: exit-openal ( -- )
+ init get-global expired? [
+ alutExit 0 = [ "Could not close OpenAL" throw ] when
+ f init set-global
+ ] unless ;
+
+: <uint-array> ( n -- byte-array ) "ALuint" <c-array> ;
+
+: gen-sources ( size -- seq )
+ dup <uint-array> 2dup underlying>> alGenSources swap ;
+
+: gen-buffers ( size -- seq )
+ dup <uint-array> 2dup underlying>> alGenBuffers swap ;
+
+: gen-buffer ( -- buffer ) 1 gen-buffers first ;
+
+: create-buffer-from-file ( filename -- buffer )
+ alutCreateBufferFromFile dup AL_NONE = [
+ "create-buffer-from-file failed" throw
+ ] when ;
+
+os macosx? "openal.macosx" "openal.other" ? require
+
+: create-buffer-from-wav ( filename -- buffer )
+ gen-buffer dup rot load-wav-file
+ [ alBufferData ] 4keep alutUnloadWAV ;
+
+: queue-buffers ( source buffers -- )
+ [ length ] [ >uint-array underlying>> ] bi alSourceQueueBuffers ;
+
+: queue-buffer ( source buffer -- )
+ 1array queue-buffers ;
+
+: set-source-param ( source param value -- )
+ alSourcei ;
+
+: get-source-param ( source param -- value )
+ 0 <uint> dup >r alGetSourcei r> *uint ;
+
+: set-buffer-param ( source param value -- )
+ alBufferi ;
+
+: get-buffer-param ( source param -- value )
+ 0 <uint> dup >r alGetBufferi r> *uint ;
+
+: source-play ( source -- )
+ alSourcePlay ;
+
+: source-stop ( source -- )
+ alSourceStop ;
+
+: check-error ( -- )
+ alGetError dup ALUT_ERROR_NO_ERROR = [
+ drop
+ ] [
+ alGetString throw
+ ] if ;
+
+: source-playing? ( source -- bool )
+ AL_SOURCE_STATE get-source-param AL_PLAYING = ;
--- /dev/null
+Chris Double
--- /dev/null
+! Copyright (C) 2007 Chris Double.
+! See http://factorcode.org/license.txt for BSD license.
+USING: openal.backend alien.c-types kernel alien alien.syntax
+shuffle combinators.lib ;
+IN: openal.other
+
+LIBRARY: alut
+
+FUNCTION: void alutLoadWAVFile ( ALbyte* fileName, ALenum* format, void** data, ALsizei* size, ALsizei* frequency, ALboolean* looping ) ;
+
+M: object load-wav-file ( filename -- format data size frequency )
+ 0 <int> f <void*> 0 <int> 0 <int>
+ [ 0 <char> alutLoadWAVFile ] 4keep
+ >r >r >r *int r> *void* r> *int r> *int ;
--- /dev/null
+OpenAL 3D audio library binding
--- /dev/null
+bindings
+audio
--- /dev/null
+
+USING: kernel quotations arrays sequences math math.ranges fry
+ opengl opengl.gl ui.render ui.gadgets.cartesian processing.shapes
+ accessors ;
+
+IN: ui.gadgets.plot
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+TUPLE: plot < cartesian functions points ;
+
+: init-plot ( plot -- plot )
+ init-cartesian
+ { } >>functions
+ 100 >>points ;
+
+: <plot> ( -- plot ) plot new init-plot ;
+
+: step-size ( plot -- step-size )
+ [ [ x-max>> ] [ x-min>> ] bi - ] [ points>> ] bi / ;
+
+: plot-range ( plot -- range )
+ [ x-min>> ] [ x-max>> ] [ step-size ] tri <range> ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+TUPLE: function function color ;
+
+GENERIC: plot-function ( plot object -- plot )
+
+M: callable plot-function ( plot quotation -- plot )
+ >r dup plot-range r> '[ dup @ 2array ] map line-strip ;
+
+M: function plot-function ( plot function -- plot )
+ dup color>> dup [ >stroke-color ] [ drop ] if
+ >r dup plot-range r> function>> '[ dup @ 2array ] map line-strip ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: plot-functions ( plot -- plot ) dup functions>> [ plot-function ] each ;
+
+: draw-axis ( plot -- plot )
+ dup
+ [ [ x-min>> ] [ drop 0 ] bi 2array ]
+ [ [ x-max>> ] [ drop 0 ] bi 2array ] bi line*
+ dup
+ [ [ drop 0 ] [ y-min>> ] bi 2array ]
+ [ [ drop 0 ] [ y-max>> ] bi 2array ] bi line* ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+USING: ui.gadgets.slate ;
+
+M: plot draw-slate ( plot -- plot )
+ 2 glLineWidth
+ draw-axis
+ plot-functions
+ fill-mode
+ 1 glLineWidth ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: add-function ( plot function -- plot )
+ over functions>> swap suffix >>functions ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: x-span ( plot -- span ) [ x-max>> ] [ x-min>> ] bi - ;
+: y-span ( plot -- span ) [ y-max>> ] [ y-min>> ] bi - ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+USING: ui.gestures ui.gadgets ;
+
+: left ( plot -- plot )
+ dup [ x-min>> ] [ x-span 1/10 * ] bi - >>x-min
+ dup [ x-max>> ] [ x-span 1/10 * ] bi - >>x-max
+ dup relayout-1 ;
+
+: right ( plot -- plot )
+ dup [ x-min>> ] [ x-span 1/10 * ] bi + >>x-min
+ dup [ x-max>> ] [ x-span 1/10 * ] bi + >>x-max
+ dup relayout-1 ;
+
+: down ( plot -- plot )
+ dup [ y-min>> ] [ y-span 1/10 * ] bi - >>y-min
+ dup [ y-max>> ] [ y-span 1/10 * ] bi - >>y-max
+ dup relayout-1 ;
+
+: up ( plot -- plot )
+ dup [ y-min>> ] [ y-span 1/10 * ] bi + >>y-min
+ dup [ y-max>> ] [ y-span 1/10 * ] bi + >>y-max
+ dup relayout-1 ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: zoom-in-horizontal ( plot -- plot )
+ dup [ x-min>> ] [ x-span 1/10 * ] bi + >>x-min
+ dup [ x-max>> ] [ x-span 1/10 * ] bi - >>x-max ;
+
+: zoom-in-vertical ( plot -- plot )
+ dup [ y-min>> ] [ y-span 1/10 * ] bi + >>y-min
+ dup [ y-max>> ] [ y-span 1/10 * ] bi - >>y-max ;
+
+: zoom-in ( plot -- plot )
+ zoom-in-horizontal
+ zoom-in-vertical
+ dup relayout-1 ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: zoom-out-horizontal ( plot -- plot )
+ dup [ x-min>> ] [ x-span 1/10 * ] bi - >>x-min
+ dup [ x-max>> ] [ x-span 1/10 * ] bi + >>x-max ;
+
+: zoom-out-vertical ( plot -- plot )
+ dup [ y-min>> ] [ y-span 1/10 * ] bi - >>y-min
+ dup [ y-max>> ] [ y-span 1/10 * ] bi + >>y-max ;
+
+: zoom-out ( plot -- plot )
+ zoom-out-horizontal
+ zoom-out-vertical
+ dup relayout-1 ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+plot
+ H{
+ { T{ mouse-enter } [ request-focus ] }
+ { T{ key-down f f "LEFT" } [ left drop ] }
+ { T{ key-down f f "RIGHT" } [ right drop ] }
+ { T{ key-down f f "DOWN" } [ down drop ] }
+ { T{ key-down f f "UP" } [ up drop ] }
+ { T{ key-down f f "a" } [ zoom-in drop ] }
+ { T{ key-down f f "z" } [ zoom-out drop ] }
+ }
+set-gestures
\ No newline at end of file
--- /dev/null
+Alex Chapman
--- /dev/null
+Alex Chapman
--- /dev/null
+! Copyright (C) 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors alien.c-types combinators kernel locals math math.ranges openal sequences sequences.merged ;
+IN: synth.buffers
+
+TUPLE: buffer sample-freq 8bit? id ;
+
+: <buffer> ( sample-freq 8bit? -- buffer )
+ f buffer boa ;
+
+TUPLE: mono-buffer < buffer data ;
+
+: <mono-buffer> ( sample-freq 8bit? -- buffer )
+ f f mono-buffer boa ;
+
+: <8bit-mono-buffer> ( sample-freq -- buffer ) t <mono-buffer> ;
+: <16bit-mono-buffer> ( sample-freq -- buffer ) f <mono-buffer> ;
+
+TUPLE: stereo-buffer < buffer left-data right-data ;
+
+: <stereo-buffer> ( sample-freq 8bit? -- buffer )
+ f f f stereo-buffer boa ;
+
+: <8bit-stereo-buffer> ( sample-freq -- buffer ) t <stereo-buffer> ;
+: <16bit-stereo-buffer> ( sample-freq -- buffer ) f <stereo-buffer> ;
+
+PREDICATE: 8bit-buffer < buffer 8bit?>> ;
+PREDICATE: 16bit-buffer < buffer 8bit?>> not ;
+INTERSECTION: 8bit-mono-buffer 8bit-buffer mono-buffer ;
+INTERSECTION: 16bit-mono-buffer 16bit-buffer mono-buffer ;
+INTERSECTION: 8bit-stereo-buffer 8bit-buffer stereo-buffer ;
+INTERSECTION: 16bit-stereo-buffer 16bit-buffer stereo-buffer ;
+
+GENERIC: buffer-format ( buffer -- format )
+M: 8bit-mono-buffer buffer-format drop AL_FORMAT_MONO8 ;
+M: 16bit-mono-buffer buffer-format drop AL_FORMAT_MONO16 ;
+M: 8bit-stereo-buffer buffer-format drop AL_FORMAT_STEREO8 ;
+M: 16bit-stereo-buffer buffer-format drop AL_FORMAT_STEREO16 ;
+
+: 8bit-buffer-data ( seq -- data size )
+ [ 128 * >integer 128 + ] uchar-array{ } map-as [ underlying>> ] [ length ] bi ;
+
+: 16bit-buffer-data ( seq -- data size )
+ [ 32768 * >integer ] short-array{ } map-as [ underlying>> ] [ byte-length ] bi ;
+
+: stereo-data ( stereo-buffer -- left right )
+ [ left-data>> ] [ right-data>> ] bi@ ;
+
+: interleaved-stereo-data ( stereo-buffer -- data )
+ stereo-data <2merged> ;
+
+GENERIC: buffer-data ( buffer -- data size )
+M: 8bit-mono-buffer buffer-data data>> 8bit-buffer-data ;
+M: 16bit-mono-buffer buffer-data data>> 16bit-buffer-data ;
+M: 8bit-stereo-buffer buffer-data
+ interleaved-stereo-data 8bit-buffer-data ;
+M: 16bit-stereo-buffer buffer-data
+ interleaved-stereo-data 16bit-buffer-data ;
+
+: telephone-sample-freq 8000 ;
+: half-sample-freq 22050 ;
+: cd-sample-freq 44100 ;
+: digital-sample-freq 48000 ;
+: professional-sample-freq 88200 ;
+
+: send-buffer ( buffer -- buffer )
+ {
+ [ gen-buffer dup [ >>id ] dip ]
+ [ buffer-format ]
+ [ buffer-data ]
+ [ sample-freq>> alBufferData ]
+ } cleave ;
+
+: ?send-buffer ( buffer -- buffer )
+ dup id>> [ send-buffer ] unless ;
+
--- /dev/null
+Alex Chapman
--- /dev/null
+! Copyright (C) 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors arrays kernel namespaces make openal sequences
+synth synth.buffers ;
+IN: synth.example
+
+: play-sine-wave ( freq seconds sample-freq -- )
+ init-openal
+ <16bit-mono-buffer> >sine-wave-buffer send-buffer id>>
+ 1 gen-sources first
+ [ AL_BUFFER rot set-source-param ] [ source-play ] bi
+ check-error ;
+
+: test-instrument1 ( -- harmonics )
+ [
+ 1 0.5 <harmonic> ,
+ 2 0.125 <harmonic> ,
+ 3 0.0625 <harmonic> ,
+ 4 0.03125 <harmonic> ,
+ ] { } make ;
+
+: test-instrument2 ( -- harmonics )
+ [
+ 1 0.25 <harmonic> ,
+ 2 0.25 <harmonic> ,
+ 3 0.25 <harmonic> ,
+ 4 0.25 <harmonic> ,
+ ] { } make ;
+
+: sine-instrument ( -- harmonics )
+ 1 1 <harmonic> 1array ;
+
+: test-note-buffer ( note -- )
+ init-openal
+ test-instrument2 swap cd-sample-freq <16bit-mono-buffer>
+ >note send-buffer id>>
+ 1 gen-sources first [ swap queue-buffer ] [ source-play ] bi
+ check-error ;
--- /dev/null
+Simple sound synthesis using OpenAL.
--- /dev/null
+! Copyright (C) 2008 Alex Chapman
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors kernel locals math math.constants math.functions memoize openal synth.buffers sequences sequences.modified sequences.repeating ;
+IN: synth
+
+MEMO: single-sine-wave ( samples/wave -- seq )
+ pi 2 * over / [ * sin ] curry map ;
+
+: (sine-wave) ( samples/wave n-samples -- seq )
+ [ single-sine-wave ] dip <repeating> ;
+
+: sine-wave ( sample-freq freq seconds -- seq )
+ pick * >integer [ /i ] dip (sine-wave) ;
+
+: >sine-wave-buffer ( freq seconds buffer -- buffer )
+ [ sample-freq>> -rot sine-wave ] keep swap >>data ;
+
+: >silent-buffer ( seconds buffer -- buffer )
+ tuck sample-freq>> * >integer 0 <repetition> >>data ;
+
+TUPLE: harmonic n amplitude ;
+C: <harmonic> harmonic
+
+TUPLE: note hz secs ;
+C: <note> note
+
+: harmonic-freq ( note harmonic -- freq )
+ n>> swap hz>> * ;
+
+:: note-harmonic-data ( harmonic note buffer -- data )
+ buffer sample-freq>> note harmonic harmonic-freq note secs>> sine-wave
+ harmonic amplitude>> <scaled> ;
+
+: >note ( harmonics note buffer -- buffer )
+ dup -roll [ note-harmonic-data ] 2curry map <summed> >>data ;
+
--- /dev/null
+! Copyright (C) 2008 Daniel Ehrenberg.
+! See http://factorcode.org/license.txt for BSD license.
+USING: lexer parser splitting kernel quotations namespaces make
+sequences assocs sequences.lib xml.generator xml.utilities
+xml.data ;
+IN: xml.syntax
+
+: parsed-name ( accum -- accum )
+ scan ":" split1 [ f <name> ] [ <simple-name> ] if* parsed ;
+
+: run-combinator ( accum quot1 quot2 -- accum )
+ >r [ ] like parsed r> [ parsed ] each ;
+
+: parse-tag-contents ( accum contained? -- accum )
+ [ \ contained*, parsed ] [
+ scan-word \ [ =
+ [ POSTPONE: [ \ tag*, parsed ]
+ [ "Expected [ missing" throw ] if
+ ] if ;
+
+DEFER: >>
+
+: attributes-parsed ( accum quot -- accum )
+ [ f parsed ] [
+ >r \ >r parsed r> parsed
+ [ H{ } make-assoc r> swap ] [ parsed ] each
+ ] if-empty ;
+
+: <<
+ parsed-name [
+ \ >> parse-until >quotation
+ attributes-parsed \ contained? get
+ ] with-scope parse-tag-contents ; parsing
+
+: ==
+ \ call parsed parsed-name \ set parsed ; parsing
+
+: //
+ \ contained? on ; parsing
+
+: parse-special ( accum end-token word -- accum )
+ >r parse-tokens " " join parsed r> parsed ;
+
+: <!-- "-->" \ comment, parse-special ; parsing
+
+: <! ">" \ directive, parse-special ; parsing
+
+: <? "?>" \ instruction, parse-special ; parsing
+
+: >xml-document ( seq -- xml )
+ dup first prolog? [ unclip-slice ] [ standard-prolog ] if swap
+ [ tag? ] split-around <xml> ;
+
+DEFER: XML>
+
+: <XML
+ \ XML> [ >quotation ] parse-literal
+ { } parsed \ make parsed \ >xml-document parsed ; parsing
DLL_EXTENSION = .dylib
ifdef X11
- LIBS = -lm -framework Foundation $(X11_UI_LIBS) -Wl,-dylib_file,/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib
+ LIBS = -lm -framework Cocoa $(X11_UI_LIBS) -Wl,-dylib_file,/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib
else
LIBS = -lm -framework Cocoa -framework AppKit
endif
include vm/Config.macosx
include vm/Config.x86.64
-CFLAGS += -arch x86_64
+CFLAGS += -m64
PLAF_DLL_OBJS += vm/cpu-x86.64.o
+CFLAGS += -DFACTOR_64
}
#define BIGNUM_REDUCE_LENGTH(source, length) \
- source = reallot_array(source,length + 1,0)
+ source = reallot_array(source,length + 1)
/* allocates memory */
bignum_type
/* Copy all literals referenced from a code block to newspace */
void collect_literals_step(F_COMPILED *compiled, CELL code_start, CELL literals_start)
{
- CELL scan;
- CELL literal_end = literals_start + compiled->literals_length;
+ if(collecting_gen >= compiled->last_scan)
+ {
+ CELL scan;
+ CELL literal_end = literals_start + compiled->literals_length;
+
+ if(collecting_accumulation_gen_p())
+ compiled->last_scan = collecting_gen;
+ else
+ compiled->last_scan = collecting_gen + 1;
+
+ for(scan = literals_start; scan < literal_end; scan += CELLS)
+ copy_handle((CELL*)scan);
+
+ if(compiled->relocation != F)
+ {
+ copy_handle(&compiled->relocation);
+
+ F_BYTE_ARRAY *relocation = untag_object(compiled->relocation);
- copy_handle(&compiled->relocation);
+ F_REL *rel = (F_REL *)(relocation + 1);
+ F_REL *rel_end = (F_REL *)((char *)rel + byte_array_capacity(relocation));
- for(scan = literals_start; scan < literal_end; scan += CELLS)
- copy_handle((CELL*)scan);
+ while(rel < rel_end)
+ {
+ if(REL_TYPE(rel) == RT_IMMEDIATE)
+ {
+ CELL offset = rel->offset + code_start;
+ F_FIXNUM absolute_value = get(CREF(literals_start,REL_ARGUMENT(rel)));
+ apply_relocation(REL_CLASS(rel),offset,absolute_value);
+ }
+
+ rel++;
+ }
+ }
+
+ flush_icache(code_start,literals_start - code_start);
+ }
}
/* Copy literals referenced from all code blocks to newspace */
break;
}
- fprintf(stderr,"%lx %lx %s\n",(CELL)scan,scan->size,status);
+ print_cell_hex((CELL)scan); print_string(" ");
+ print_cell_hex(scan->size); print_string(" ");
+ print_string(status); print_string("\n");
scan = next_block(heap,scan);
}
- printf("%ld bytes of relocation data\n",size);
+ print_cell(size); print_string(" bytes of relocation data\n");
}
/* Compute where each block is going to go, after compaction */
/* Free all unreachable code blocks */
gc();
- fprintf(stderr,"*** Code heap compaction...\n");
- fflush(stderr);
-
/* Figure out where the code heap blocks are going to end up */
CELL size = compute_heap_forwarding(&code_heap);
general_error(ERROR_UNDEFINED_SYMBOL,F,F,NULL);
}
-#define CREF(array,i) ((CELL)(array) + CELLS * (i))
-
INLINE CELL get_literal(CELL literals_start, CELL num)
{
return get(CREF(literals_start,num));
INLINE CELL compute_code_rel(F_REL *rel,
CELL code_start, CELL literals_start)
{
+ CELL obj;
+
switch(REL_TYPE(rel))
{
case RT_PRIMITIVE:
return (CELL)primitives[REL_ARGUMENT(rel)];
case RT_DLSYM:
return (CELL)get_rel_symbol(rel,literals_start);
- case RT_LITERAL:
- return CREF(literals_start,REL_ARGUMENT(rel));
case RT_IMMEDIATE:
return get(CREF(literals_start,REL_ARGUMENT(rel)));
case RT_XT:
- return (CELL)untag_word(get(CREF(literals_start,REL_ARGUMENT(rel))))->xt;
+ obj = get(CREF(literals_start,REL_ARGUMENT(rel)));
+ if(type_of(obj) == WORD_TYPE)
+ return (CELL)untag_word(obj)->xt;
+ else
+ return (CELL)untag_quotation(obj)->xt;
case RT_HERE:
return rel->offset + code_start + (short)REL_ARGUMENT(rel);
case RT_LABEL:
/* Perform all fixups on a code block */
void relocate_code_block(F_COMPILED *compiled, CELL code_start, CELL literals_start)
{
+ compiled->last_scan = NURSERY;
+
if(compiled->relocation != F)
{
F_BYTE_ARRAY *relocation = untag_object(compiled->relocation);
CELL used, total_free, max_free;
heap_usage(&code_heap,&used,&total_free,&max_free);
- fprintf(stderr,"Code heap stats:\n");
- fprintf(stderr,"Used: %ld\n",used);
- fprintf(stderr,"Total free space: %ld\n",total_free);
- fprintf(stderr,"Largest free block: %ld\n",max_free);
+ print_string("Code heap stats:\n");
+ print_string("Used: "); print_cell(used); nl();
+ print_string("Total free space: "); print_cell(total_free); nl();
+ print_string("Largest free block: "); print_cell(max_free); nl();
fatal_error("Out of memory in add-compiled-block",0);
}
}
/* compiled header */
F_COMPILED *header = (void *)here;
header->type = type;
+ header->last_scan = NURSERY;
header->code_length = code_length;
header->literals_length = literals_length;
header->relocation = relocation;
RT_PRIMITIVE,
/* arg is a literal table index, holding an array pair (symbol/dll) */
RT_DLSYM,
- /* an indirect literal from the word's literal table */
- RT_LITERAL,
/* a pointer to a compiled word reference */
RT_DISPATCH,
/* a compiled word reference */
unsigned int offset;
} F_REL;
+#define CREF(array,i) ((CELL)(array) + CELLS * (i))
+
+void apply_relocation(CELL class, CELL offset, F_FIXNUM absolute_value);
+
void relocate_code_block(F_COMPILED *relocating, CELL code_start, CELL literals_start);
void default_word_code(F_WORD *word, bool relocate);
DEF(void,lazy_jit_compile,(CELL quot)):
mov r1,sp /* save stack pointer */
PROLOGUE
- bl MANGLE(primitive_jit_compile)
+ bl MANGLE(lazy_jit_compile_impl)
EPILOGUE
JUMP_QUOT /* call the quotation */
in the public domain. */
#include "asm.h"
+#define DS_REG r29
+
+DEF(void,primitive_fixnum_add,(void)):
+ lwz r3,0(DS_REG)
+ lwz r4,-4(DS_REG)
+ subi DS_REG,DS_REG,4
+ li r0,0
+ mtxer r0
+ addo. r5,r3,r4
+ bso add_overflow
+ stw r5,0(DS_REG)
+ blr
+add_overflow:
+ b MANGLE(overflow_fixnum_add)
+
+DEF(void,primitive_fixnum_subtract,(void)):
+ lwz r3,-4(DS_REG)
+ lwz r4,0(DS_REG)
+ subi DS_REG,DS_REG,4
+ li r0,0
+ mtxer r0
+ subfo. r5,r4,r3
+ bso sub_overflow
+ stw r5,0(DS_REG)
+ blr
+sub_overflow:
+ b MANGLE(overflow_fixnum_subtract)
+
+DEF(void,primitive_fixnum_multiply,(void)):
+ lwz r3,0(DS_REG)
+ lwz r4,-4(DS_REG)
+ subi DS_REG,DS_REG,4
+ srawi r3,r3,3
+ mullwo. r5,r3,r4
+ bso multiply_overflow
+ stw r5,0(DS_REG)
+ blr
+multiply_overflow:
+ srawi r4,r4,3
+ b MANGLE(overflow_fixnum_multiply)
+
/* Note that the XT is passed to the quotation in r11 */
#define CALL_OR_JUMP_QUOT \
lwz r11,9(r3) /* load quotation-xt slot */ XX \
DEF(void,lazy_jit_compile,(CELL quot)):
mr r4,r1 /* save stack pointer */
PROLOGUE
- bl MANGLE(primitive_jit_compile)
+ bl MANGLE(lazy_jit_compile_impl)
EPILOGUE
JUMP_QUOT /* call the quotation */
#define NV_TEMP_REG %ebx
+#define ARITH_TEMP_1 %ebp
+#define ARITH_TEMP_2 %ebx
+#define DIV_RESULT %eax
+
#define CELL_SIZE 4
#define STACK_PADDING 12
#define NV_TEMP_REG %rbp
+#define ARITH_TEMP_1 %r8
+#define ARITH_TEMP_2 %r9
+#define DIV_RESULT %rax
+
#ifdef WINDOWS
#define ARG0 %rcx
+DEF(void,primitive_fixnum_add,(void)):
+ mov (DS_REG),ARG0
+ mov -CELL_SIZE(DS_REG),ARG1
+ sub $CELL_SIZE,DS_REG
+ mov ARG1,ARITH_TEMP_1
+ add ARG0,ARITH_TEMP_1
+ jo MANGLE(overflow_fixnum_add)
+ mov ARITH_TEMP_1,(DS_REG)
+ ret
+
+DEF(void,primitive_fixnum_subtract,(void)):
+ mov (DS_REG),ARG1
+ mov -CELL_SIZE(DS_REG),ARG0
+ sub $CELL_SIZE,DS_REG
+ mov ARG0,ARITH_TEMP_1
+ sub ARG1,ARITH_TEMP_1
+ jo MANGLE(overflow_fixnum_subtract)
+ mov ARITH_TEMP_1,(DS_REG)
+ ret
+
+DEF(void,primitive_fixnum_multiply,(void)):
+ mov (DS_REG),ARITH_TEMP_1
+ mov ARITH_TEMP_1,DIV_RESULT
+ mov -CELL_SIZE(DS_REG),ARITH_TEMP_2
+ sar $3,ARITH_TEMP_2
+ sub $CELL_SIZE,DS_REG
+ imul ARITH_TEMP_2
+ jo multiply_overflow
+ mov DIV_RESULT,(DS_REG)
+ ret
+multiply_overflow:
+ sar $3,ARITH_TEMP_1
+ mov ARITH_TEMP_1,ARG0
+ mov ARITH_TEMP_2,ARG1
+ jmp MANGLE(overflow_fixnum_multiply)
+
DEF(F_FASTCALL void,c_to_factor,(CELL quot)):
PUSH_NONVOLATILE
mov ARG0,NV_TEMP_REG
DEF(FASTCALL void,lazy_jit_compile,(CELL quot)):
mov STACK_REG,ARG1 /* Save stack pointer */
sub $STACK_PADDING,STACK_REG
- call MANGLE(primitive_jit_compile)
+ call MANGLE(lazy_jit_compile_impl)
mov RETURN_REG,ARG0 /* No-op on 32-bit */
add $STACK_PADDING,STACK_REG
jmp *QUOT_XT_OFFSET(ARG0) /* Call the quotation */
#include "master.h"
-#define ALLOC_DATA_HEAP "alloc_data_heap: gens=%ld, young_size=%ld, aging_size=%ld, tenured_size=%ld\n"
-#define GC_REQUESTED "garbage_collection: growing_data_heap=%d, requested_bytes=%ld\n"
-#define BEGIN_GC "begin_gc: growing_data_heap=%d, collecting_gen=%ld\n"
-#define END_GC "end_gc: gc_elapsed=%ld\n"
-#define END_AGING_GC "end_gc: aging_collections=%ld, cards_scanned=%ld\n"
-#define END_NURSERY_GC "end_gc: nursery_collections=%ld, cards_scanned=%ld\n"
-
-/* #define GC_DEBUG */
-
-#ifdef GC_DEBUG
- #define GC_PRINT printf
-#else
- INLINE void GC_PRINT() { }
-#endif
-
CELL init_zone(F_ZONE *z, CELL size, CELL start)
{
z->size = size;
CELL aging_size,
CELL tenured_size)
{
- GC_PRINT(ALLOC_DATA_HEAP,gens,young_size,aging_size,tenured_size);
-
young_size = align(young_size,DECK_SIZE);
aging_size = align(aging_size,DECK_SIZE);
tenured_size = align(tenured_size,DECK_SIZE);
data_heap->gen_count = gens;
CELL total_size;
- if(data_heap->gen_count == 1)
- total_size = 2 * tenured_size;
- else if(data_heap->gen_count == 2)
+ if(data_heap->gen_count == 2)
total_size = young_size + 2 * tenured_size;
else if(data_heap->gen_count == 3)
total_size = young_size + 2 * aging_size + 2 * tenured_size;
/* NOTE: reverse order due to heap layout. */
F_CARD *first_card = ADDR_TO_CARD(data_heap->generations[to].start);
F_CARD *last_card = ADDR_TO_CARD(data_heap->generations[from].end);
- F_CARD *ptr;
- for(ptr = first_card; ptr < last_card; ptr++) *ptr = 0;
+ memset(first_card,0,last_card - first_card);
}
void clear_decks(CELL from, CELL to)
/* NOTE: reverse order due to heap layout. */
F_DECK *first_deck = ADDR_TO_DECK(data_heap->generations[to].start);
F_DECK *last_deck = ADDR_TO_DECK(data_heap->generations[from].end);
- F_DECK *ptr;
- for(ptr = first_deck; ptr < last_deck; ptr++) *ptr = 0;
+ memset(first_deck,0,last_deck - first_deck);
}
void clear_allot_markers(CELL from, CELL to)
/* NOTE: reverse order due to heap layout. */
F_CARD *first_card = ADDR_TO_ALLOT_MARKER(data_heap->generations[to].start);
F_CARD *last_card = ADDR_TO_ALLOT_MARKER(data_heap->generations[from].end);
- F_CARD *ptr;
- for(ptr = first_card; ptr < last_card; ptr++) *ptr = INVALID_ALLOT_MARKER;
+ memset(first_card,INVALID_ALLOT_MARKER,last_card - first_card);
}
void set_data_heap(F_DATA_HEAP *data_heap_)
/* Scan all the objects in the card */
void collect_card(F_CARD *ptr, CELL gen, CELL here)
{
- CELL offset = CARD_OFFSET(ptr);
+ CELL card_scan = (CELL)CARD_TO_ADDR(ptr) + CARD_OFFSET(ptr);
+ CELL card_end = (CELL)CARD_TO_ADDR(ptr + 1);
- if(offset != INVALID_ALLOT_MARKER)
- {
- if(offset & TAG_MASK)
- critical_error("Bad card",(CELL)ptr);
-
- CELL card_scan = (CELL)CARD_TO_ADDR(ptr) + offset;
- CELL card_end = (CELL)CARD_TO_ADDR(ptr + 1);
+ if(here < card_end)
+ card_end = here;
- while(card_scan < card_end && card_scan < here)
- card_scan = collect_next(card_scan);
+ collect_next_loop(card_scan,&card_end);
- cards_scanned++;
- }
+ cards_scanned++;
}
void collect_card_deck(F_DECK *deck, CELL gen, F_CARD mask, F_CARD unmask)
old->new references */
void collect_cards(void)
{
- GC_PRINT("Collect cards\n");
-
int i;
for(i = collecting_gen + 1; i < data_heap->gen_count; i++)
collect_gen_cards(i);
CELL top = (CELL)stacks->callstack_top;
CELL bottom = (CELL)stacks->callstack_bottom;
- GC_PRINT("Collect callstack %ld %ld\n",top,bottom);
iterate_callstack(top,bottom,collect_stack_frame);
- GC_PRINT("Done\n");
}
}
the user environment and extra roots registered with REGISTER_ROOT */
void collect_roots(void)
{
- GC_PRINT("Collect roots\n");
copy_handle(&T);
copy_handle(&bignum_zero);
copy_handle(&bignum_pos_one);
/* Given a pointer to oldspace, copy it to newspace */
INLINE void *copy_untagged_object(void *pointer, CELL size)
{
- void *newpointer;
if(newspace->here + size >= newspace->end)
longjmp(gc_jmp,1);
allot_barrier(newspace->here);
- newpointer = allot_zone(newspace,size);
+ void *newpointer = allot_zone(newspace,size);
F_GC_STATS *s = &gc_stats[collecting_gen];
s->object_count++;
we ignore. */
CELL binary_payload_start(CELL pointer)
{
+ F_TUPLE *tuple;
+ F_TUPLE_LAYOUT *layout;
+
switch(untag_header(get(pointer)))
{
/* these objects do not refer to other objects at all */
case STRING_TYPE:
return sizeof(F_STRING);
/* everything else consists entirely of pointers */
+ case ARRAY_TYPE:
+ return array_size(array_capacity((F_ARRAY*)pointer));
+ case TUPLE_TYPE:
+ tuple = untag_object(pointer);
+ layout = untag_object(tuple->layout);
+ return tuple_size(layout);
+ case RATIO_TYPE:
+ return sizeof(F_RATIO);
+ case COMPLEX_TYPE:
+ return sizeof(F_COMPLEX);
+ case WRAPPER_TYPE:
+ return sizeof(F_WRAPPER);
default:
- return unaligned_object_size(pointer);
+ critical_error("Invalid header",pointer);
+ return -1; /* can't happen */
}
}
}
}
-/* This function is performance-critical */
-CELL collect_next(CELL scan)
+CELL collect_next_nursery(CELL scan)
{
CELL *obj = (CELL *)scan;
CELL *end = (CELL *)(scan + binary_payload_start(scan));
- obj++;
-
- CELL newspace_start = newspace->start;
- CELL newspace_end = newspace->end;
-
- if(HAVE_NURSERY_P && collecting_gen == NURSERY)
+ if(obj != end)
{
+ obj++;
+
CELL nursery_start = nursery.start;
CELL nursery_end = nursery.end;
*obj = copy_object(pointer);
}
}
- else if(HAVE_AGING_P && collecting_gen == AGING)
+
+ return scan + untagged_object_size(scan);
+}
+
+CELL collect_next_aging(CELL scan)
+{
+ CELL *obj = (CELL *)scan;
+ CELL *end = (CELL *)(scan + binary_payload_start(scan));
+
+ if(obj != end)
{
- F_ZONE *tenured = &data_heap->generations[TENURED];
+ obj++;
+
+ CELL tenured_start = data_heap->generations[TENURED].start;
+ CELL tenured_end = data_heap->generations[TENURED].end;
- CELL tenured_start = tenured->start;
- CELL tenured_end = tenured->end;
+ CELL newspace_start = newspace->start;
+ CELL newspace_end = newspace->end;
for(; obj < end; obj++)
{
*obj = copy_object(pointer);
}
}
- else if(collecting_gen == TENURED)
+
+ return scan + untagged_object_size(scan);
+}
+
+/* This function is performance-critical */
+CELL collect_next_tenured(CELL scan)
+{
+ CELL *obj = (CELL *)scan;
+ CELL *end = (CELL *)(scan + binary_payload_start(scan));
+
+ if(obj != end)
{
+ obj++;
+
+ CELL newspace_start = newspace->start;
+ CELL newspace_end = newspace->end;
+
for(; obj < end; obj++)
{
CELL pointer = *obj;
- if(!immediate_p(pointer)
- && !(pointer >= newspace_start && pointer < newspace_end))
+ if(!immediate_p(pointer) && !(pointer >= newspace_start && pointer < newspace_end))
*obj = copy_object(pointer);
}
-
- do_code_slots(scan);
}
- else
- critical_error("Bug in collect_next",0);
+
+ do_code_slots(scan);
return scan + untagged_object_size(scan);
}
+void collect_next_loop(CELL scan, CELL *end)
+{
+ if(HAVE_NURSERY_P && collecting_gen == NURSERY)
+ {
+ while(scan < *end)
+ scan = collect_next_nursery(scan);
+ }
+ else if(HAVE_AGING_P && collecting_gen == AGING)
+ {
+ while(scan < *end)
+ scan = collect_next_aging(scan);
+ }
+ else if(collecting_gen == TENURED)
+ {
+ while(scan < *end)
+ scan = collect_next_tenured(scan);
+ }
+}
+
INLINE void reset_generation(CELL i)
{
F_ZONE *z = (i == NURSERY ? &nursery : &data_heap->generations[i]);
so we set the newspace so the next generation. */
newspace = &data_heap->generations[collecting_gen + 1];
}
-
-#ifdef GC_DEBUG
- printf("\n");
- dump_generations();
- printf("Newspace: ");
- dump_zone(newspace);
- printf("\n");
-#endif
}
void end_gc(CELL gc_elapsed)
if(collecting_gen != NURSERY)
reset_generations(NURSERY,collecting_gen - 1);
}
+ else if(HAVE_NURSERY_P && collecting_gen == NURSERY)
+ {
+ nursery.here = nursery.start;
+ }
else
{
/* all generations up to and including the one
return;
}
- GC_PRINT(GC_REQUESTED,growing_data_heap_,requested_bytes);
-
- s64 start = current_millis();
+ s64 start = current_micros();
performing_gc = true;
growing_data_heap = growing_data_heap_;
}
}
- GC_PRINT(BEGIN_GC,growing_data_heap,collecting_gen);
begin_gc(requested_bytes);
/* initialize chase pointer */
/* collect objects referenced from older generations */
collect_cards();
- if(collecting_gen != TENURED)
+ /* don't scan code heap unless it has pointers to this
+ generation or younger */
+ if(collecting_gen >= last_code_heap_scan)
{
- /* don't scan code heap unless it has pointers to this
- generation or younger */
- if(collecting_gen >= last_code_heap_scan)
+ if(collecting_gen != TENURED)
{
+
/* if we are doing code GC, then we will copy over
literals from any code block which gets marked as live.
if we are not doing code GC, just consider all literals
code_heap_scans++;
collect_literals();
-
- if(collecting_accumulation_gen_p())
- last_code_heap_scan = collecting_gen;
- else
- last_code_heap_scan = collecting_gen + 1;
}
+
+ if(collecting_accumulation_gen_p())
+ last_code_heap_scan = collecting_gen;
+ else
+ last_code_heap_scan = collecting_gen + 1;
}
- while(scan < newspace->here)
- scan = collect_next(scan);
+ collect_next_loop(scan,&newspace->here);
- CELL gc_elapsed = (current_millis() - start);
+ CELL gc_elapsed = (current_micros() - start);
- GC_PRINT(END_GC,gc_elapsed);
end_gc(gc_elapsed);
performing_gc = false;
GROWABLE_ARRAY(stats);
CELL i;
- CELL total_gc_time = 0;
+ u64 total_gc_time = 0;
for(i = 0; i < MAX_GEN_COUNT; i++)
{
F_GC_STATS *s = &gc_stats[i];
GROWABLE_ARRAY_ADD(stats,allot_cell(s->collections));
- GROWABLE_ARRAY_ADD(stats,allot_cell(s->gc_time));
- GROWABLE_ARRAY_ADD(stats,allot_cell(s->max_gc_time));
+ GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(s->gc_time)));
+ GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(s->max_gc_time)));
GROWABLE_ARRAY_ADD(stats,allot_cell(s->collections == 0 ? 0 : s->gc_time / s->collections));
GROWABLE_ARRAY_ADD(stats,allot_cell(s->object_count));
GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(s->bytes_copied)));
total_gc_time += s->gc_time;
}
- GROWABLE_ARRAY_ADD(stats,allot_cell(total_gc_time));
+ GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(total_gc_time)));
GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(cards_scanned)));
GROWABLE_ARRAY_ADD(stats,tag_bignum(long_long_to_bignum(decks_scanned)));
GROWABLE_ARRAY_ADD(stats,allot_cell(code_heap_scans));
}
gc();
+
+ compile_all_words();
}
CELL find_all_words(void)
/* the oldest generation */
#define TENURED (data_heap->gen_count-1)
+#define MIN_GEN_COUNT 1
#define MAX_GEN_COUNT 3
/* used during garbage collection only */
/* statistics */
typedef struct {
CELL collections;
- CELL gc_time;
- CELL max_gc_time;
+ u64 gc_time;
+ u64 max_gc_time;
CELL object_count;
u64 bytes_copied;
} F_GC_STATS;
return object;
}
-CELL collect_next(CELL scan);
+void collect_next_loop(CELL scan, CELL *end);
void primitive_gc(void);
void primitive_gc_stats(void);
if(type_of(word->vocabulary) == STRING_TYPE)
{
print_chars(untag_string(word->vocabulary));
- printf(":");
+ print_string(":");
}
if(type_of(word->name) == STRING_TYPE)
print_chars(untag_string(word->name));
else
{
- printf("#<not a string: ");
+ print_string("#<not a string: ");
print_nested_obj(word->name,nesting);
- printf(">");
+ print_string(">");
}
}
-void print_string(F_STRING* str)
+void print_factor_string(F_STRING* str)
{
putchar('"');
print_chars(str);
for(i = 0; i < length; i++)
{
- printf(" ");
+ print_string(" ");
print_nested_obj(array_nth(array,i),nesting);
}
if(trimmed)
- printf("...");
+ print_string("...");
}
void print_tuple(F_TUPLE* tuple, CELL nesting)
F_TUPLE_LAYOUT *layout = untag_object(tuple->layout);
CELL length = to_fixnum(layout->size);
- printf(" ");
+ print_string(" ");
print_nested_obj(layout->class,nesting);
CELL i;
for(i = 0; i < length; i++)
{
- printf(" ");
+ print_string(" ");
print_nested_obj(tuple_nth(tuple,i),nesting);
}
if(trimmed)
- printf("...");
+ print_string("...");
}
void print_nested_obj(CELL obj, F_FIXNUM nesting)
{
if(nesting <= 0 && !full_output)
{
- printf(" ... ");
+ print_string(" ... ");
return;
}
switch(type_of(obj))
{
case FIXNUM_TYPE:
- printf("%ld",untag_fixnum_fast(obj));
+ print_fixnum(untag_fixnum_fast(obj));
break;
case WORD_TYPE:
print_word(untag_word(obj),nesting - 1);
break;
case STRING_TYPE:
- print_string(untag_string(obj));
+ print_factor_string(untag_string(obj));
break;
case F_TYPE:
- printf("f");
+ print_string("f");
break;
case TUPLE_TYPE:
- printf("T{");
+ print_string("T{");
print_tuple(untag_object(obj),nesting - 1);
- printf(" }");
+ print_string(" }");
break;
case ARRAY_TYPE:
- printf("{");
+ print_string("{");
print_array(untag_object(obj),nesting - 1);
- printf(" }");
+ print_string(" }");
break;
case QUOTATION_TYPE:
- printf("[");
+ print_string("[");
quot = untag_object(obj);
print_array(untag_object(quot->array),nesting - 1);
- printf(" ]");
+ print_string(" ]");
break;
default:
- printf("#<type %ld @ %lx>",type_of(obj),obj);
+ print_string("#<type "); print_cell(type_of(obj)); print_string(" @ "); print_cell_hex(obj); print_string(">");
break;
}
}
for(; start <= end; start += CELLS)
{
print_obj(get(start));
- printf("\n");
+ nl();
}
}
void print_datastack(void)
{
- printf("==== DATA STACK:\n");
+ print_string("==== DATA STACK:\n");
print_objects(ds_bot,ds);
}
void print_retainstack(void)
{
- printf("==== RETAIN STACK:\n");
+ print_string("==== RETAIN STACK:\n");
print_objects(rs_bot,rs);
}
void print_stack_frame(F_STACK_FRAME *frame)
{
print_obj(frame_executing(frame));
- printf("\n");
+ print_string("\n");
print_obj(frame_scan(frame));
- printf("\n");
- printf("%lx\n",(CELL)frame_executing(frame));
- printf("%lx\n",(CELL)frame->xt);
+ print_string("\n");
+ print_cell_hex((CELL)frame_executing(frame));
+ print_string(" ");
+ print_cell_hex((CELL)frame->xt);
+ print_string("\n");
}
void print_callstack(void)
{
- printf("==== CALL STACK:\n");
+ print_string("==== CALL STACK:\n");
CELL bottom = (CELL)stack_chain->callstack_bottom;
CELL top = (CELL)stack_chain->callstack_top;
iterate_callstack(top,bottom,print_stack_frame);
void dump_cell(CELL cell)
{
- printf("%08lx: ",cell);
+ print_cell_hex_pad(cell); print_string(": ");
cell = get(cell);
- printf("%08lx tag %ld",cell,TAG(cell));
+ print_cell_hex_pad(cell); print_string(" tag "); print_cell(TAG(cell));
switch(TAG(cell))
{
case BIGNUM_TYPE:
case FLOAT_TYPE:
if(cell == F)
- printf(" -- F");
+ print_string(" -- F");
else if(cell < TYPE_COUNT<<TAG_BITS)
- printf(" -- possible header: %ld",cell>>TAG_BITS);
+ {
+ print_string(" -- possible header: ");
+ print_cell(cell>>TAG_BITS);
+ }
else if(cell >= data_heap->segment->start
&& cell < data_heap->segment->end)
{
CELL header = get(UNTAG(cell));
CELL type = header>>TAG_BITS;
- printf(" -- object; ");
+ print_string(" -- object; ");
if(TAG(header) == 0 && type < TYPE_COUNT)
- printf(" type %ld",type);
+ {
+ print_string(" type "); print_cell(type);
+ }
else
- printf(" header corrupt");
+ print_string(" header corrupt");
}
break;
}
- printf("\n");
+ nl();
}
void dump_memory(CELL from, CELL to)
void dump_zone(F_ZONE *z)
{
- printf("start=%ld, size=%ld, here=%ld\n",
- z->start,z->size,z->here - z->start);
+ print_string("Start="); print_cell(z->start);
+ print_string(", size="); print_cell(z->size);
+ print_string(", here="); print_cell(z->here - z->start); nl();
}
void dump_generations(void)
{
- int i;
+ CELL i;
- printf("Nursery: ");
+ print_string("Nursery: ");
dump_zone(&nursery);
for(i = 1; i < data_heap->gen_count; i++)
{
- printf("Generation %d: ",i);
+ print_string("Generation "); print_cell(i); print_string(": ");
dump_zone(&data_heap->generations[i]);
}
for(i = 0; i < data_heap->gen_count; i++)
{
- printf("Semispace %d: ",i);
+ print_string("Semispace "); print_cell(i); print_string(": ");
dump_zone(&data_heap->semispaces[i]);
}
- printf("Cards: base=%lx, size=%lx\n",
- (CELL)data_heap->cards,
- (CELL)(data_heap->cards_end - data_heap->cards));
+ print_string("Cards: base=");
+ print_cell((CELL)data_heap->cards);
+ print_string(", size=");
+ print_cell((CELL)(data_heap->cards_end - data_heap->cards));
+ nl();
}
void dump_objects(F_FIXNUM type)
{
if(type == -1 || type_of(obj) == type)
{
- printf("%lx ",obj);
+ print_cell_hex_pad(obj);
+ print_string(" ");
print_nested_obj(obj,2);
- printf("\n");
+ nl();
}
}
{
if(look_for == *scan)
{
- printf("%lx ",obj);
+ print_cell_hex_pad(obj);
+ print_string(" ");
print_nested_obj(obj,2);
- printf("\n");
+ nl();
}
}
if(look_for == get(scan))
{
- printf("%lx ",obj);
+ print_cell_hex_pad(obj);
+ print_string(" ");
print_nested_obj(obj,2);
- printf("\n");
+ nl();
}
}
}
{
if(fep_disabled)
{
- printf("Low level debugger disabled\n");
+ print_string("Low level debugger disabled\n");
exit(1);
}
- open_console();
-
- printf("Starting low level debugger...\n");
- printf(" Basic commands:\n");
- printf("q -- continue executing Factor - NOT SAFE\n");
- printf("im -- save image to fep.image\n");
- printf("x -- exit Factor\n");
- printf(" Advanced commands:\n");
- printf("d <addr> <count> -- dump memory\n");
- printf("u <addr> -- dump object at tagged <addr>\n");
- printf(". <addr> -- print object at tagged <addr>\n");
- printf("t -- toggle output trimming\n");
- printf("s r -- dump data, retain stacks\n");
- printf(".s .r .c -- print data, retain, call stacks\n");
- printf("e -- dump environment\n");
- printf("g -- dump generations\n");
- printf("card <addr> -- print card containing address\n");
- printf("addr <card> -- print address containing card\n");
- printf("data -- data heap dump\n");
- printf("words -- words dump\n");
- printf("tuples -- tuples dump\n");
- printf("refs <addr> -- find data heap references to object\n");
- printf("push <addr> -- push object on data stack - NOT SAFE\n");
- printf("code -- code heap dump\n");
+ /* open_console(); */
+
+ print_string("Starting low level debugger...\n");
+ print_string(" Basic commands:\n");
+ print_string("q -- continue executing Factor - NOT SAFE\n");
+ print_string("im -- save image to fep.image\n");
+ print_string("x -- exit Factor\n");
+ print_string(" Advanced commands:\n");
+ print_string("d <addr> <count> -- dump memory\n");
+ print_string("u <addr> -- dump object at tagged <addr>\n");
+ print_string(". <addr> -- print object at tagged <addr>\n");
+ print_string("t -- toggle output trimming\n");
+ print_string("s r -- dump data, retain stacks\n");
+ print_string(".s .r .c -- print data, retain, call stacks\n");
+ print_string("e -- dump environment\n");
+ print_string("g -- dump generations\n");
+ print_string("card <addr> -- print card containing address\n");
+ print_string("addr <card> -- print address containing card\n");
+ print_string("data -- data heap dump\n");
+ print_string("words -- words dump\n");
+ print_string("tuples -- tuples dump\n");
+ print_string("refs <addr> -- find data heap references to object\n");
+ print_string("push <addr> -- push object on data stack - NOT SAFE\n");
+ print_string("code -- code heap dump\n");
bool seen_command = false;
{
char cmd[1024];
- printf("READY\n");
+ print_string("READY\n");
fflush(stdout);
if(scanf("%1000s",cmd) <= 0)
if(strcmp(cmd,"d") == 0)
{
- CELL addr, count;
- scanf("%lx %lx",&addr,&count);
+ CELL addr = read_cell_hex();
+ scanf(" ");
+ CELL count = read_cell_hex();
dump_memory(addr,addr+count);
}
- if(strcmp(cmd,"u") == 0)
+ else if(strcmp(cmd,"u") == 0)
{
- CELL addr, count;
- scanf("%lx",&addr);
- count = object_size(addr);
+ CELL addr = read_cell_hex();
+ CELL count = object_size(addr);
dump_memory(addr,addr+count);
}
else if(strcmp(cmd,".") == 0)
{
- CELL addr;
- scanf("%lx",&addr);
+ CELL addr = read_cell_hex();
print_obj(addr);
- printf("\n");
+ print_string("\n");
}
else if(strcmp(cmd,"t") == 0)
full_output = !full_output;
dump_generations();
else if(strcmp(cmd,"card") == 0)
{
- CELL addr;
- scanf("%lx",&addr);
- printf("%lx\n",(CELL)ADDR_TO_CARD(addr));
+ CELL addr = read_cell_hex();
+ print_cell_hex((CELL)ADDR_TO_CARD(addr));
+ nl();
}
else if(strcmp(cmd,"addr") == 0)
{
- CELL card;
- scanf("%lx",&card);
- printf("%lx\n",(CELL)CARD_TO_ADDR(card));
+ CELL card = read_cell_hex();
+ print_cell_hex((CELL)CARD_TO_ADDR(card));
+ nl();
}
else if(strcmp(cmd,"q") == 0)
return;
dump_objects(-1);
else if(strcmp(cmd,"refs") == 0)
{
- CELL addr;
- scanf("%lx",&addr);
- printf("Data heap references:\n");
+ CELL addr = read_cell_hex();
+ print_string("Data heap references:\n");
find_data_references(addr);
- printf("Code heap references:\n");
+ print_string("Code heap references:\n");
find_code_references(addr);
- printf("\n");
+ nl();
}
else if(strcmp(cmd,"words") == 0)
dump_objects(WORD_TYPE);
dump_objects(TUPLE_TYPE);
else if(strcmp(cmd,"push") == 0)
{
- CELL addr;
- scanf("%lx",&addr);
+ CELL addr = read_cell_hex();
dpush(addr);
}
else if(strcmp(cmd,"code") == 0)
dump_heap(&code_heap);
else
- printf("unknown command\n");
+ print_string("unknown command\n");
}
}
void primitive_die(void)
{
- fprintf(stderr,"The die word was called by the library. Unless you called it yourself,\n");
- fprintf(stderr,"you have triggered a bug in Factor. Please report.\n");
+ print_string("The die word was called by the library. Unless you called it yourself,\n");
+ print_string("you have triggered a bug in Factor. Please report.\n");
factorbug();
}
void out_of_memory(void)
{
- fprintf(stderr,"Out of memory\n\n");
+ print_string("Out of memory\n\n");
dump_generations();
exit(1);
}
void fatal_error(char* msg, CELL tagged)
{
- fprintf(stderr,"fatal_error: %s %lx\n",msg,tagged);
+ print_string("fatal_error: "); print_string(msg);
+ print_string(": "); print_cell_hex(tagged); nl();
exit(1);
}
void critical_error(char* msg, CELL tagged)
{
- fprintf(stderr,"You have triggered a bug in Factor. Please report.\n");
- fprintf(stderr,"critical_error: %s %lx\n",msg,tagged);
+ print_string("You have triggered a bug in Factor. Please report.\n");
+ print_string("critical_error: "); print_string(msg);
+ print_string(": "); print_cell_hex(tagged); nl();
factorbug();
}
crash. */
else
{
- printf("You have triggered a bug in Factor. Please report.\n");
- printf("early_error: ");
+ print_string("You have triggered a bug in Factor. Please report.\n");
+ print_string("early_error: ");
print_obj(error);
- printf("\n");
+ nl();
factorbug();
}
}
/* Do some initialization that we do once only */
void do_stage1_init(void)
{
- fprintf(stderr,"*** Stage 2 early init... ");
- fflush(stderr);
-
- CELL words = find_all_words();
-
- REGISTER_ROOT(words);
-
- CELL i;
- CELL length = array_capacity(untag_object(words));
- for(i = 0; i < length; i++)
- {
- F_WORD *word = untag_word(array_nth(untag_array(words),i));
- REGISTER_UNTAGGED(word);
- default_word_code(word,false);
- UNREGISTER_UNTAGGED(word);
- update_word_xt(word);
- }
-
- UNREGISTER_ROOT(words);
-
- iterate_code_heap(relocate_code_block);
+ print_string("*** Stage 2 early init... ");
+ fflush(stdout);
+ compile_all_words();
userenv[STAGE2_ENV] = T;
- fprintf(stderr,"done\n");
- fflush(stderr);
+ print_string("done\n");
+ fflush(stdout);
}
/* Get things started */
if(p->image == NULL)
p->image = default_image_path();
- srand(current_millis());
+ srand(current_micros());
init_ffi();
init_stacks(p->ds_size,p->rs_size);
load_image(p);
callback();
}
-void factor_sleep(long ms)
+void factor_sleep(long us)
{
void (*callback)() = alien_offset(userenv[SLEEP_CALLBACK_ENV]);
- callback(ms);
+ callback(us);
}
void ffi_test_0(void)
{
- printf("ffi_test_0()\n");
}
int ffi_test_1(void)
{
- printf("ffi_test_1()\n");
return 3;
}
int ffi_test_2(int x, int y)
{
- printf("ffi_test_2(%d,%d)\n",x,y);
return x + y;
}
int ffi_test_3(int x, int y, int z, int t)
{
- printf("ffi_test_3(%d,%d,%d,%d)\n",x,y,z,t);
return x + y + z * t;
}
float ffi_test_4(void)
{
- printf("ffi_test_4()\n");
return 1.5;
}
double ffi_test_5(void)
{
- printf("ffi_test_5()\n");
return 1.5;
}
double ffi_test_6(float x, float y)
{
- printf("ffi_test_6(%f,%f)\n",x,y);
return x * y;
}
double ffi_test_7(double x, double y)
{
- printf("ffi_test_7(%f,%f)\n",x,y);
return x * y;
}
double ffi_test_8(double x, float y, double z, float t, int w)
{
- printf("ffi_test_8(%f,%f,%f,%f,%d)\n",x,y,z,t,w);
return x * y + z * t + w;
}
int ffi_test_9(int a, int b, int c, int d, int e, int f, int g)
{
- printf("ffi_test_9(%d,%d,%d,%d,%d,%d,%d)\n",a,b,c,d,e,f,g);
return a + b + c + d + e + f + g;
}
int ffi_test_10(int a, int b, double c, int d, float e, int f, int g, int h)
{
- printf("ffi_test_10(%d,%d,%f,%d,%f,%d,%d,%d)\n",a,b,c,d,e,f,g,h);
return a - b - c - d - e - f - g - h;
}
int ffi_test_11(int a, struct foo b, int c)
{
- printf("ffi_test_11(%d,{%d,%d},%d)\n",a,b.x,b.y,c);
return a * b.x + c * b.y;
}
int ffi_test_12(int a, int b, struct rect c, int d, int e, int f)
{
- printf("ffi_test_12(%d,%d,{%f,%f,%f,%f},%d,%d,%d)\n",a,b,c.x,c.y,c.w,c.h,d,e,f);
return a + b + c.x + c.y + c.w + c.h + d + e + f;
}
int ffi_test_13(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k)
{
- printf("ffi_test_13(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)\n",a,b,c,d,e,f,g,h,i,j,k);
return a + b + c + d + e + f + g + h + i + j + k;
}
struct foo ffi_test_14(int x, int y)
{
struct foo r;
- printf("ffi_test_14(%d,%d)\n",x,y);
r.x = x; r.y = y;
return r;
}
F_STDCALL int ffi_test_18(int x, int y, int z, int t)
{
- printf("ffi_test_18(%d,%d,%d,%d)\n",x,y,z,t);
return x + y + z * t;
}
double y1, double y2, double y3,
double z1, double z2, double z3)
{
- printf("ffi_test_20(%f,%f,%f,%f,%f,%f,%f,%f,%f)\n",
- x1, x2, x3, y1, y2, y3, z1, z2, z3);
}
long long ffi_test_21(long x, long y)
long ffi_test_22(long x, long long y, long long z)
{
- printf("ffi_test_22(%ld,%lld,%lld)\n",x,y,z);
return x + y / z;
}
return s;
}
-void ffi_test_31(int x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10, int x11, int x12, int x13, int x14, int x15, int x16, int x17, int x18, int x19, int x20, int x21, int x22, int x23, int x24, int x25, int x26, int x27, int x28, int x29, int x30, int x31, int x32, int x33, int x34, int x35, int x36, int x37, int x38, int x39, int x40, int x41) { }
+int ffi_test_31(int x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10, int x11, int x12, int x13, int x14, int x15, int x16, int x17, int x18, int x19, int x20, int x21, int x22, int x23, int x24, int x25, int x26, int x27, int x28, int x29, int x30, int x31, int x32, int x33, int x34, int x35, int x36, int x37, int x38, int x39, int x40, int x41)
+{
+ return x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23 + x24 + x25 + x26 + x27 + x28 + x29 + x30 + x31 + x32 + x33 + x34 + x35 + x36 + x37 + x38 + x39 + x40 + x41;
+}
+
+float ffi_test_31_point_5(float x0, float x1, float x2, float x3, float x4, float x5, float x6, float x7, float x8, float x9, float x10, float x11, float x12, float x13, float x14, float x15, float x16, float x17, float x18, float x19, float x20, float x21, float x22, float x23, float x24, float x25, float x26, float x27, float x28, float x29, float x30, float x31, float x32, float x33, float x34, float x35, float x36, float x37, float x38, float x39, float x40, float x41)
+{
+ return x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23 + x24 + x25 + x26 + x27 + x28 + x29 + x30 + x31 + x32 + x33 + x34 + x35 + x36 + x37 + x38 + x39 + x40 + x41;
+}
double ffi_test_32(struct test_struct_8 x, int y)
{
void ffi_test_36_point_5(void)
{
- printf("ffi_test_36_point_5\n");
global_var = 0;
}
int ffi_test_37(int (*f)(int, int, int))
{
- printf("ffi_test_37\n");
- printf("global_var is %d\n",global_var);
global_var = f(global_var,global_var * 2,global_var * 3);
- printf("global_var is %d\n",global_var);
- fflush(stdout);
return global_var;
}
int ffi_test_39(long a, long b, struct test_struct_13 s)
{
- printf("ffi_test_39(%ld,%ld,%f,%f,%f,%f,%f,%f)\n",a,b,s.x1,s.x2,s.x3,s.x4,s.x5,s.x6);
if(a != b) abort();
return s.x1 + s.x2 + s.x3 + s.x4 + s.x5 + s.x6;
}
struct test_struct_14 retval;
retval.x1 = x1;
retval.x2 = x2;
- printf("ffi_test_40(%f,%f)\n",x1,x2);
return retval;
}
struct test_struct_12 retval;
retval.a = a;
retval.x = x;
- printf("ffi_test_41(%d,%f)\n",a,x);
return retval;
}
struct test_struct_15 retval;
retval.x = x;
retval.y = y;
- printf("ffi_test_42(%f,%f)\n",x,y);
return retval;
}
struct test_struct_16 retval;
retval.x = x;
retval.a = a;
- printf("ffi_test_43(%f,%d)\n",x,a);
return retval;
}
struct test_struct_14 retval;
retval.x1 = 1.0;
retval.x2 = 2.0;
- //printf("ffi_test_44()\n");
return retval;
}
DLLEXPORT struct test_struct_6 ffi_test_29(void);
struct test_struct_7 { char x, y, z, a, b, c, d; };
DLLEXPORT struct test_struct_7 ffi_test_30(void);
-DLLEXPORT void ffi_test_31(int x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10, int x11, int x12, int x13, int x14, int x15, int x16, int x17, int x18, int x19, int x20, int x21, int x22, int x23, int x24, int x25, int x26, int x27, int x28, int x29, int x30, int x31, int x32, int x33, int x34, int x35, int x36, int x37, int x38, int x39, int x40, int x41);
+DLLEXPORT int ffi_test_31(int x0, int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10, int x11, int x12, int x13, int x14, int x15, int x16, int x17, int x18, int x19, int x20, int x21, int x22, int x23, int x24, int x25, int x26, int x27, int x28, int x29, int x30, int x31, int x32, int x33, int x34, int x35, int x36, int x37, int x38, int x39, int x40, int x41);
+DLLEXPORT float ffi_test_31_point_5(float x0, float x1, float x2, float x3, float x4, float x5, float x6, float x7, float x8, float x9, float x10, float x11, float x12, float x13, float x14, float x15, float x16, float x17, float x18, float x19, float x20, float x21, float x22, float x23, float x24, float x25, float x26, float x27, float x28, float x29, float x30, float x31, float x32, float x33, float x34, float x35, float x36, float x37, float x38, float x39, float x40, float x41);
struct test_struct_8 { double x; double y; };
DLLEXPORT double ffi_test_32(struct test_struct_8 x, int y);
struct test_struct_9 { float x; float y; };
F_ZONE *tenured = &data_heap->generations[TENURED];
- long int bytes_read = fread((void*)tenured->start,1,h->data_size,file);
+ F_FIXNUM bytes_read = fread((void*)tenured->start,1,h->data_size,file);
if(bytes_read != h->data_size)
{
- fprintf(stderr,"truncated image: %ld bytes read, %ld bytes expected\n",
- bytes_read,h->data_size);
+ print_string("truncated image: ");
+ print_fixnum(bytes_read);
+ print_string(" bytes read, ");
+ print_cell(h->data_size);
+ print_string(" bytes expected\n");
fatal_error("load_data_heap failed",0);
}
if(h->code_size != 0)
{
- long int bytes_read = fread(first_block(&code_heap),1,h->code_size,file);
+ F_FIXNUM bytes_read = fread(first_block(&code_heap),1,h->code_size,file);
if(bytes_read != h->code_size)
{
- fprintf(stderr,"truncated image: %ld bytes read, %ld bytes expected\n",
- bytes_read,h->code_size);
+ print_string("truncated image: ");
+ print_fixnum(bytes_read);
+ print_string(" bytes read, ");
+ print_cell(h->code_size);
+ print_string(" bytes expected\n");
fatal_error("load_code_heap failed",0);
}
}
FILE *file = OPEN_READ(p->image);
if(file == NULL)
{
- FPRINTF(stderr,"Cannot open image file: %s\n",p->image);
- fprintf(stderr,"%s\n",strerror(errno));
+ print_string("Cannot open image file: "); print_native_string(p->image); nl();
+ print_string(strerror(errno)); nl();
exit(1);
}
FILE* file;
F_HEADER h;
- FPRINTF(stderr,"*** Saving %s...\n",filename);
-
file = OPEN_WRITE(filename);
if(file == NULL)
{
- fprintf(stderr,"Cannot open image file: %s\n",strerror(errno));
+ print_string("Cannot open image file: "); print_native_string(filename); nl();
+ print_string(strerror(errno)); nl();
return false;
}
if(fwrite((void*)tenured->start,h.data_size,1,file) != 1)
{
- fprintf(stderr,"Save data heap failed: %s\n",strerror(errno));
+ print_string("Save data heap failed: "); print_string(strerror(errno)); nl();
return false;
}
if(fwrite(first_block(&code_heap),h.code_size,1,file) != 1)
{
- fprintf(stderr,"Save code heap failed: %s\n",strerror(errno));
+ print_string("Save code heap failed: "); print_string(strerror(errno)); nl();
return false;
}
if(fclose(file))
{
- fprintf(stderr,"Failed to close image file: %s\n",strerror(errno));
+ print_string("Failed to close image file: "); print_string(strerror(errno)); nl();
return false;
}
save_image(unbox_native_string());
}
-void strip_compiled_quotations(void)
-{
- begin_scan();
- CELL obj;
- while((obj = next_object()) != F)
- {
- if(type_of(obj) == QUOTATION_TYPE)
- {
- F_QUOTATION *quot = untag_object(obj);
- quot->compiledp = F;
- }
- }
- gc_off = false;
-}
-
void primitive_save_image_and_exit(void)
{
/* We unbox this before doing anything else. This is the only point
REGISTER_C_STRING(path);
- /* This reduces deployed image size */
- strip_compiled_quotations();
-
/* strip out userenv data which is set on startup anyway */
CELL i;
for(i = 0; i < FIRST_SAVE_ENV; i++)
/* The compiled code heap is structured into blocks. */
typedef struct
{
- CELL type; /* this is WORD_TYPE or QUOTATION_TYPE */
+ char type; /* this is WORD_TYPE or QUOTATION_TYPE */
+ char last_scan; /* the youngest generation in which this block's literals may live */
CELL code_length; /* # bytes */
CELL literals_length; /* # bytes */
CELL relocation; /* tagged pointer to byte-array or f */
int nArgs;
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
- if( NULL == szArglist )
+ if(NULL == szArglist)
{
- wprintf(L"CommandLineToArgvW failed\n");
+ puts("CommandLineToArgvW failed");
return 1;
}
#include "master.h"
/* Fixnums */
-
F_FIXNUM to_fixnum(CELL tagged)
{
switch(TAG(tagged))
drepl(tag_fixnum(float_to_fixnum(dpeek())));
}
-#define POP_FIXNUMS(x,y) \
- F_FIXNUM y = untag_fixnum_fast(dpop()); \
- F_FIXNUM x = untag_fixnum_fast(dpop());
-
-void primitive_fixnum_add(void)
+/* The fixnum+, fixnum- and fixnum* primitives are defined in cpu_*.S. On
+overflow, they call these functions. */
+F_FASTCALL void overflow_fixnum_add(F_FIXNUM x, F_FIXNUM y)
{
- POP_FIXNUMS(x,y)
- box_signed_cell(x + y);
+ drepl(tag_bignum(fixnum_to_bignum(
+ untag_fixnum_fast(x) + untag_fixnum_fast(y))));
}
-void primitive_fixnum_subtract(void)
+F_FASTCALL void overflow_fixnum_subtract(F_FIXNUM x, F_FIXNUM y)
{
- POP_FIXNUMS(x,y)
- box_signed_cell(x - y);
+ drepl(tag_bignum(fixnum_to_bignum(
+ untag_fixnum_fast(x) - untag_fixnum_fast(y))));
}
-/* Multiply two integers, and trap overflow.
-Thanks to David Blaikie (The_Vulture from freenode #java) for the hint. */
-void primitive_fixnum_multiply(void)
+F_FASTCALL void overflow_fixnum_multiply(F_FIXNUM x, F_FIXNUM y)
{
- POP_FIXNUMS(x,y)
-
- if(x == 0 || y == 0)
- dpush(tag_fixnum(0));
- else
- {
- F_FIXNUM prod = x * y;
- /* if this is not equal, we have overflow */
- if(prod / x == y)
- box_signed_cell(prod);
- else
- {
- F_ARRAY *bx = fixnum_to_bignum(x);
- REGISTER_BIGNUM(bx);
- F_ARRAY *by = fixnum_to_bignum(y);
- UNREGISTER_BIGNUM(bx);
- dpush(tag_bignum(bignum_multiply(bx,by)));
- }
- }
+ F_ARRAY *bx = fixnum_to_bignum(x);
+ REGISTER_BIGNUM(bx);
+ F_ARRAY *by = fixnum_to_bignum(y);
+ UNREGISTER_BIGNUM(bx);
+ drepl(tag_bignum(bignum_multiply(bx,by)));
}
+/* Division can only overflow when we are dividing the most negative fixnum
+by -1. */
void primitive_fixnum_divint(void)
{
- POP_FIXNUMS(x,y)
- box_signed_cell(x / y);
+ F_FIXNUM y = untag_fixnum_fast(dpop()); \
+ F_FIXNUM x = untag_fixnum_fast(dpeek());
+ F_FIXNUM result = x / y;
+ if(result == -FIXNUM_MIN)
+ drepl(allot_integer(-FIXNUM_MIN));
+ else
+ drepl(tag_fixnum(result));
}
void primitive_fixnum_divmod(void)
{
- POP_FIXNUMS(x,y)
- box_signed_cell(x / y);
- dpush(tag_fixnum(x % y));
+ F_FIXNUM y = get(ds);
+ F_FIXNUM x = get(ds - CELLS);
+ if(y == tag_fixnum(-1) && x == tag_fixnum(FIXNUM_MIN))
+ {
+ put(ds - CELLS,allot_integer(-FIXNUM_MIN));
+ put(ds,tag_fixnum(0));
+ }
+ else
+ {
+ put(ds - CELLS,tag_fixnum(x / y));
+ put(ds,x % y);
+ }
}
/*
- * Note the hairy overflow check.
* If we're shifting right by n bits, we won't overflow as long as none of the
* high WORD_SIZE-TAG_BITS-n bits are set.
*/
+#define SIGN_MASK(x) ((x) >> (WORD_SIZE - 1))
+#define BRANCHLESS_MAX(x,y) ((x) - (((x) - (y)) & SIGN_MASK((x) - (y))))
+#define BRANCHLESS_ABS(x) ((x ^ SIGN_MASK(x)) - SIGN_MASK(x))
+
void primitive_fixnum_shift(void)
{
- POP_FIXNUMS(x,y)
+ F_FIXNUM y = untag_fixnum_fast(dpop()); \
+ F_FIXNUM x = untag_fixnum_fast(dpeek());
- if(x == 0 || y == 0)
- {
- dpush(tag_fixnum(x));
+ if(x == 0)
return;
- }
else if(y < 0)
{
- if(y <= -WORD_SIZE)
- dpush(x < 0 ? tag_fixnum(-1) : tag_fixnum(0));
- else
- dpush(tag_fixnum(x >> -y));
+ y = BRANCHLESS_MAX(y,-WORD_SIZE + 1);
+ drepl(tag_fixnum(x >> -y));
return;
}
else if(y < WORD_SIZE - TAG_BITS)
{
- F_FIXNUM mask = -(1L << (WORD_SIZE - 1 - TAG_BITS - y));
- if((x > 0 && (x & mask) == 0) || (x & mask) == mask)
+ F_FIXNUM mask = -((F_FIXNUM)1 << (WORD_SIZE - 1 - TAG_BITS - y));
+ if(!(BRANCHLESS_ABS(x) & mask))
{
- dpush(tag_fixnum(x << y));
+ drepl(tag_fixnum(x << y));
return;
}
}
- dpush(tag_bignum(bignum_arithmetic_shift(
+ drepl(tag_bignum(bignum_arithmetic_shift(
fixnum_to_bignum(x),y)));
}
void primitive_bignum_shift(void)
{
- F_FIXNUM y = to_fixnum(dpop());
+ F_FIXNUM y = untag_fixnum_fast(dpop());
F_ARRAY* x = untag_object(dpop());
dpush(tag_bignum(bignum_arithmetic_shift(x,y)));
}
void primitive_fixnum_add(void);
void primitive_fixnum_subtract(void);
void primitive_fixnum_multiply(void);
+
+DLLEXPORT F_FASTCALL void overflow_fixnum_add(F_FIXNUM x, F_FIXNUM y);
+DLLEXPORT F_FASTCALL void overflow_fixnum_subtract(F_FIXNUM x, F_FIXNUM y);
+DLLEXPORT F_FASTCALL void overflow_fixnum_multiply(F_FIXNUM x, F_FIXNUM y);
+
void primitive_fixnum_divint(void);
void primitive_fixnum_divmod(void);
void primitive_fixnum_shift(void);
void early_init(void)
{
+ SInt32 version;
+ Gestalt(gestaltSystemVersion,&version);
+ if(version <= 0x1050)
+ {
+ printf("Factor requires Mac OS X 10.5 or later.\n");
+ exit(1);
+ }
+
[[NSAutoreleasePool alloc] init];
}
#define UAP_PROGRAM_COUNTER(uap) _UC_MACHINE_PC((ucontext_t *)uap)
-#define UNKNOWN_TYPE_P(file) ((file)->d_type == DT_UNKNOWN)
#define DIRECTORY_P(file) ((file)->d_type == DT_DIR)
static void *null_dll;
-s64 current_millis(void)
+s64 current_micros(void)
{
struct timeval t;
gettimeofday(&t,NULL);
- return (s64)t.tv_sec * 1000 + t.tv_usec / 1000;
+ return (s64)t.tv_sec * 1000000 + t.tv_usec;
}
-void sleep_millis(CELL msec)
+void sleep_micros(CELL usec)
{
- usleep(msec * 1000);
+ usleep(usec);
}
void init_ffi(void)
#define STRNCMP strncmp
#define STRDUP strdup
+#define FIXNUM_FORMAT "%ld"
+#define CELL_FORMAT "%lu"
+#define CELL_HEX_FORMAT "%lx"
+
+#ifdef FACTOR_64
+ #define CELL_HEX_PAD_FORMAT "%016lx"
+#else
+ #define CELL_HEX_PAD_FORMAT "%08lx"
+#endif
+
+#define FIXNUM_FORMAT "%ld"
+
#define OPEN_READ(path) fopen(path,"rb")
#define OPEN_WRITE(path) fopen(path,"wb")
-#define FPRINTF(stream,format,arg) fprintf(stream,format,arg)
+
+#define print_native_string(string) print_string(string)
void start_thread(void *(*start_routine)(void *));
void signal_handler(int signal, siginfo_t* siginfo, void* uap);
void dump_stack_signal(int signal, siginfo_t* siginfo, void* uap);
-s64 current_millis(void);
-void sleep_millis(CELL msec);
+s64 current_micros(void);
+void sleep_micros(CELL usec);
void open_console(void);
#include "master.h"
-s64 current_millis(void)
+s64 current_micros(void)
{
SYSTEMTIME st;
FILETIME ft;
GetSystemTime(&st);
SystemTimeToFileTime(&st, &ft);
return (((s64)ft.dwLowDateTime
- | (s64)ft.dwHighDateTime<<32) - EPOCH_OFFSET) / 10000;
+ | (s64)ft.dwHighDateTime<<32) - EPOCH_OFFSET) / 10;
}
char *strerror(int err)
#define snprintf _snprintf
#define snwprintf _snwprintf
-s64 current_millis(void);
+s64 current_micros(void);
void c_to_factor_toplevel(CELL quot);
void open_console(void);
#include "master.h"
-s64 current_millis(void)
+s64 current_micros(void)
{
FILETIME t;
GetSystemTimeAsFileTime(&t);
return (((s64)t.dwLowDateTime | (s64)t.dwHighDateTime<<32)
- - EPOCH_OFFSET) / 10000;
+ - EPOCH_OFFSET) / 10;
}
long exception_handler(PEXCEPTION_POINTERS pe)
signal_number = ERROR_DIVIDE_BY_ZERO;
c->EIP = (CELL)divide_by_zero_signal_handler_impl;
}
- else
+ /* If the Widcomm bluetooth stack is installed, the BTTray.exe process
+ injects code into running programs. For some reason this results in
+ random SEH exceptions with this (undocumented) exception code being
+ raised. The workaround seems to be ignoring this altogether, since that
+ is what happens if SEH is not enabled. Don't really have any idea what
+ this exception means. */
+ else if(e->ExceptionCode != 0x40010006)
{
signal_number = 11;
c->EIP = (CELL)misc_signal_handler_impl;
BY_HANDLE_FILE_INFORMATION bhfi;
F_CHAR *path = unbox_u16_string();
- //wprintf(L"path = %s\n", path);
HANDLE h = CreateFileW(path,
GENERIC_READ,
FILE_SHARE_READ,
return g_pagesize;
}
-void sleep_millis(DWORD msec)
+void sleep_micros(DWORD usec)
{
- Sleep(msec);
+ Sleep(usec);
}
#define STRNCMP wcsncmp
#define STRDUP _wcsdup
+#define FIXNUM_FORMAT "%Id"
+#define CELL_FORMAT "%lu"
+#define CELL_HEX_FORMAT "%Ix"
+
+#ifdef WIN64
+ #define CELL_HEX_PAD_FORMAT "%016Ix"
+#else
+ #define CELL_HEX_PAD_FORMAT "%08lx"
+#endif
+
+#define FIXNUM_FORMAT "%Id"
+
#define OPEN_READ(path) _wfopen(path,L"rb")
#define OPEN_WRITE(path) _wfopen(path,L"wb")
-#define FPRINTF(stream,format,arg) fwprintf(stream,L##format,arg)
+#define print_native_string(string) wprintf(L"%s",string)
/* Difference between Jan 1 00:00:00 1601 and Jan 1 00:00:00 1970 */
#define EPOCH_OFFSET 0x019db1ded53e8000LL
void *ffi_dlsym(F_DLL *dll, F_SYMBOL *symbol);
void ffi_dlclose(F_DLL *dll);
-void sleep_millis(DWORD msec);
+void sleep_micros(DWORD msec);
INLINE void init_signals(void) {}
INLINE void early_init(void) {}
const F_CHAR *default_image_path(void);
long getpagesize (void);
-s64 current_millis(void);
+s64 current_micros(void);
primitive_exit,
primitive_data_room,
primitive_code_room,
- primitive_millis,
+ primitive_micros,
primitive_modify_code_heap,
primitive_dlopen,
primitive_dlsym,
primitive_dlclose,
primitive_byte_array,
+ primitive_uninitialized_byte_array,
primitive_displaced_alien,
primitive_alien_signed_cell,
primitive_set_alien_signed_cell,
primitive_alien_address,
primitive_set_slot,
primitive_string_nth,
- primitive_set_string_nth,
+ primitive_set_string_nth_fast,
+ primitive_set_string_nth_slow,
primitive_resize_array,
primitive_resize_string,
primitive_array,
primitive_dll_validp,
primitive_unimplemented,
primitive_gc_reset,
+ primitive_jit_compile,
+ primitive_load_locals,
};
machine code chunks; prolog, epilog, call word, jump to word, etc. These machine
code chunks are generated from Factor code in core/cpu/.../bootstrap.factor.
+Calls to words and constant quotations (referenced by conditionals and dips)
+are direct jumps to machine code blocks. Literals are also referenced directly
+without going through the literal table.
+
It actually does do a little bit of very simple optimization:
1) Tail call optimization.
'if' and 'dispatch' conditionals are generated inline, instead of as a call to
the 'if' word.
-4) When preceded by an array, calls to the 'declare' word are optimized out
+4) When preceded by a quotation, calls to 'dip', '2dip' and '3dip' are
+open-coded as retain stack manipulation surrounding a subroutine call.
+
+5) When preceded by an array, calls to the 'declare' word are optimized out
entirely. This word is only used by the optimizing compiler, and with the
non-optimizing compiler it would otherwise just decrease performance to have to
push the array and immediately drop it after.
-5) Sub-primitives are primitive words which are implemented in assembly and not
+6) Sub-primitives are primitive words which are implemented in assembly and not
in the VM. They are open-coded and no subroutine call is generated. This
includes stack shufflers, some fixnum arithmetic words, and words such as tag,
slot and eq?. A primitive call is relatively expensive (two subroutine calls)
&& array_nth(array,i + 1) == userenv[JIT_DISPATCH_WORD];
}
+bool jit_fast_dip_p(F_ARRAY *array, CELL i)
+{
+ return (i + 2) <= array_capacity(array)
+ && type_of(array_nth(array,i)) == QUOTATION_TYPE
+ && array_nth(array,i + 1) == userenv[JIT_DIP_WORD];
+}
+
+bool jit_fast_2dip_p(F_ARRAY *array, CELL i)
+{
+ return (i + 2) <= array_capacity(array)
+ && type_of(array_nth(array,i)) == QUOTATION_TYPE
+ && array_nth(array,i + 1) == userenv[JIT_2DIP_WORD];
+}
+
+bool jit_fast_3dip_p(F_ARRAY *array, CELL i)
+{
+ return (i + 2) <= array_capacity(array)
+ && type_of(array_nth(array,i)) == QUOTATION_TYPE
+ && array_nth(array,i + 1) == userenv[JIT_3DIP_WORD];
+}
+
bool jit_ignore_declare_p(F_ARRAY *array, CELL i)
{
return (i + 1) < array_capacity(array)
if(word->subprimitive == F && obj != userenv[JIT_DECLARE_WORD])
return true;
}
+ else if(type_of(obj) == QUOTATION_TYPE)
+ {
+ if(jit_fast_dip_p(array,i)
+ || jit_fast_2dip_p(array,i)
+ || jit_fast_3dip_p(array,i))
+ return true;
+ }
}
return false;
case WRAPPER_TYPE:
wrapper = untag_object(obj);
GROWABLE_ARRAY_ADD(literals,wrapper->object);
- EMIT(userenv[JIT_PUSH_LITERAL],literals_count - 1);
+ EMIT(userenv[JIT_PUSH_IMMEDIATE],literals_count - 1);
break;
case FIXNUM_TYPE:
if(jit_primitive_call_p(untag_object(array),i))
if(stack_frame)
EMIT(userenv[JIT_EPILOG],0);
+ jit_compile(array_nth(untag_object(array),i),relocate);
+ jit_compile(array_nth(untag_object(array),i + 1),relocate);
+
GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
+ EMIT(userenv[JIT_IF_1],literals_count - 1);
GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i + 1));
- EMIT(userenv[JIT_IF_JUMP],literals_count - 2);
+ EMIT(userenv[JIT_IF_2],literals_count - 1);
i += 2;
tail_call = true;
break;
}
+ else if(jit_fast_dip_p(untag_object(array),i))
+ {
+ jit_compile(obj,relocate);
+
+ GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
+ EMIT(userenv[JIT_DIP],literals_count - 1);
+
+ i++;
+ break;
+ }
+ else if(jit_fast_2dip_p(untag_object(array),i))
+ {
+ jit_compile(obj,relocate);
+
+ GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
+ EMIT(userenv[JIT_2DIP],literals_count - 1);
+
+ i++;
+ break;
+ }
+ else if(jit_fast_3dip_p(untag_object(array),i))
+ {
+ jit_compile(obj,relocate);
+
+ GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
+ EMIT(userenv[JIT_3DIP],literals_count - 1);
+
+ i++;
+ break;
+ }
case ARRAY_TYPE:
if(jit_fast_dispatch_p(untag_object(array),i))
{
}
default:
GROWABLE_ARRAY_ADD(literals,obj);
- EMIT(userenv[immediate_p(obj) ? JIT_PUSH_IMMEDIATE : JIT_PUSH_LITERAL],literals_count - 1);
+ EMIT(userenv[JIT_PUSH_IMMEDIATE],literals_count - 1);
break;
}
}
struct.) */
#define COUNT(name,scan) \
{ \
+ CELL size = array_capacity(code_to_emit(name)) * code_format; \
if(offset == 0) return scan - 1; \
- offset -= array_capacity(code_to_emit(name)) * code_format; \
+ if(offset < size) return scan + 1; \
+ offset -= size; \
}
F_FIXNUM quot_code_offset_to_scan(CELL quot, F_FIXNUM offset)
COUNT(userenv[JIT_WORD_CALL],i)
break;
case WRAPPER_TYPE:
- COUNT(userenv[JIT_PUSH_LITERAL],i)
+ COUNT(userenv[JIT_PUSH_IMMEDIATE],i)
break;
case FIXNUM_TYPE:
if(jit_primitive_call_p(untag_object(array),i))
if(stack_frame)
COUNT(userenv[JIT_EPILOG],i)
+ COUNT(userenv[JIT_IF_1],i)
+ COUNT(userenv[JIT_IF_2],i)
i += 2;
- COUNT(userenv[JIT_IF_JUMP],i)
-
tail_call = true;
break;
}
+ else if(jit_fast_dip_p(untag_object(array),i))
+ {
+ COUNT(userenv[JIT_DIP],i)
+ i++;
+ break;
+ }
+ else if(jit_fast_2dip_p(untag_object(array),i))
+ {
+ COUNT(userenv[JIT_2DIP],i)
+ i++;
+ break;
+ }
+ else if(jit_fast_3dip_p(untag_object(array),i))
+ {
+ COUNT(userenv[JIT_3DIP],i)
+ i++;
+ break;
+ }
case ARRAY_TYPE:
if(jit_fast_dispatch_p(untag_object(array),i))
{
break;
}
default:
- COUNT(userenv[immediate_p(obj) ? JIT_PUSH_IMMEDIATE : JIT_PUSH_LITERAL],i)
+ COUNT(userenv[JIT_PUSH_IMMEDIATE],i)
break;
}
}
return -1;
}
-F_FASTCALL CELL primitive_jit_compile(CELL quot, F_STACK_FRAME *stack)
+F_FASTCALL CELL lazy_jit_compile_impl(CELL quot, F_STACK_FRAME *stack)
{
stack_chain->callstack_top = stack;
REGISTER_ROOT(quot);
return quot;
}
+void primitive_jit_compile(void)
+{
+ jit_compile(dpop(),true);
+}
+
/* push a new quotation on the stack */
void primitive_array_to_quotation(void)
{
F_QUOTATION *quot = untag_quotation(dpeek());
drepl(allot_cell((CELL)quot->xt));
}
+
+void compile_all_words(void)
+{
+ CELL words = find_all_words();
+
+ REGISTER_ROOT(words);
+
+ CELL i;
+ CELL length = array_capacity(untag_object(words));
+ for(i = 0; i < length; i++)
+ {
+ F_WORD *word = untag_word(array_nth(untag_array(words),i));
+ REGISTER_UNTAGGED(word);
+ if(word->compiledp == F)
+ default_word_code(word,false);
+ UNREGISTER_UNTAGGED(word);
+ update_word_xt(word);
+ }
+
+ UNREGISTER_ROOT(words);
+
+ iterate_code_heap(relocate_code_block);
+}
void set_quot_xt(F_QUOTATION *quot, F_COMPILED *code);
void jit_compile(CELL quot, bool relocate);
-F_FASTCALL CELL primitive_jit_compile(CELL quot, F_STACK_FRAME *stack);
+F_FASTCALL CELL lazy_jit_compile_impl(CELL quot, F_STACK_FRAME *stack);
F_FIXNUM quot_code_offset_to_scan(CELL quot, F_FIXNUM offset);
void primitive_array_to_quotation(void);
void primitive_quotation_xt(void);
+void primitive_jit_compile(void);
+void compile_all_words(void);
}
}
+F_CONTEXT *alloc_context(void)
+{
+ F_CONTEXT *context;
+
+ if(unused_contexts)
+ {
+ context = unused_contexts;
+ unused_contexts = unused_contexts->next;
+ }
+ else
+ {
+ context = safe_malloc(sizeof(F_CONTEXT));
+ context->datastack_region = alloc_segment(ds_size);
+ context->retainstack_region = alloc_segment(rs_size);
+ }
+
+ return context;
+}
+
+void dealloc_context(F_CONTEXT *context)
+{
+ context->next = unused_contexts;
+ unused_contexts = context;
+}
+
/* called on entry into a compiled callback */
void nest_stacks(void)
{
- F_CONTEXT *new_stacks = safe_malloc(sizeof(F_CONTEXT));
+ F_CONTEXT *new_stacks = alloc_context();
new_stacks->callstack_bottom = (F_STACK_FRAME *)-1;
new_stacks->callstack_top = (F_STACK_FRAME *)-1;
new_stacks->current_callback_save = userenv[CURRENT_CALLBACK_ENV];
new_stacks->catchstack_save = userenv[CATCHSTACK_ENV];
- new_stacks->datastack_region = alloc_segment(ds_size);
- new_stacks->retainstack_region = alloc_segment(rs_size);
-
new_stacks->next = stack_chain;
stack_chain = new_stacks;
/* called when leaving a compiled callback */
void unnest_stacks(void)
{
- dealloc_segment(stack_chain->datastack_region);
- dealloc_segment(stack_chain->retainstack_region);
-
ds = stack_chain->datastack_save;
rs = stack_chain->retainstack_save;
F_CONTEXT *old_stacks = stack_chain;
stack_chain = old_stacks->next;
- free(old_stacks);
+ dealloc_context(old_stacks);
}
/* called on startup */
ds_size = ds_size_;
rs_size = rs_size_;
stack_chain = NULL;
+ unused_contexts = NULL;
}
bool stack_to_array(CELL bottom, CELL top)
exit(to_fixnum(dpop()));
}
-void primitive_millis(void)
+void primitive_micros(void)
{
- box_unsigned_8(current_millis());
+ box_unsigned_8(current_micros());
}
void primitive_sleep(void)
{
- sleep_millis(to_cell(dpop()));
+ sleep_micros(to_cell(dpop()));
}
void primitive_set_slot(void)
CELL value = dpop();
set_slot(obj,slot,value);
}
+
+void primitive_load_locals(void)
+{
+ F_FIXNUM count = untag_fixnum_fast(dpop());
+ memcpy((CELL *)(rs + CELLS),(CELL *)(ds - CELLS * (count - 1)),CELLS * count);
+ ds -= CELLS * count;
+ rs += CELLS * count;
+}
JIT_PRIMITIVE,
JIT_WORD_JUMP,
JIT_WORD_CALL,
- JIT_PUSH_LITERAL,
JIT_IF_WORD,
- JIT_IF_JUMP,
+ JIT_IF_1,
+ JIT_IF_2,
JIT_DISPATCH_WORD,
JIT_DISPATCH,
JIT_EPILOG,
JIT_PUSH_IMMEDIATE,
JIT_DECLARE_WORD = 42,
JIT_SAVE_STACK,
+ JIT_DIP_WORD,
+ JIT_DIP,
+ JIT_2DIP_WORD,
+ JIT_2DIP,
+ JIT_3DIP_WORD,
+ JIT_3DIP,
STACK_TRACES_ENV = 59,
DLLEXPORT F_CONTEXT *stack_chain;
+F_CONTEXT *unused_contexts;
+
CELL ds_size, rs_size;
#define ds_bot (stack_chain->datastack_region->start)
void primitive_set_os_env(void);
void primitive_unset_os_env(void);
void primitive_set_os_envs(void);
-void primitive_millis(void);
+void primitive_micros(void);
void primitive_sleep(void);
void primitive_set_slot(void);
+void primitive_load_locals(void);
bool stage2;
return tag_object(a);
}
-CELL allot_array_2(CELL v1, CELL v2)
-{
- REGISTER_ROOT(v1);
- REGISTER_ROOT(v2);
- F_ARRAY *a = allot_array_internal(ARRAY_TYPE,2);
- UNREGISTER_ROOT(v2);
- UNREGISTER_ROOT(v1);
- set_array_nth(a,0,v1);
- set_array_nth(a,1,v2);
- return tag_object(a);
-}
-
CELL allot_array_4(CELL v1, CELL v2, CELL v3, CELL v4)
{
REGISTER_ROOT(v1);
return tag_object(a);
}
-F_ARRAY *reallot_array(F_ARRAY* array, CELL capacity, CELL fill)
+F_ARRAY *reallot_array(F_ARRAY* array, CELL capacity)
{
- int i;
- F_ARRAY* new_array;
-
CELL to_copy = array_capacity(array);
if(capacity < to_copy)
to_copy = capacity;
REGISTER_UNTAGGED(array);
- REGISTER_ROOT(fill);
-
- new_array = allot_array_internal(untag_header(array->header),capacity);
-
- UNREGISTER_ROOT(fill);
+ F_ARRAY* new_array = allot_array_internal(untag_header(array->header),capacity);
UNREGISTER_UNTAGGED(array);
memcpy(new_array + 1,array + 1,to_copy * CELLS);
-
- for(i = to_copy; i < capacity; i++)
- put(AREF(new_array,i),fill);
+ memset((char *)AREF(new_array,to_copy),'\0',(capacity - to_copy) * CELLS);
return new_array;
}
{
F_ARRAY* array = untag_array(dpop());
CELL capacity = unbox_array_size();
- dpush(tag_object(reallot_array(array,capacity,F)));
+ dpush(tag_object(reallot_array(array,capacity)));
}
F_ARRAY *growable_array_add(F_ARRAY *result, CELL elt, CELL *result_count)
if(*result_count == array_capacity(result))
{
- result = reallot_array(result,
- *result_count * 2,F);
+ result = reallot_array(result,*result_count * 2);
}
UNREGISTER_ROOT(elt);
CELL new_size = *result_count + elts_size;
if(new_size >= array_capacity(result))
- result = reallot_array(result,new_size * 2,F);
+ result = reallot_array(result,new_size * 2);
UNREGISTER_UNTAGGED(elts);
dpush(tag_object(allot_byte_array(size)));
}
+void primitive_uninitialized_byte_array(void)
+{
+ CELL size = unbox_array_size();
+ dpush(tag_object(allot_byte_array_internal(size)));
+}
+
F_BYTE_ARRAY *reallot_byte_array(F_BYTE_ARRAY *array, CELL capacity)
{
CELL to_copy = array_capacity(array);
to_copy = capacity;
REGISTER_UNTAGGED(array);
- F_BYTE_ARRAY *new_array = allot_byte_array(capacity);
+ F_BYTE_ARRAY *new_array = allot_byte_array_internal(capacity);
UNREGISTER_UNTAGGED(array);
memcpy(new_array + 1,array + 1,to_copy);
{
F_TUPLE_LAYOUT *layout = untag_object(dpop());
F_FIXNUM size = untag_fixnum_fast(layout->size);
-
- REGISTER_UNTAGGED(layout);
F_TUPLE *tuple = allot_tuple(layout);
- UNREGISTER_UNTAGGED(layout);
-
- F_FIXNUM i;
- for(i = size - 1; i >= 0; i--)
- put(AREF(tuple,i),dpop());
-
+ memcpy(tuple + 1,(CELL *)(ds - CELLS * (size - 1)),CELLS * size);
+ ds -= CELLS * size;
dpush(tag_tuple(tuple));
}
/* Strings */
CELL string_nth(F_STRING* string, CELL index)
{
+ /* If high bit is set, the most significant 16 bits of the char
+ come from the aux vector. The least significant bit of the
+ corresponding aux vector entry is negated, so that we can
+ XOR the two components together and get the original code point
+ back. */
CELL ch = bget(SREF(string,index));
- if(string->aux == F)
+ if((ch & 0x80) == 0)
return ch;
else
{
F_BYTE_ARRAY *aux = untag_object(string->aux);
- return (cget(BREF(aux,index * sizeof(u16))) << 8) | ch;
+ return (cget(BREF(aux,index * sizeof(u16))) << 7) ^ ch;
}
}
-/* allocates memory */
-void set_string_nth(F_STRING* string, CELL index, CELL value)
+void set_string_nth_fast(F_STRING* string, CELL index, CELL ch)
{
- bput(SREF(string,index),value & 0xff);
+ bput(SREF(string,index),ch);
+}
+void set_string_nth_slow(F_STRING* string, CELL index, CELL ch)
+{
F_BYTE_ARRAY *aux;
+ bput(SREF(string,index),(ch & 0x7f) | 0x80);
+
if(string->aux == F)
{
- if(value <= 0xff)
- return;
- else
- {
- REGISTER_UNTAGGED(string);
- aux = allot_byte_array(
- untag_fixnum_fast(string->length)
- * sizeof(u16));
- UNREGISTER_UNTAGGED(string);
+ REGISTER_UNTAGGED(string);
+ /* We don't need to pre-initialize the
+ byte array with any data, since we
+ only ever read from the aux vector
+ if the most significant bit of a
+ character is set. Initially all of
+ the bits are clear. */
+ aux = allot_byte_array_internal(
+ untag_fixnum_fast(string->length)
+ * sizeof(u16));
+ UNREGISTER_UNTAGGED(string);
- write_barrier((CELL)string);
- string->aux = tag_object(aux);
- }
+ write_barrier((CELL)string);
+ string->aux = tag_object(aux);
}
else
aux = untag_object(string->aux);
- cput(BREF(aux,index * sizeof(u16)),value >> 8);
+ cput(BREF(aux,index * sizeof(u16)),(ch >> 7) ^ 1);
+}
+
+/* allocates memory */
+void set_string_nth(F_STRING* string, CELL index, CELL ch)
+{
+ if(ch <= 0x7f)
+ set_string_nth_fast(string,index,ch);
+ else
+ set_string_nth_slow(string,index,ch);
}
/* untagged */
/* allocates memory */
void fill_string(F_STRING *string, CELL start, CELL capacity, CELL fill)
{
- if(fill == 0)
- {
- memset((void *)SREF(string,start),'\0',capacity - start);
-
- if(string->aux != F)
- {
- F_BYTE_ARRAY *aux = untag_object(string->aux);
- memset((void *)BREF(aux,start * sizeof(u16)),'\0',
- (capacity - start) * sizeof(u16));
- }
- }
+ if(fill <= 0x7f)
+ memset((void *)SREF(string,start),fill,capacity - start);
else
{
CELL i;
dpush(tag_object(allot_string(length,initial)));
}
-F_STRING* reallot_string(F_STRING* string, CELL capacity, CELL fill)
+F_STRING* reallot_string(F_STRING* string, CELL capacity)
{
CELL to_copy = string_capacity(string);
if(capacity < to_copy)
REGISTER_UNTAGGED(string);
REGISTER_UNTAGGED(new_string);
- fill_string(new_string,to_copy,capacity,fill);
+ fill_string(new_string,to_copy,capacity,'\0');
UNREGISTER_UNTAGGED(new_string);
UNREGISTER_UNTAGGED(string);
{
F_STRING* string = untag_string(dpop());
CELL capacity = unbox_array_size();
- dpush(tag_object(reallot_string(string,capacity,0)));
+ dpush(tag_object(reallot_string(string,capacity)));
}
/* Some ugly macros to prevent a 2x code duplication */
CELL value = untag_fixnum_fast(dpop());
set_string_nth(string,index,value);
}
+
+void primitive_set_string_nth_fast(void)
+{
+ F_STRING *string = untag_object(dpop());
+ CELL index = untag_fixnum_fast(dpop());
+ CELL value = untag_fixnum_fast(dpop());
+ set_string_nth_fast(string,index,value);
+}
+
+void primitive_set_string_nth_slow(void)
+{
+ F_STRING *string = untag_object(dpop());
+ CELL index = untag_fixnum_fast(dpop());
+ CELL value = untag_fixnum_fast(dpop());
+ set_string_nth_slow(string,index,value);
+}
F_BYTE_ARRAY *allot_byte_array(CELL size);
CELL allot_array_1(CELL obj);
-CELL allot_array_2(CELL v1, CELL v2);
CELL allot_array_4(CELL v1, CELL v2, CELL v3, CELL v4);
void primitive_array(void);
void primitive_tuple_boa(void);
void primitive_tuple_layout(void);
void primitive_byte_array(void);
+void primitive_uninitialized_byte_array(void);
void primitive_clone(void);
-F_ARRAY *reallot_array(F_ARRAY* array, CELL capacity, CELL fill);
+F_ARRAY *reallot_array(F_ARRAY* array, CELL capacity);
F_BYTE_ARRAY *reallot_byte_array(F_BYTE_ARRAY *array, CELL capacity);
void primitive_resize_array(void);
void primitive_resize_byte_array(void);
F_STRING* allot_string_internal(CELL capacity);
F_STRING* allot_string(CELL capacity, CELL fill);
+void primitive_uninitialized_string(void);
void primitive_string(void);
-F_STRING *reallot_string(F_STRING *string, CELL capacity, CELL fill);
+F_STRING *reallot_string(F_STRING *string, CELL capacity);
void primitive_resize_string(void);
F_STRING *memory_to_char_string(const char *string, CELL length);
void set_string_nth(F_STRING* string, CELL index, CELL value);
void primitive_string_nth(void);
-void primitive_set_string_nth(void);
+void primitive_set_string_nth_slow(void);
+void primitive_set_string_nth_fast(void);
F_WORD *allot_word(CELL vocab, CELL name);
void primitive_word(void);
result = tag_object(growable_array_append(untag_object(result),elts,&result##_count))
#define GROWABLE_ARRAY_TRIM(result) \
- result = tag_object(reallot_array(untag_object(result),result##_count,F))
+ result = tag_object(reallot_array(untag_object(result),result##_count))
/* Macros to simulate a byte vector in C */
#define GROWABLE_BYTE_ARRAY(result) \
if(!ptr) fatal_error("Out of memory in safe_strdup", 0);
return ptr;
}
+
+/* We don't use printf directly, because format directives are not portable.
+Instead we define the common cases here. */
+void nl(void)
+{
+ fputs("\n",stdout);
+}
+
+void print_string(const char *str)
+{
+ fputs(str,stdout);
+}
+
+void print_cell(CELL x)
+{
+ printf(CELL_FORMAT,x);
+}
+
+void print_cell_hex(CELL x)
+{
+ printf(CELL_HEX_FORMAT,x);
+}
+
+void print_cell_hex_pad(CELL x)
+{
+ printf(CELL_HEX_PAD_FORMAT,x);
+}
+
+void print_fixnum(F_FIXNUM x)
+{
+ printf(FIXNUM_FORMAT,x);
+}
+
+CELL read_cell_hex(void)
+{
+ CELL cell;
+ scanf(CELL_HEX_FORMAT,&cell);
+ return cell;
+};
void *safe_malloc(size_t size);
F_CHAR *safe_strdup(const F_CHAR *str);
+
+void nl(void);
+void print_string(const char *str);
+void print_cell(CELL x);
+void print_cell_hex(CELL x);
+void print_cell_hex_pad(CELL x);
+void print_fixnum(F_FIXNUM x);
+CELL read_cell_hex(void);